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>
1823f0703cSBryan Whitehead #include "lan743x_main.h"
190cf63226SBryan Whitehead #include "lan743x_ethtool.h"
2023f0703cSBryan Whitehead
21a2ab95a3SRaju Lakkaraju #define MMD_ACCESS_ADDRESS 0
22a2ab95a3SRaju Lakkaraju #define MMD_ACCESS_WRITE 1
23a2ab95a3SRaju Lakkaraju #define MMD_ACCESS_READ 2
24a2ab95a3SRaju Lakkaraju #define MMD_ACCESS_READ_INC 3
2546b777adSRaju Lakkaraju #define PCS_POWER_STATE_DOWN 0x6
2646b777adSRaju Lakkaraju #define PCS_POWER_STATE_UP 0x4
27a2ab95a3SRaju Lakkaraju
2874a78a00SRaju Lakkaraju #define RFE_RD_FIFO_TH_3_DWORDS 0x3
2974a78a00SRaju Lakkaraju
pci11x1x_strap_get_status(struct lan743x_adapter * adapter)30a46d9d37SRaju Lakkaraju static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
31a46d9d37SRaju Lakkaraju {
32a46d9d37SRaju Lakkaraju u32 chip_rev;
3346b777adSRaju Lakkaraju u32 cfg_load;
3446b777adSRaju Lakkaraju u32 hw_cfg;
35a46d9d37SRaju Lakkaraju u32 strap;
3646b777adSRaju Lakkaraju int ret;
37a46d9d37SRaju Lakkaraju
3846b777adSRaju Lakkaraju /* Timeout = 100 (i.e. 1 sec (10 msce * 100)) */
3946b777adSRaju Lakkaraju ret = lan743x_hs_syslock_acquire(adapter, 100);
4046b777adSRaju Lakkaraju if (ret < 0) {
4146b777adSRaju Lakkaraju netif_err(adapter, drv, adapter->netdev,
4246b777adSRaju Lakkaraju "Sys Lock acquire failed ret:%d\n", ret);
4346b777adSRaju Lakkaraju return;
4446b777adSRaju Lakkaraju }
4546b777adSRaju Lakkaraju
4646b777adSRaju Lakkaraju cfg_load = lan743x_csr_read(adapter, ETH_SYS_CONFIG_LOAD_STARTED_REG);
4746b777adSRaju Lakkaraju lan743x_hs_syslock_release(adapter);
4846b777adSRaju Lakkaraju hw_cfg = lan743x_csr_read(adapter, HW_CFG);
4946b777adSRaju Lakkaraju
5046b777adSRaju Lakkaraju if (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ ||
5146b777adSRaju Lakkaraju hw_cfg & HW_CFG_RST_PROTECT_) {
52a46d9d37SRaju Lakkaraju strap = lan743x_csr_read(adapter, STRAP_READ);
53a46d9d37SRaju Lakkaraju if (strap & STRAP_READ_SGMII_EN_)
54a46d9d37SRaju Lakkaraju adapter->is_sgmii_en = true;
55a46d9d37SRaju Lakkaraju else
56a46d9d37SRaju Lakkaraju adapter->is_sgmii_en = false;
57a46d9d37SRaju Lakkaraju } else {
58a46d9d37SRaju Lakkaraju chip_rev = lan743x_csr_read(adapter, FPGA_REV);
59a46d9d37SRaju Lakkaraju if (chip_rev) {
60a46d9d37SRaju Lakkaraju if (chip_rev & FPGA_SGMII_OP)
61a46d9d37SRaju Lakkaraju adapter->is_sgmii_en = true;
62a46d9d37SRaju Lakkaraju else
63a46d9d37SRaju Lakkaraju adapter->is_sgmii_en = false;
64a46d9d37SRaju Lakkaraju } else {
65a46d9d37SRaju Lakkaraju adapter->is_sgmii_en = false;
66a46d9d37SRaju Lakkaraju }
67a46d9d37SRaju Lakkaraju }
6846b777adSRaju Lakkaraju netif_dbg(adapter, drv, adapter->netdev,
6946b777adSRaju Lakkaraju "SGMII I/F %sable\n", adapter->is_sgmii_en ? "En" : "Dis");
70a46d9d37SRaju Lakkaraju }
71a46d9d37SRaju Lakkaraju
is_pci11x1x_chip(struct lan743x_adapter * adapter)72cf9aaea8SRaju Lakkaraju static bool is_pci11x1x_chip(struct lan743x_adapter *adapter)
73cf9aaea8SRaju Lakkaraju {
74cf9aaea8SRaju Lakkaraju struct lan743x_csr *csr = &adapter->csr;
75cf9aaea8SRaju Lakkaraju u32 id_rev = csr->id_rev;
76cf9aaea8SRaju Lakkaraju
77cf9aaea8SRaju Lakkaraju if (((id_rev & 0xFFFF0000) == ID_REV_ID_A011_) ||
78cf9aaea8SRaju Lakkaraju ((id_rev & 0xFFFF0000) == ID_REV_ID_A041_)) {
79cf9aaea8SRaju Lakkaraju return true;
80cf9aaea8SRaju Lakkaraju }
81cf9aaea8SRaju Lakkaraju return false;
82cf9aaea8SRaju Lakkaraju }
83cf9aaea8SRaju Lakkaraju
lan743x_pci_cleanup(struct lan743x_adapter * adapter)8423f0703cSBryan Whitehead static void lan743x_pci_cleanup(struct lan743x_adapter *adapter)
8523f0703cSBryan Whitehead {
8623f0703cSBryan Whitehead pci_release_selected_regions(adapter->pdev,
8723f0703cSBryan Whitehead pci_select_bars(adapter->pdev,
8823f0703cSBryan Whitehead IORESOURCE_MEM));
8923f0703cSBryan Whitehead pci_disable_device(adapter->pdev);
9023f0703cSBryan Whitehead }
9123f0703cSBryan Whitehead
lan743x_pci_init(struct lan743x_adapter * adapter,struct pci_dev * pdev)9223f0703cSBryan Whitehead static int lan743x_pci_init(struct lan743x_adapter *adapter,
9323f0703cSBryan Whitehead struct pci_dev *pdev)
9423f0703cSBryan Whitehead {
9523f0703cSBryan Whitehead unsigned long bars = 0;
9623f0703cSBryan Whitehead int ret;
9723f0703cSBryan Whitehead
9823f0703cSBryan Whitehead adapter->pdev = pdev;
9923f0703cSBryan Whitehead ret = pci_enable_device_mem(pdev);
10023f0703cSBryan Whitehead if (ret)
10123f0703cSBryan Whitehead goto return_error;
10223f0703cSBryan Whitehead
10323f0703cSBryan Whitehead netif_info(adapter, probe, adapter->netdev,
10423f0703cSBryan Whitehead "PCI: Vendor ID = 0x%04X, Device ID = 0x%04X\n",
10523f0703cSBryan Whitehead pdev->vendor, pdev->device);
10623f0703cSBryan Whitehead bars = pci_select_bars(pdev, IORESOURCE_MEM);
10723f0703cSBryan Whitehead if (!test_bit(0, &bars))
10823f0703cSBryan Whitehead goto disable_device;
10923f0703cSBryan Whitehead
11023f0703cSBryan Whitehead ret = pci_request_selected_regions(pdev, bars, DRIVER_NAME);
11123f0703cSBryan Whitehead if (ret)
11223f0703cSBryan Whitehead goto disable_device;
11323f0703cSBryan Whitehead
11423f0703cSBryan Whitehead pci_set_master(pdev);
11523f0703cSBryan Whitehead return 0;
11623f0703cSBryan Whitehead
11723f0703cSBryan Whitehead disable_device:
11823f0703cSBryan Whitehead pci_disable_device(adapter->pdev);
11923f0703cSBryan Whitehead
12023f0703cSBryan Whitehead return_error:
12123f0703cSBryan Whitehead return ret;
12223f0703cSBryan Whitehead }
12323f0703cSBryan Whitehead
lan743x_csr_read(struct lan743x_adapter * adapter,int offset)1248114e8a2SBryan Whitehead u32 lan743x_csr_read(struct lan743x_adapter *adapter, int offset)
12523f0703cSBryan Whitehead {
12623f0703cSBryan Whitehead return ioread32(&adapter->csr.csr_address[offset]);
12723f0703cSBryan Whitehead }
12823f0703cSBryan Whitehead
lan743x_csr_write(struct lan743x_adapter * adapter,int offset,u32 data)1298114e8a2SBryan Whitehead void lan743x_csr_write(struct lan743x_adapter *adapter, int offset,
130c16b1a9cSColin Ian King u32 data)
13123f0703cSBryan Whitehead {
13223f0703cSBryan Whitehead iowrite32(data, &adapter->csr.csr_address[offset]);
13323f0703cSBryan Whitehead }
13423f0703cSBryan Whitehead
13523f0703cSBryan Whitehead #define LAN743X_CSR_READ_OP(offset) lan743x_csr_read(adapter, offset)
13623f0703cSBryan Whitehead
lan743x_csr_light_reset(struct lan743x_adapter * adapter)13723f0703cSBryan Whitehead static int lan743x_csr_light_reset(struct lan743x_adapter *adapter)
13823f0703cSBryan Whitehead {
13923f0703cSBryan Whitehead u32 data;
14023f0703cSBryan Whitehead
14123f0703cSBryan Whitehead data = lan743x_csr_read(adapter, HW_CFG);
14223f0703cSBryan Whitehead data |= HW_CFG_LRST_;
14323f0703cSBryan Whitehead lan743x_csr_write(adapter, HW_CFG, data);
14423f0703cSBryan Whitehead
14523f0703cSBryan Whitehead return readx_poll_timeout(LAN743X_CSR_READ_OP, HW_CFG, data,
14623f0703cSBryan Whitehead !(data & HW_CFG_LRST_), 100000, 10000000);
14723f0703cSBryan Whitehead }
14823f0703cSBryan 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)1497a8227b2SMoritz Fischer static int lan743x_csr_wait_for_bit_atomic(struct lan743x_adapter *adapter,
1507a8227b2SMoritz Fischer int offset, u32 bit_mask,
1517a8227b2SMoritz Fischer int target_value, int udelay_min,
1527a8227b2SMoritz Fischer int udelay_max, int count)
1537a8227b2SMoritz Fischer {
1547a8227b2SMoritz Fischer u32 data;
1557a8227b2SMoritz Fischer
1567a8227b2SMoritz Fischer return readx_poll_timeout_atomic(LAN743X_CSR_READ_OP, offset, data,
1577a8227b2SMoritz Fischer target_value == !!(data & bit_mask),
1587a8227b2SMoritz Fischer udelay_max, udelay_min * count);
1597a8227b2SMoritz Fischer }
1607a8227b2SMoritz 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)16123f0703cSBryan Whitehead static int lan743x_csr_wait_for_bit(struct lan743x_adapter *adapter,
16223f0703cSBryan Whitehead int offset, u32 bit_mask,
16323f0703cSBryan Whitehead int target_value, int usleep_min,
16423f0703cSBryan Whitehead int usleep_max, int count)
16523f0703cSBryan Whitehead {
16623f0703cSBryan Whitehead u32 data;
16723f0703cSBryan Whitehead
16823f0703cSBryan Whitehead return readx_poll_timeout(LAN743X_CSR_READ_OP, offset, data,
16930ac666aSMoritz Fischer target_value == !!(data & bit_mask),
17023f0703cSBryan Whitehead usleep_max, usleep_min * count);
17123f0703cSBryan Whitehead }
17223f0703cSBryan Whitehead
lan743x_csr_init(struct lan743x_adapter * adapter)17323f0703cSBryan Whitehead static int lan743x_csr_init(struct lan743x_adapter *adapter)
17423f0703cSBryan Whitehead {
17523f0703cSBryan Whitehead struct lan743x_csr *csr = &adapter->csr;
17623f0703cSBryan Whitehead resource_size_t bar_start, bar_length;
17723f0703cSBryan Whitehead
17823f0703cSBryan Whitehead bar_start = pci_resource_start(adapter->pdev, 0);
17923f0703cSBryan Whitehead bar_length = pci_resource_len(adapter->pdev, 0);
18023f0703cSBryan Whitehead csr->csr_address = devm_ioremap(&adapter->pdev->dev,
18123f0703cSBryan Whitehead bar_start, bar_length);
1820f0f5868SMoritz Fischer if (!csr->csr_address)
1830f0f5868SMoritz Fischer return -ENOMEM;
18423f0703cSBryan Whitehead
18523f0703cSBryan Whitehead csr->id_rev = lan743x_csr_read(adapter, ID_REV);
18623f0703cSBryan Whitehead csr->fpga_rev = lan743x_csr_read(adapter, FPGA_REV);
18723f0703cSBryan Whitehead netif_info(adapter, probe, adapter->netdev,
18823f0703cSBryan Whitehead "ID_REV = 0x%08X, FPGA_REV = %d.%d\n",
18923f0703cSBryan Whitehead csr->id_rev, FPGA_REV_GET_MAJOR_(csr->fpga_rev),
19023f0703cSBryan Whitehead FPGA_REV_GET_MINOR_(csr->fpga_rev));
1910f0f5868SMoritz Fischer if (!ID_REV_IS_VALID_CHIP_ID_(csr->id_rev))
1920f0f5868SMoritz Fischer return -ENODEV;
19323f0703cSBryan Whitehead
19423f0703cSBryan Whitehead csr->flags = LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR;
19523f0703cSBryan Whitehead switch (csr->id_rev & ID_REV_CHIP_REV_MASK_) {
19623f0703cSBryan Whitehead case ID_REV_CHIP_REV_A0_:
19723f0703cSBryan Whitehead csr->flags |= LAN743X_CSR_FLAG_IS_A0;
19823f0703cSBryan Whitehead csr->flags &= ~LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR;
19923f0703cSBryan Whitehead break;
20023f0703cSBryan Whitehead case ID_REV_CHIP_REV_B0_:
20123f0703cSBryan Whitehead csr->flags |= LAN743X_CSR_FLAG_IS_B0;
20223f0703cSBryan Whitehead break;
20323f0703cSBryan Whitehead }
20423f0703cSBryan Whitehead
2050f0f5868SMoritz Fischer return lan743x_csr_light_reset(adapter);
20623f0703cSBryan Whitehead }
20723f0703cSBryan Whitehead
lan743x_intr_software_isr(struct lan743x_adapter * adapter)208c31799baSSven Van Asbroeck static void lan743x_intr_software_isr(struct lan743x_adapter *adapter)
20923f0703cSBryan Whitehead {
21023f0703cSBryan Whitehead struct lan743x_intr *intr = &adapter->intr;
21123f0703cSBryan Whitehead
212796a2665SSven Van Asbroeck /* disable the interrupt to prevent repeated re-triggering */
213796a2665SSven Van Asbroeck lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_SW_GP_);
214470dfd80SSven Van Asbroeck intr->software_isr_flag = true;
215470dfd80SSven Van Asbroeck wake_up(&intr->software_isr_wq);
21623f0703cSBryan Whitehead }
21723f0703cSBryan Whitehead
lan743x_tx_isr(void * context,u32 int_sts,u32 flags)21823f0703cSBryan Whitehead static void lan743x_tx_isr(void *context, u32 int_sts, u32 flags)
21923f0703cSBryan Whitehead {
22023f0703cSBryan Whitehead struct lan743x_tx *tx = context;
22123f0703cSBryan Whitehead struct lan743x_adapter *adapter = tx->adapter;
22223f0703cSBryan Whitehead bool enable_flag = true;
22323f0703cSBryan Whitehead
2247c8c0291SJesse Brandeburg lan743x_csr_read(adapter, INT_EN_SET);
22523f0703cSBryan Whitehead if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR) {
22623f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR,
22723f0703cSBryan Whitehead INT_BIT_DMA_TX_(tx->channel_number));
22823f0703cSBryan Whitehead }
22923f0703cSBryan Whitehead
23023f0703cSBryan Whitehead if (int_sts & INT_BIT_DMA_TX_(tx->channel_number)) {
23123f0703cSBryan Whitehead u32 ioc_bit = DMAC_INT_BIT_TX_IOC_(tx->channel_number);
23223f0703cSBryan Whitehead u32 dmac_int_sts;
23323f0703cSBryan Whitehead u32 dmac_int_en;
23423f0703cSBryan Whitehead
23523f0703cSBryan Whitehead if (flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ)
23623f0703cSBryan Whitehead dmac_int_sts = lan743x_csr_read(adapter, DMAC_INT_STS);
23723f0703cSBryan Whitehead else
23823f0703cSBryan Whitehead dmac_int_sts = ioc_bit;
23923f0703cSBryan Whitehead if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK)
24023f0703cSBryan Whitehead dmac_int_en = lan743x_csr_read(adapter,
24123f0703cSBryan Whitehead DMAC_INT_EN_SET);
24223f0703cSBryan Whitehead else
24323f0703cSBryan Whitehead dmac_int_en = ioc_bit;
24423f0703cSBryan Whitehead
24523f0703cSBryan Whitehead dmac_int_en &= ioc_bit;
24623f0703cSBryan Whitehead dmac_int_sts &= dmac_int_en;
24723f0703cSBryan Whitehead if (dmac_int_sts & ioc_bit) {
24823f0703cSBryan Whitehead napi_schedule(&tx->napi);
24923f0703cSBryan Whitehead enable_flag = false;/* poll func will enable later */
25023f0703cSBryan Whitehead }
25123f0703cSBryan Whitehead }
25223f0703cSBryan Whitehead
25323f0703cSBryan Whitehead if (enable_flag)
25423f0703cSBryan Whitehead /* enable isr */
25523f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET,
25623f0703cSBryan Whitehead INT_BIT_DMA_TX_(tx->channel_number));
25723f0703cSBryan Whitehead }
25823f0703cSBryan Whitehead
lan743x_rx_isr(void * context,u32 int_sts,u32 flags)25923f0703cSBryan Whitehead static void lan743x_rx_isr(void *context, u32 int_sts, u32 flags)
26023f0703cSBryan Whitehead {
26123f0703cSBryan Whitehead struct lan743x_rx *rx = context;
26223f0703cSBryan Whitehead struct lan743x_adapter *adapter = rx->adapter;
26323f0703cSBryan Whitehead bool enable_flag = true;
26423f0703cSBryan Whitehead
26523f0703cSBryan Whitehead if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR) {
26623f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR,
26723f0703cSBryan Whitehead INT_BIT_DMA_RX_(rx->channel_number));
26823f0703cSBryan Whitehead }
26923f0703cSBryan Whitehead
27023f0703cSBryan Whitehead if (int_sts & INT_BIT_DMA_RX_(rx->channel_number)) {
27123f0703cSBryan Whitehead u32 rx_frame_bit = DMAC_INT_BIT_RXFRM_(rx->channel_number);
27223f0703cSBryan Whitehead u32 dmac_int_sts;
27323f0703cSBryan Whitehead u32 dmac_int_en;
27423f0703cSBryan Whitehead
27523f0703cSBryan Whitehead if (flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ)
27623f0703cSBryan Whitehead dmac_int_sts = lan743x_csr_read(adapter, DMAC_INT_STS);
27723f0703cSBryan Whitehead else
27823f0703cSBryan Whitehead dmac_int_sts = rx_frame_bit;
27923f0703cSBryan Whitehead if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK)
28023f0703cSBryan Whitehead dmac_int_en = lan743x_csr_read(adapter,
28123f0703cSBryan Whitehead DMAC_INT_EN_SET);
28223f0703cSBryan Whitehead else
28323f0703cSBryan Whitehead dmac_int_en = rx_frame_bit;
28423f0703cSBryan Whitehead
28523f0703cSBryan Whitehead dmac_int_en &= rx_frame_bit;
28623f0703cSBryan Whitehead dmac_int_sts &= dmac_int_en;
28723f0703cSBryan Whitehead if (dmac_int_sts & rx_frame_bit) {
28823f0703cSBryan Whitehead napi_schedule(&rx->napi);
28923f0703cSBryan Whitehead enable_flag = false;/* poll funct will enable later */
29023f0703cSBryan Whitehead }
29123f0703cSBryan Whitehead }
29223f0703cSBryan Whitehead
29323f0703cSBryan Whitehead if (enable_flag) {
29423f0703cSBryan Whitehead /* enable isr */
29523f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET,
29623f0703cSBryan Whitehead INT_BIT_DMA_RX_(rx->channel_number));
29723f0703cSBryan Whitehead }
29823f0703cSBryan Whitehead }
29923f0703cSBryan Whitehead
lan743x_intr_shared_isr(void * context,u32 int_sts,u32 flags)30023f0703cSBryan Whitehead static void lan743x_intr_shared_isr(void *context, u32 int_sts, u32 flags)
30123f0703cSBryan Whitehead {
30223f0703cSBryan Whitehead struct lan743x_adapter *adapter = context;
30323f0703cSBryan Whitehead unsigned int channel;
30423f0703cSBryan Whitehead
30523f0703cSBryan Whitehead if (int_sts & INT_BIT_ALL_RX_) {
30623f0703cSBryan Whitehead for (channel = 0; channel < LAN743X_USED_RX_CHANNELS;
30723f0703cSBryan Whitehead channel++) {
30823f0703cSBryan Whitehead u32 int_bit = INT_BIT_DMA_RX_(channel);
30923f0703cSBryan Whitehead
31023f0703cSBryan Whitehead if (int_sts & int_bit) {
31123f0703cSBryan Whitehead lan743x_rx_isr(&adapter->rx[channel],
31223f0703cSBryan Whitehead int_bit, flags);
31323f0703cSBryan Whitehead int_sts &= ~int_bit;
31423f0703cSBryan Whitehead }
31523f0703cSBryan Whitehead }
31623f0703cSBryan Whitehead }
31723f0703cSBryan Whitehead if (int_sts & INT_BIT_ALL_TX_) {
318cf9aaea8SRaju Lakkaraju for (channel = 0; channel < adapter->used_tx_channels;
31923f0703cSBryan Whitehead channel++) {
32023f0703cSBryan Whitehead u32 int_bit = INT_BIT_DMA_TX_(channel);
32123f0703cSBryan Whitehead
32223f0703cSBryan Whitehead if (int_sts & int_bit) {
32323f0703cSBryan Whitehead lan743x_tx_isr(&adapter->tx[channel],
32423f0703cSBryan Whitehead int_bit, flags);
32523f0703cSBryan Whitehead int_sts &= ~int_bit;
32623f0703cSBryan Whitehead }
32723f0703cSBryan Whitehead }
32823f0703cSBryan Whitehead }
32923f0703cSBryan Whitehead if (int_sts & INT_BIT_ALL_OTHER_) {
33023f0703cSBryan Whitehead if (int_sts & INT_BIT_SW_GP_) {
33123f0703cSBryan Whitehead lan743x_intr_software_isr(adapter);
33223f0703cSBryan Whitehead int_sts &= ~INT_BIT_SW_GP_;
33323f0703cSBryan Whitehead }
33407624df1SBryan Whitehead if (int_sts & INT_BIT_1588_) {
33507624df1SBryan Whitehead lan743x_ptp_isr(adapter);
33607624df1SBryan Whitehead int_sts &= ~INT_BIT_1588_;
33707624df1SBryan Whitehead }
33823f0703cSBryan Whitehead }
33923f0703cSBryan Whitehead if (int_sts)
34023f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR, int_sts);
34123f0703cSBryan Whitehead }
34223f0703cSBryan Whitehead
lan743x_intr_entry_isr(int irq,void * ptr)34323f0703cSBryan Whitehead static irqreturn_t lan743x_intr_entry_isr(int irq, void *ptr)
34423f0703cSBryan Whitehead {
34523f0703cSBryan Whitehead struct lan743x_vector *vector = ptr;
34623f0703cSBryan Whitehead struct lan743x_adapter *adapter = vector->adapter;
34723f0703cSBryan Whitehead irqreturn_t result = IRQ_NONE;
34823f0703cSBryan Whitehead u32 int_enables;
34923f0703cSBryan Whitehead u32 int_sts;
35023f0703cSBryan Whitehead
35123f0703cSBryan Whitehead if (vector->flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ) {
35223f0703cSBryan Whitehead int_sts = lan743x_csr_read(adapter, INT_STS);
35323f0703cSBryan Whitehead } else if (vector->flags &
35423f0703cSBryan Whitehead (LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C |
35523f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C)) {
35623f0703cSBryan Whitehead int_sts = lan743x_csr_read(adapter, INT_STS_R2C);
35723f0703cSBryan Whitehead } else {
35823f0703cSBryan Whitehead /* use mask as implied status */
35923f0703cSBryan Whitehead int_sts = vector->int_mask | INT_BIT_MAS_;
36023f0703cSBryan Whitehead }
36123f0703cSBryan Whitehead
36223f0703cSBryan Whitehead if (!(int_sts & INT_BIT_MAS_))
36323f0703cSBryan Whitehead goto irq_done;
36423f0703cSBryan Whitehead
36523f0703cSBryan Whitehead if (vector->flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR)
36623f0703cSBryan Whitehead /* disable vector interrupt */
36723f0703cSBryan Whitehead lan743x_csr_write(adapter,
36823f0703cSBryan Whitehead INT_VEC_EN_CLR,
36923f0703cSBryan Whitehead INT_VEC_EN_(vector->vector_index));
37023f0703cSBryan Whitehead
37123f0703cSBryan Whitehead if (vector->flags & LAN743X_VECTOR_FLAG_MASTER_ENABLE_CLEAR)
37223f0703cSBryan Whitehead /* disable master interrupt */
37323f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_MAS_);
37423f0703cSBryan Whitehead
37523f0703cSBryan Whitehead if (vector->flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK) {
37623f0703cSBryan Whitehead int_enables = lan743x_csr_read(adapter, INT_EN_SET);
37723f0703cSBryan Whitehead } else {
37823f0703cSBryan Whitehead /* use vector mask as implied enable mask */
37923f0703cSBryan Whitehead int_enables = vector->int_mask;
38023f0703cSBryan Whitehead }
38123f0703cSBryan Whitehead
38223f0703cSBryan Whitehead int_sts &= int_enables;
38323f0703cSBryan Whitehead int_sts &= vector->int_mask;
38423f0703cSBryan Whitehead if (int_sts) {
38523f0703cSBryan Whitehead if (vector->handler) {
38623f0703cSBryan Whitehead vector->handler(vector->context,
38723f0703cSBryan Whitehead int_sts, vector->flags);
38823f0703cSBryan Whitehead } else {
38923f0703cSBryan Whitehead /* disable interrupts on this vector */
39023f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR,
39123f0703cSBryan Whitehead vector->int_mask);
39223f0703cSBryan Whitehead }
39323f0703cSBryan Whitehead result = IRQ_HANDLED;
39423f0703cSBryan Whitehead }
39523f0703cSBryan Whitehead
39623f0703cSBryan Whitehead if (vector->flags & LAN743X_VECTOR_FLAG_MASTER_ENABLE_SET)
39723f0703cSBryan Whitehead /* enable master interrupt */
39823f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAS_);
39923f0703cSBryan Whitehead
40023f0703cSBryan Whitehead if (vector->flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET)
40123f0703cSBryan Whitehead /* enable vector interrupt */
40223f0703cSBryan Whitehead lan743x_csr_write(adapter,
40323f0703cSBryan Whitehead INT_VEC_EN_SET,
40423f0703cSBryan Whitehead INT_VEC_EN_(vector->vector_index));
40523f0703cSBryan Whitehead irq_done:
40623f0703cSBryan Whitehead return result;
40723f0703cSBryan Whitehead }
40823f0703cSBryan Whitehead
lan743x_intr_test_isr(struct lan743x_adapter * adapter)40923f0703cSBryan Whitehead static int lan743x_intr_test_isr(struct lan743x_adapter *adapter)
41023f0703cSBryan Whitehead {
41123f0703cSBryan Whitehead struct lan743x_intr *intr = &adapter->intr;
412470dfd80SSven Van Asbroeck int ret;
41323f0703cSBryan Whitehead
414470dfd80SSven Van Asbroeck intr->software_isr_flag = false;
41523f0703cSBryan Whitehead
416470dfd80SSven Van Asbroeck /* enable and activate test interrupt */
41723f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_SW_GP_);
41823f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_SET, INT_BIT_SW_GP_);
41923f0703cSBryan Whitehead
420470dfd80SSven Van Asbroeck ret = wait_event_timeout(intr->software_isr_wq,
421470dfd80SSven Van Asbroeck intr->software_isr_flag,
422470dfd80SSven Van Asbroeck msecs_to_jiffies(200));
42323f0703cSBryan Whitehead
424470dfd80SSven Van Asbroeck /* disable test interrupt */
42523f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_SW_GP_);
426470dfd80SSven Van Asbroeck
427470dfd80SSven Van Asbroeck return ret > 0 ? 0 : -ENODEV;
42823f0703cSBryan Whitehead }
42923f0703cSBryan Whitehead
lan743x_intr_register_isr(struct lan743x_adapter * adapter,int vector_index,u32 flags,u32 int_mask,lan743x_vector_handler handler,void * context)43023f0703cSBryan Whitehead static int lan743x_intr_register_isr(struct lan743x_adapter *adapter,
43123f0703cSBryan Whitehead int vector_index, u32 flags,
43223f0703cSBryan Whitehead u32 int_mask,
43323f0703cSBryan Whitehead lan743x_vector_handler handler,
43423f0703cSBryan Whitehead void *context)
43523f0703cSBryan Whitehead {
43623f0703cSBryan Whitehead struct lan743x_vector *vector = &adapter->intr.vector_list
43723f0703cSBryan Whitehead [vector_index];
43823f0703cSBryan Whitehead int ret;
43923f0703cSBryan Whitehead
44023f0703cSBryan Whitehead vector->adapter = adapter;
44123f0703cSBryan Whitehead vector->flags = flags;
44223f0703cSBryan Whitehead vector->vector_index = vector_index;
44323f0703cSBryan Whitehead vector->int_mask = int_mask;
44423f0703cSBryan Whitehead vector->handler = handler;
44523f0703cSBryan Whitehead vector->context = context;
44623f0703cSBryan Whitehead
44723f0703cSBryan Whitehead ret = request_irq(vector->irq,
44823f0703cSBryan Whitehead lan743x_intr_entry_isr,
44923f0703cSBryan Whitehead (flags & LAN743X_VECTOR_FLAG_IRQ_SHARED) ?
45023f0703cSBryan Whitehead IRQF_SHARED : 0, DRIVER_NAME, vector);
45123f0703cSBryan Whitehead if (ret) {
45223f0703cSBryan Whitehead vector->handler = NULL;
45323f0703cSBryan Whitehead vector->context = NULL;
45423f0703cSBryan Whitehead vector->int_mask = 0;
45523f0703cSBryan Whitehead vector->flags = 0;
45623f0703cSBryan Whitehead }
45723f0703cSBryan Whitehead return ret;
45823f0703cSBryan Whitehead }
45923f0703cSBryan Whitehead
lan743x_intr_unregister_isr(struct lan743x_adapter * adapter,int vector_index)46023f0703cSBryan Whitehead static void lan743x_intr_unregister_isr(struct lan743x_adapter *adapter,
46123f0703cSBryan Whitehead int vector_index)
46223f0703cSBryan Whitehead {
46323f0703cSBryan Whitehead struct lan743x_vector *vector = &adapter->intr.vector_list
46423f0703cSBryan Whitehead [vector_index];
46523f0703cSBryan Whitehead
46623f0703cSBryan Whitehead free_irq(vector->irq, vector);
46723f0703cSBryan Whitehead vector->handler = NULL;
46823f0703cSBryan Whitehead vector->context = NULL;
46923f0703cSBryan Whitehead vector->int_mask = 0;
47023f0703cSBryan Whitehead vector->flags = 0;
47123f0703cSBryan Whitehead }
47223f0703cSBryan Whitehead
lan743x_intr_get_vector_flags(struct lan743x_adapter * adapter,u32 int_mask)47323f0703cSBryan Whitehead static u32 lan743x_intr_get_vector_flags(struct lan743x_adapter *adapter,
47423f0703cSBryan Whitehead u32 int_mask)
47523f0703cSBryan Whitehead {
47623f0703cSBryan Whitehead int index;
47723f0703cSBryan Whitehead
478ac16b6ebSRaju Lakkaraju for (index = 0; index < adapter->max_vector_count; index++) {
47923f0703cSBryan Whitehead if (adapter->intr.vector_list[index].int_mask & int_mask)
48023f0703cSBryan Whitehead return adapter->intr.vector_list[index].flags;
48123f0703cSBryan Whitehead }
48223f0703cSBryan Whitehead return 0;
48323f0703cSBryan Whitehead }
48423f0703cSBryan Whitehead
lan743x_intr_close(struct lan743x_adapter * adapter)48523f0703cSBryan Whitehead static void lan743x_intr_close(struct lan743x_adapter *adapter)
48623f0703cSBryan Whitehead {
48723f0703cSBryan Whitehead struct lan743x_intr *intr = &adapter->intr;
48823f0703cSBryan Whitehead int index = 0;
48923f0703cSBryan Whitehead
49023f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_MAS_);
491ac16b6ebSRaju Lakkaraju if (adapter->is_pci11x1x)
492ac16b6ebSRaju Lakkaraju lan743x_csr_write(adapter, INT_VEC_EN_CLR, 0x0000FFFF);
493ac16b6ebSRaju Lakkaraju else
49423f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_VEC_EN_CLR, 0x000000FF);
49523f0703cSBryan Whitehead
496ac16b6ebSRaju Lakkaraju for (index = 0; index < intr->number_of_vectors; index++) {
49723f0703cSBryan Whitehead if (intr->flags & INTR_FLAG_IRQ_REQUESTED(index)) {
49823f0703cSBryan Whitehead lan743x_intr_unregister_isr(adapter, index);
49923f0703cSBryan Whitehead intr->flags &= ~INTR_FLAG_IRQ_REQUESTED(index);
50023f0703cSBryan Whitehead }
50123f0703cSBryan Whitehead }
50223f0703cSBryan Whitehead
50323f0703cSBryan Whitehead if (intr->flags & INTR_FLAG_MSI_ENABLED) {
50423f0703cSBryan Whitehead pci_disable_msi(adapter->pdev);
50523f0703cSBryan Whitehead intr->flags &= ~INTR_FLAG_MSI_ENABLED;
50623f0703cSBryan Whitehead }
50723f0703cSBryan Whitehead
50823f0703cSBryan Whitehead if (intr->flags & INTR_FLAG_MSIX_ENABLED) {
50923f0703cSBryan Whitehead pci_disable_msix(adapter->pdev);
51023f0703cSBryan Whitehead intr->flags &= ~INTR_FLAG_MSIX_ENABLED;
51123f0703cSBryan Whitehead }
51223f0703cSBryan Whitehead }
51323f0703cSBryan Whitehead
lan743x_intr_open(struct lan743x_adapter * adapter)51423f0703cSBryan Whitehead static int lan743x_intr_open(struct lan743x_adapter *adapter)
51523f0703cSBryan Whitehead {
516ac16b6ebSRaju Lakkaraju struct msix_entry msix_entries[PCI11X1X_MAX_VECTOR_COUNT];
51723f0703cSBryan Whitehead struct lan743x_intr *intr = &adapter->intr;
518cf9aaea8SRaju Lakkaraju unsigned int used_tx_channels;
51923f0703cSBryan Whitehead u32 int_vec_en_auto_clr = 0;
520ac16b6ebSRaju Lakkaraju u8 max_vector_count;
52123f0703cSBryan Whitehead u32 int_vec_map0 = 0;
52223f0703cSBryan Whitehead u32 int_vec_map1 = 0;
52323f0703cSBryan Whitehead int ret = -ENODEV;
52423f0703cSBryan Whitehead int index = 0;
52523f0703cSBryan Whitehead u32 flags = 0;
52623f0703cSBryan Whitehead
52723f0703cSBryan Whitehead intr->number_of_vectors = 0;
52823f0703cSBryan Whitehead
52923f0703cSBryan Whitehead /* Try to set up MSIX interrupts */
530ac16b6ebSRaju Lakkaraju max_vector_count = adapter->max_vector_count;
53123f0703cSBryan Whitehead memset(&msix_entries[0], 0,
532ac16b6ebSRaju Lakkaraju sizeof(struct msix_entry) * max_vector_count);
533ac16b6ebSRaju Lakkaraju for (index = 0; index < max_vector_count; index++)
53423f0703cSBryan Whitehead msix_entries[index].entry = index;
535cf9aaea8SRaju Lakkaraju used_tx_channels = adapter->used_tx_channels;
53623f0703cSBryan Whitehead ret = pci_enable_msix_range(adapter->pdev,
53723f0703cSBryan Whitehead msix_entries, 1,
538cf9aaea8SRaju Lakkaraju 1 + used_tx_channels +
53923f0703cSBryan Whitehead LAN743X_USED_RX_CHANNELS);
54023f0703cSBryan Whitehead
54123f0703cSBryan Whitehead if (ret > 0) {
54223f0703cSBryan Whitehead intr->flags |= INTR_FLAG_MSIX_ENABLED;
54323f0703cSBryan Whitehead intr->number_of_vectors = ret;
54423f0703cSBryan Whitehead intr->using_vectors = true;
54523f0703cSBryan Whitehead for (index = 0; index < intr->number_of_vectors; index++)
54623f0703cSBryan Whitehead intr->vector_list[index].irq = msix_entries
54723f0703cSBryan Whitehead [index].vector;
54823f0703cSBryan Whitehead netif_info(adapter, ifup, adapter->netdev,
54923f0703cSBryan Whitehead "using MSIX interrupts, number of vectors = %d\n",
55023f0703cSBryan Whitehead intr->number_of_vectors);
55123f0703cSBryan Whitehead }
55223f0703cSBryan Whitehead
55323f0703cSBryan Whitehead /* If MSIX failed try to setup using MSI interrupts */
55423f0703cSBryan Whitehead if (!intr->number_of_vectors) {
55523f0703cSBryan Whitehead if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) {
55623f0703cSBryan Whitehead if (!pci_enable_msi(adapter->pdev)) {
55723f0703cSBryan Whitehead intr->flags |= INTR_FLAG_MSI_ENABLED;
55823f0703cSBryan Whitehead intr->number_of_vectors = 1;
55923f0703cSBryan Whitehead intr->using_vectors = true;
56023f0703cSBryan Whitehead intr->vector_list[0].irq =
56123f0703cSBryan Whitehead adapter->pdev->irq;
56223f0703cSBryan Whitehead netif_info(adapter, ifup, adapter->netdev,
56323f0703cSBryan Whitehead "using MSI interrupts, number of vectors = %d\n",
56423f0703cSBryan Whitehead intr->number_of_vectors);
56523f0703cSBryan Whitehead }
56623f0703cSBryan Whitehead }
56723f0703cSBryan Whitehead }
56823f0703cSBryan Whitehead
56923f0703cSBryan Whitehead /* If MSIX, and MSI failed, setup using legacy interrupt */
57023f0703cSBryan Whitehead if (!intr->number_of_vectors) {
57123f0703cSBryan Whitehead intr->number_of_vectors = 1;
57223f0703cSBryan Whitehead intr->using_vectors = false;
57323f0703cSBryan Whitehead intr->vector_list[0].irq = intr->irq;
57423f0703cSBryan Whitehead netif_info(adapter, ifup, adapter->netdev,
57523f0703cSBryan Whitehead "using legacy interrupts\n");
57623f0703cSBryan Whitehead }
57723f0703cSBryan Whitehead
57823f0703cSBryan Whitehead /* At this point we must have at least one irq */
57923f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_VEC_EN_CLR, 0xFFFFFFFF);
58023f0703cSBryan Whitehead
58123f0703cSBryan Whitehead /* map all interrupts to vector 0 */
58223f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_VEC_MAP0, 0x00000000);
58323f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_VEC_MAP1, 0x00000000);
58423f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_VEC_MAP2, 0x00000000);
58523f0703cSBryan Whitehead flags = LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ |
58623f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C |
58723f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK |
58823f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR;
58923f0703cSBryan Whitehead
59023f0703cSBryan Whitehead if (intr->using_vectors) {
59123f0703cSBryan Whitehead flags |= LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR |
59223f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET;
59323f0703cSBryan Whitehead } else {
59423f0703cSBryan Whitehead flags |= LAN743X_VECTOR_FLAG_MASTER_ENABLE_CLEAR |
59523f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_MASTER_ENABLE_SET |
59623f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_IRQ_SHARED;
59723f0703cSBryan Whitehead }
59823f0703cSBryan Whitehead
59923f0703cSBryan Whitehead if (adapter->csr.flags & LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR) {
60023f0703cSBryan Whitehead flags &= ~LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ;
60123f0703cSBryan Whitehead flags &= ~LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C;
60223f0703cSBryan Whitehead flags &= ~LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR;
60323f0703cSBryan Whitehead flags &= ~LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK;
60423f0703cSBryan Whitehead flags |= LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C;
60523f0703cSBryan Whitehead flags |= LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C;
60623f0703cSBryan Whitehead }
60723f0703cSBryan Whitehead
608470dfd80SSven Van Asbroeck init_waitqueue_head(&intr->software_isr_wq);
609470dfd80SSven Van Asbroeck
61023f0703cSBryan Whitehead ret = lan743x_intr_register_isr(adapter, 0, flags,
61123f0703cSBryan Whitehead INT_BIT_ALL_RX_ | INT_BIT_ALL_TX_ |
61223f0703cSBryan Whitehead INT_BIT_ALL_OTHER_,
61323f0703cSBryan Whitehead lan743x_intr_shared_isr, adapter);
61423f0703cSBryan Whitehead if (ret)
61523f0703cSBryan Whitehead goto clean_up;
61623f0703cSBryan Whitehead intr->flags |= INTR_FLAG_IRQ_REQUESTED(0);
61723f0703cSBryan Whitehead
61823f0703cSBryan Whitehead if (intr->using_vectors)
61923f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_VEC_EN_SET,
62023f0703cSBryan Whitehead INT_VEC_EN_(0));
62123f0703cSBryan Whitehead
62223f0703cSBryan Whitehead if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) {
62323f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_MOD_CFG0, LAN743X_INT_MOD);
62423f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_MOD_CFG1, LAN743X_INT_MOD);
62523f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_MOD_CFG2, LAN743X_INT_MOD);
62623f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_MOD_CFG3, LAN743X_INT_MOD);
62723f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_MOD_CFG4, LAN743X_INT_MOD);
62823f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_MOD_CFG5, LAN743X_INT_MOD);
62923f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_MOD_CFG6, LAN743X_INT_MOD);
63023f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_MOD_CFG7, LAN743X_INT_MOD);
631ac16b6ebSRaju Lakkaraju if (adapter->is_pci11x1x) {
632ac16b6ebSRaju Lakkaraju lan743x_csr_write(adapter, INT_MOD_CFG8, LAN743X_INT_MOD);
633ac16b6ebSRaju Lakkaraju lan743x_csr_write(adapter, INT_MOD_CFG9, LAN743X_INT_MOD);
634ac16b6ebSRaju Lakkaraju lan743x_csr_write(adapter, INT_MOD_MAP0, 0x00007654);
635ac16b6ebSRaju Lakkaraju lan743x_csr_write(adapter, INT_MOD_MAP1, 0x00003210);
636ac16b6ebSRaju Lakkaraju } else {
63723f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_MOD_MAP0, 0x00005432);
63823f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_MOD_MAP1, 0x00000001);
639ac16b6ebSRaju Lakkaraju }
64023f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_MOD_MAP2, 0x00FFFFFF);
64123f0703cSBryan Whitehead }
64223f0703cSBryan Whitehead
64323f0703cSBryan Whitehead /* enable interrupts */
64423f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAS_);
64523f0703cSBryan Whitehead ret = lan743x_intr_test_isr(adapter);
64623f0703cSBryan Whitehead if (ret)
64723f0703cSBryan Whitehead goto clean_up;
64823f0703cSBryan Whitehead
64923f0703cSBryan Whitehead if (intr->number_of_vectors > 1) {
65023f0703cSBryan Whitehead int number_of_tx_vectors = intr->number_of_vectors - 1;
65123f0703cSBryan Whitehead
652cf9aaea8SRaju Lakkaraju if (number_of_tx_vectors > used_tx_channels)
653cf9aaea8SRaju Lakkaraju number_of_tx_vectors = used_tx_channels;
65423f0703cSBryan Whitehead flags = LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ |
65523f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C |
65623f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK |
65723f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR |
65823f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR |
65923f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET;
66023f0703cSBryan Whitehead
66123f0703cSBryan Whitehead if (adapter->csr.flags &
66223f0703cSBryan Whitehead LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR) {
663deb6bfabSBryan Whitehead flags = LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET |
66423f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET |
66523f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR |
66623f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR;
66723f0703cSBryan Whitehead }
66823f0703cSBryan Whitehead
66923f0703cSBryan Whitehead for (index = 0; index < number_of_tx_vectors; index++) {
67023f0703cSBryan Whitehead u32 int_bit = INT_BIT_DMA_TX_(index);
67123f0703cSBryan Whitehead int vector = index + 1;
67223f0703cSBryan Whitehead
67323f0703cSBryan Whitehead /* map TX interrupt to vector */
67423f0703cSBryan Whitehead int_vec_map1 |= INT_VEC_MAP1_TX_VEC_(index, vector);
67523f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_VEC_MAP1, int_vec_map1);
67623f0703cSBryan Whitehead
67723f0703cSBryan Whitehead /* Remove TX interrupt from shared mask */
67823f0703cSBryan Whitehead intr->vector_list[0].int_mask &= ~int_bit;
67923f0703cSBryan Whitehead ret = lan743x_intr_register_isr(adapter, vector, flags,
68023f0703cSBryan Whitehead int_bit, lan743x_tx_isr,
68123f0703cSBryan Whitehead &adapter->tx[index]);
68223f0703cSBryan Whitehead if (ret)
68323f0703cSBryan Whitehead goto clean_up;
68423f0703cSBryan Whitehead intr->flags |= INTR_FLAG_IRQ_REQUESTED(vector);
68523f0703cSBryan Whitehead if (!(flags &
68623f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET))
68723f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_VEC_EN_SET,
68823f0703cSBryan Whitehead INT_VEC_EN_(vector));
68923f0703cSBryan Whitehead }
69023f0703cSBryan Whitehead }
691cf9aaea8SRaju Lakkaraju if ((intr->number_of_vectors - used_tx_channels) > 1) {
69223f0703cSBryan Whitehead int number_of_rx_vectors = intr->number_of_vectors -
693cf9aaea8SRaju Lakkaraju used_tx_channels - 1;
69423f0703cSBryan Whitehead
69523f0703cSBryan Whitehead if (number_of_rx_vectors > LAN743X_USED_RX_CHANNELS)
69623f0703cSBryan Whitehead number_of_rx_vectors = LAN743X_USED_RX_CHANNELS;
69723f0703cSBryan Whitehead
69823f0703cSBryan Whitehead flags = LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ |
69923f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C |
70023f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK |
70123f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR |
70223f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR |
70323f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET;
70423f0703cSBryan Whitehead
70523f0703cSBryan Whitehead if (adapter->csr.flags &
70623f0703cSBryan Whitehead LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR) {
70723f0703cSBryan Whitehead flags = LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_CLEAR |
70823f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET |
70923f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET |
71023f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR |
71123f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR;
71223f0703cSBryan Whitehead }
71323f0703cSBryan Whitehead for (index = 0; index < number_of_rx_vectors; index++) {
714ac16b6ebSRaju Lakkaraju int vector = index + 1 + used_tx_channels;
71523f0703cSBryan Whitehead u32 int_bit = INT_BIT_DMA_RX_(index);
71623f0703cSBryan Whitehead
71723f0703cSBryan Whitehead /* map RX interrupt to vector */
71823f0703cSBryan Whitehead int_vec_map0 |= INT_VEC_MAP0_RX_VEC_(index, vector);
71923f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_VEC_MAP0, int_vec_map0);
72023f0703cSBryan Whitehead if (flags &
72123f0703cSBryan Whitehead LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_CLEAR) {
72223f0703cSBryan Whitehead int_vec_en_auto_clr |= INT_VEC_EN_(vector);
72323f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_VEC_EN_AUTO_CLR,
72423f0703cSBryan Whitehead int_vec_en_auto_clr);
72523f0703cSBryan Whitehead }
72623f0703cSBryan Whitehead
72723f0703cSBryan Whitehead /* Remove RX interrupt from shared mask */
72823f0703cSBryan Whitehead intr->vector_list[0].int_mask &= ~int_bit;
72923f0703cSBryan Whitehead ret = lan743x_intr_register_isr(adapter, vector, flags,
73023f0703cSBryan Whitehead int_bit, lan743x_rx_isr,
73123f0703cSBryan Whitehead &adapter->rx[index]);
73223f0703cSBryan Whitehead if (ret)
73323f0703cSBryan Whitehead goto clean_up;
73423f0703cSBryan Whitehead intr->flags |= INTR_FLAG_IRQ_REQUESTED(vector);
73523f0703cSBryan Whitehead
73623f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_VEC_EN_SET,
73723f0703cSBryan Whitehead INT_VEC_EN_(vector));
73823f0703cSBryan Whitehead }
73923f0703cSBryan Whitehead }
74023f0703cSBryan Whitehead return 0;
74123f0703cSBryan Whitehead
74223f0703cSBryan Whitehead clean_up:
74323f0703cSBryan Whitehead lan743x_intr_close(adapter);
74423f0703cSBryan Whitehead return ret;
74523f0703cSBryan Whitehead }
74623f0703cSBryan Whitehead
lan743x_dp_write(struct lan743x_adapter * adapter,u32 select,u32 addr,u32 length,u32 * buf)74723f0703cSBryan Whitehead static int lan743x_dp_write(struct lan743x_adapter *adapter,
74823f0703cSBryan Whitehead u32 select, u32 addr, u32 length, u32 *buf)
74923f0703cSBryan Whitehead {
75023f0703cSBryan Whitehead u32 dp_sel;
75123f0703cSBryan Whitehead int i;
75223f0703cSBryan Whitehead
7537a8227b2SMoritz Fischer if (lan743x_csr_wait_for_bit_atomic(adapter, DP_SEL, DP_SEL_DPRDY_,
75423f0703cSBryan Whitehead 1, 40, 100, 100))
7552b52a4b6SSven Van Asbroeck return -EIO;
75623f0703cSBryan Whitehead dp_sel = lan743x_csr_read(adapter, DP_SEL);
75723f0703cSBryan Whitehead dp_sel &= ~DP_SEL_MASK_;
75823f0703cSBryan Whitehead dp_sel |= select;
75923f0703cSBryan Whitehead lan743x_csr_write(adapter, DP_SEL, dp_sel);
76023f0703cSBryan Whitehead
76123f0703cSBryan Whitehead for (i = 0; i < length; i++) {
76223f0703cSBryan Whitehead lan743x_csr_write(adapter, DP_ADDR, addr + i);
76323f0703cSBryan Whitehead lan743x_csr_write(adapter, DP_DATA_0, buf[i]);
76423f0703cSBryan Whitehead lan743x_csr_write(adapter, DP_CMD, DP_CMD_WRITE_);
7657a8227b2SMoritz Fischer if (lan743x_csr_wait_for_bit_atomic(adapter, DP_SEL,
7667a8227b2SMoritz Fischer DP_SEL_DPRDY_,
76723f0703cSBryan Whitehead 1, 40, 100, 100))
7682b52a4b6SSven Van Asbroeck return -EIO;
76923f0703cSBryan Whitehead }
77023f0703cSBryan Whitehead
7712b52a4b6SSven Van Asbroeck return 0;
77223f0703cSBryan Whitehead }
77323f0703cSBryan Whitehead
lan743x_mac_mii_access(u16 id,u16 index,int read)77423f0703cSBryan Whitehead static u32 lan743x_mac_mii_access(u16 id, u16 index, int read)
77523f0703cSBryan Whitehead {
77623f0703cSBryan Whitehead u32 ret;
77723f0703cSBryan Whitehead
77823f0703cSBryan Whitehead ret = (id << MAC_MII_ACC_PHY_ADDR_SHIFT_) &
77923f0703cSBryan Whitehead MAC_MII_ACC_PHY_ADDR_MASK_;
78023f0703cSBryan Whitehead ret |= (index << MAC_MII_ACC_MIIRINDA_SHIFT_) &
78123f0703cSBryan Whitehead MAC_MII_ACC_MIIRINDA_MASK_;
78223f0703cSBryan Whitehead
78323f0703cSBryan Whitehead if (read)
78423f0703cSBryan Whitehead ret |= MAC_MII_ACC_MII_READ_;
78523f0703cSBryan Whitehead else
78623f0703cSBryan Whitehead ret |= MAC_MII_ACC_MII_WRITE_;
78723f0703cSBryan Whitehead ret |= MAC_MII_ACC_MII_BUSY_;
78823f0703cSBryan Whitehead
78923f0703cSBryan Whitehead return ret;
79023f0703cSBryan Whitehead }
79123f0703cSBryan Whitehead
lan743x_mac_mii_wait_till_not_busy(struct lan743x_adapter * adapter)79223f0703cSBryan Whitehead static int lan743x_mac_mii_wait_till_not_busy(struct lan743x_adapter *adapter)
79323f0703cSBryan Whitehead {
79423f0703cSBryan Whitehead u32 data;
79523f0703cSBryan Whitehead
79623f0703cSBryan Whitehead return readx_poll_timeout(LAN743X_CSR_READ_OP, MAC_MII_ACC, data,
79723f0703cSBryan Whitehead !(data & MAC_MII_ACC_MII_BUSY_), 0, 1000000);
79823f0703cSBryan Whitehead }
79923f0703cSBryan Whitehead
lan743x_mdiobus_read_c22(struct mii_bus * bus,int phy_id,int index)8003d90c03cSAndrew Lunn static int lan743x_mdiobus_read_c22(struct mii_bus *bus, int phy_id, int index)
80123f0703cSBryan Whitehead {
80223f0703cSBryan Whitehead struct lan743x_adapter *adapter = bus->priv;
80323f0703cSBryan Whitehead u32 val, mii_access;
80423f0703cSBryan Whitehead int ret;
80523f0703cSBryan Whitehead
80623f0703cSBryan Whitehead /* comfirm MII not busy */
80723f0703cSBryan Whitehead ret = lan743x_mac_mii_wait_till_not_busy(adapter);
80823f0703cSBryan Whitehead if (ret < 0)
80923f0703cSBryan Whitehead return ret;
81023f0703cSBryan Whitehead
81123f0703cSBryan Whitehead /* set the address, index & direction (read from PHY) */
81223f0703cSBryan Whitehead mii_access = lan743x_mac_mii_access(phy_id, index, MAC_MII_READ);
81323f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_MII_ACC, mii_access);
81423f0703cSBryan Whitehead ret = lan743x_mac_mii_wait_till_not_busy(adapter);
81523f0703cSBryan Whitehead if (ret < 0)
81623f0703cSBryan Whitehead return ret;
81723f0703cSBryan Whitehead
81823f0703cSBryan Whitehead val = lan743x_csr_read(adapter, MAC_MII_DATA);
81923f0703cSBryan Whitehead return (int)(val & 0xFFFF);
82023f0703cSBryan Whitehead }
82123f0703cSBryan Whitehead
lan743x_mdiobus_write_c22(struct mii_bus * bus,int phy_id,int index,u16 regval)8223d90c03cSAndrew Lunn static int lan743x_mdiobus_write_c22(struct mii_bus *bus,
82323f0703cSBryan Whitehead int phy_id, int index, u16 regval)
82423f0703cSBryan Whitehead {
82523f0703cSBryan Whitehead struct lan743x_adapter *adapter = bus->priv;
82623f0703cSBryan Whitehead u32 val, mii_access;
82723f0703cSBryan Whitehead int ret;
82823f0703cSBryan Whitehead
82923f0703cSBryan Whitehead /* confirm MII not busy */
83023f0703cSBryan Whitehead ret = lan743x_mac_mii_wait_till_not_busy(adapter);
83123f0703cSBryan Whitehead if (ret < 0)
83223f0703cSBryan Whitehead return ret;
83323f0703cSBryan Whitehead val = (u32)regval;
83423f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_MII_DATA, val);
83523f0703cSBryan Whitehead
83623f0703cSBryan Whitehead /* set the address, index & direction (write to PHY) */
83723f0703cSBryan Whitehead mii_access = lan743x_mac_mii_access(phy_id, index, MAC_MII_WRITE);
83823f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_MII_ACC, mii_access);
83923f0703cSBryan Whitehead ret = lan743x_mac_mii_wait_till_not_busy(adapter);
84023f0703cSBryan Whitehead return ret;
84123f0703cSBryan Whitehead }
84223f0703cSBryan Whitehead
lan743x_mac_mmd_access(int id,int dev_addr,int op)8433d90c03cSAndrew Lunn static u32 lan743x_mac_mmd_access(int id, int dev_addr, int op)
844a2ab95a3SRaju Lakkaraju {
845a2ab95a3SRaju Lakkaraju u32 ret;
846a2ab95a3SRaju Lakkaraju
847a2ab95a3SRaju Lakkaraju ret = (id << MAC_MII_ACC_PHY_ADDR_SHIFT_) &
848a2ab95a3SRaju Lakkaraju MAC_MII_ACC_PHY_ADDR_MASK_;
849a2ab95a3SRaju Lakkaraju ret |= (dev_addr << MAC_MII_ACC_MIIMMD_SHIFT_) &
850a2ab95a3SRaju Lakkaraju MAC_MII_ACC_MIIMMD_MASK_;
851a2ab95a3SRaju Lakkaraju if (op == MMD_ACCESS_WRITE)
852a2ab95a3SRaju Lakkaraju ret |= MAC_MII_ACC_MIICMD_WRITE_;
853a2ab95a3SRaju Lakkaraju else if (op == MMD_ACCESS_READ)
854a2ab95a3SRaju Lakkaraju ret |= MAC_MII_ACC_MIICMD_READ_;
855a2ab95a3SRaju Lakkaraju else if (op == MMD_ACCESS_READ_INC)
856a2ab95a3SRaju Lakkaraju ret |= MAC_MII_ACC_MIICMD_READ_INC_;
857a2ab95a3SRaju Lakkaraju else
858a2ab95a3SRaju Lakkaraju ret |= MAC_MII_ACC_MIICMD_ADDR_;
859a2ab95a3SRaju Lakkaraju ret |= (MAC_MII_ACC_MII_BUSY_ | MAC_MII_ACC_MIICL45_);
860a2ab95a3SRaju Lakkaraju
861a2ab95a3SRaju Lakkaraju return ret;
862a2ab95a3SRaju Lakkaraju }
863a2ab95a3SRaju Lakkaraju
lan743x_mdiobus_read_c45(struct mii_bus * bus,int phy_id,int dev_addr,int index)8643d90c03cSAndrew Lunn static int lan743x_mdiobus_read_c45(struct mii_bus *bus, int phy_id,
8653d90c03cSAndrew Lunn int dev_addr, int index)
866a2ab95a3SRaju Lakkaraju {
867a2ab95a3SRaju Lakkaraju struct lan743x_adapter *adapter = bus->priv;
868a2ab95a3SRaju Lakkaraju u32 mmd_access;
869a2ab95a3SRaju Lakkaraju int ret;
870a2ab95a3SRaju Lakkaraju
871a2ab95a3SRaju Lakkaraju /* comfirm MII not busy */
872a2ab95a3SRaju Lakkaraju ret = lan743x_mac_mii_wait_till_not_busy(adapter);
873a2ab95a3SRaju Lakkaraju if (ret < 0)
874a2ab95a3SRaju Lakkaraju return ret;
8753d90c03cSAndrew Lunn
876a2ab95a3SRaju Lakkaraju /* Load Register Address */
8773d90c03cSAndrew Lunn lan743x_csr_write(adapter, MAC_MII_DATA, index);
8783d90c03cSAndrew Lunn mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr,
879a2ab95a3SRaju Lakkaraju MMD_ACCESS_ADDRESS);
880a2ab95a3SRaju Lakkaraju lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
881a2ab95a3SRaju Lakkaraju ret = lan743x_mac_mii_wait_till_not_busy(adapter);
882a2ab95a3SRaju Lakkaraju if (ret < 0)
883a2ab95a3SRaju Lakkaraju return ret;
8843d90c03cSAndrew Lunn
885a2ab95a3SRaju Lakkaraju /* Read Data */
8863d90c03cSAndrew Lunn mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr,
887a2ab95a3SRaju Lakkaraju MMD_ACCESS_READ);
888a2ab95a3SRaju Lakkaraju lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
889a2ab95a3SRaju Lakkaraju ret = lan743x_mac_mii_wait_till_not_busy(adapter);
890a2ab95a3SRaju Lakkaraju if (ret < 0)
891a2ab95a3SRaju Lakkaraju return ret;
8923d90c03cSAndrew Lunn
893a2ab95a3SRaju Lakkaraju ret = lan743x_csr_read(adapter, MAC_MII_DATA);
894a2ab95a3SRaju Lakkaraju return (int)(ret & 0xFFFF);
895a2ab95a3SRaju Lakkaraju }
896a2ab95a3SRaju Lakkaraju
lan743x_mdiobus_write_c45(struct mii_bus * bus,int phy_id,int dev_addr,int index,u16 regval)8973d90c03cSAndrew Lunn static int lan743x_mdiobus_write_c45(struct mii_bus *bus, int phy_id,
8983d90c03cSAndrew Lunn int dev_addr, int index, u16 regval)
899a2ab95a3SRaju Lakkaraju {
900a2ab95a3SRaju Lakkaraju struct lan743x_adapter *adapter = bus->priv;
901a2ab95a3SRaju Lakkaraju u32 mmd_access;
902a2ab95a3SRaju Lakkaraju int ret;
903a2ab95a3SRaju Lakkaraju
904a2ab95a3SRaju Lakkaraju /* confirm MII not busy */
905a2ab95a3SRaju Lakkaraju ret = lan743x_mac_mii_wait_till_not_busy(adapter);
906a2ab95a3SRaju Lakkaraju if (ret < 0)
907a2ab95a3SRaju Lakkaraju return ret;
9083d90c03cSAndrew Lunn
909a2ab95a3SRaju Lakkaraju /* Load Register Address */
9103d90c03cSAndrew Lunn lan743x_csr_write(adapter, MAC_MII_DATA, (u32)index);
9113d90c03cSAndrew Lunn mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr,
912a2ab95a3SRaju Lakkaraju MMD_ACCESS_ADDRESS);
913a2ab95a3SRaju Lakkaraju lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
914a2ab95a3SRaju Lakkaraju ret = lan743x_mac_mii_wait_till_not_busy(adapter);
915a2ab95a3SRaju Lakkaraju if (ret < 0)
916a2ab95a3SRaju Lakkaraju return ret;
9173d90c03cSAndrew Lunn
918a2ab95a3SRaju Lakkaraju /* Write Data */
919a2ab95a3SRaju Lakkaraju lan743x_csr_write(adapter, MAC_MII_DATA, (u32)regval);
9203d90c03cSAndrew Lunn mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr,
921a2ab95a3SRaju Lakkaraju MMD_ACCESS_WRITE);
922a2ab95a3SRaju Lakkaraju lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
923a2ab95a3SRaju Lakkaraju
9243d90c03cSAndrew Lunn return lan743x_mac_mii_wait_till_not_busy(adapter);
925a2ab95a3SRaju Lakkaraju }
926a2ab95a3SRaju Lakkaraju
lan743x_sgmii_wait_till_not_busy(struct lan743x_adapter * adapter)92746b777adSRaju Lakkaraju static int lan743x_sgmii_wait_till_not_busy(struct lan743x_adapter *adapter)
92846b777adSRaju Lakkaraju {
92946b777adSRaju Lakkaraju u32 data;
93046b777adSRaju Lakkaraju int ret;
93146b777adSRaju Lakkaraju
93246b777adSRaju Lakkaraju ret = readx_poll_timeout(LAN743X_CSR_READ_OP, SGMII_ACC, data,
93346b777adSRaju Lakkaraju !(data & SGMII_ACC_SGMII_BZY_), 100, 1000000);
93446b777adSRaju Lakkaraju if (ret < 0)
93546b777adSRaju Lakkaraju netif_err(adapter, drv, adapter->netdev,
93646b777adSRaju Lakkaraju "%s: error %d sgmii wait timeout\n", __func__, ret);
93746b777adSRaju Lakkaraju
93846b777adSRaju Lakkaraju return ret;
93946b777adSRaju Lakkaraju }
94046b777adSRaju Lakkaraju
lan743x_sgmii_read(struct lan743x_adapter * adapter,u8 mmd,u16 addr)94190452205SRaju Lakkaraju int lan743x_sgmii_read(struct lan743x_adapter *adapter, u8 mmd, u16 addr)
94246b777adSRaju Lakkaraju {
94346b777adSRaju Lakkaraju u32 mmd_access;
94446b777adSRaju Lakkaraju int ret;
94546b777adSRaju Lakkaraju u32 val;
94646b777adSRaju Lakkaraju
94746b777adSRaju Lakkaraju if (mmd > 31) {
94846b777adSRaju Lakkaraju netif_err(adapter, probe, adapter->netdev,
94946b777adSRaju Lakkaraju "%s mmd should <= 31\n", __func__);
95046b777adSRaju Lakkaraju return -EINVAL;
95146b777adSRaju Lakkaraju }
95246b777adSRaju Lakkaraju
95346b777adSRaju Lakkaraju mutex_lock(&adapter->sgmii_rw_lock);
95446b777adSRaju Lakkaraju /* Load Register Address */
95546b777adSRaju Lakkaraju mmd_access = mmd << SGMII_ACC_SGMII_MMD_SHIFT_;
95646b777adSRaju Lakkaraju mmd_access |= (addr | SGMII_ACC_SGMII_BZY_);
95746b777adSRaju Lakkaraju lan743x_csr_write(adapter, SGMII_ACC, mmd_access);
95846b777adSRaju Lakkaraju ret = lan743x_sgmii_wait_till_not_busy(adapter);
95946b777adSRaju Lakkaraju if (ret < 0)
96046b777adSRaju Lakkaraju goto sgmii_unlock;
96146b777adSRaju Lakkaraju
96246b777adSRaju Lakkaraju val = lan743x_csr_read(adapter, SGMII_DATA);
96346b777adSRaju Lakkaraju ret = (int)(val & SGMII_DATA_MASK_);
96446b777adSRaju Lakkaraju
96546b777adSRaju Lakkaraju sgmii_unlock:
96646b777adSRaju Lakkaraju mutex_unlock(&adapter->sgmii_rw_lock);
96746b777adSRaju Lakkaraju
96846b777adSRaju Lakkaraju return ret;
96946b777adSRaju Lakkaraju }
97046b777adSRaju Lakkaraju
lan743x_sgmii_write(struct lan743x_adapter * adapter,u8 mmd,u16 addr,u16 val)97146b777adSRaju Lakkaraju static int lan743x_sgmii_write(struct lan743x_adapter *adapter,
97246b777adSRaju Lakkaraju u8 mmd, u16 addr, u16 val)
97346b777adSRaju Lakkaraju {
97446b777adSRaju Lakkaraju u32 mmd_access;
97546b777adSRaju Lakkaraju int ret;
97646b777adSRaju Lakkaraju
97746b777adSRaju Lakkaraju if (mmd > 31) {
97846b777adSRaju Lakkaraju netif_err(adapter, probe, adapter->netdev,
97946b777adSRaju Lakkaraju "%s mmd should <= 31\n", __func__);
98046b777adSRaju Lakkaraju return -EINVAL;
98146b777adSRaju Lakkaraju }
98246b777adSRaju Lakkaraju mutex_lock(&adapter->sgmii_rw_lock);
98346b777adSRaju Lakkaraju /* Load Register Data */
98446b777adSRaju Lakkaraju lan743x_csr_write(adapter, SGMII_DATA, (u32)(val & SGMII_DATA_MASK_));
98546b777adSRaju Lakkaraju /* Load Register Address */
98646b777adSRaju Lakkaraju mmd_access = mmd << SGMII_ACC_SGMII_MMD_SHIFT_;
98746b777adSRaju Lakkaraju mmd_access |= (addr | SGMII_ACC_SGMII_BZY_ | SGMII_ACC_SGMII_WR_);
98846b777adSRaju Lakkaraju lan743x_csr_write(adapter, SGMII_ACC, mmd_access);
98946b777adSRaju Lakkaraju ret = lan743x_sgmii_wait_till_not_busy(adapter);
99046b777adSRaju Lakkaraju mutex_unlock(&adapter->sgmii_rw_lock);
99146b777adSRaju Lakkaraju
99246b777adSRaju Lakkaraju return ret;
99346b777adSRaju Lakkaraju }
99446b777adSRaju Lakkaraju
lan743x_sgmii_mpll_set(struct lan743x_adapter * adapter,u16 baud)99546b777adSRaju Lakkaraju static int lan743x_sgmii_mpll_set(struct lan743x_adapter *adapter,
99646b777adSRaju Lakkaraju u16 baud)
99746b777adSRaju Lakkaraju {
99846b777adSRaju Lakkaraju int mpllctrl0;
99946b777adSRaju Lakkaraju int mpllctrl1;
100046b777adSRaju Lakkaraju int miscctrl1;
100146b777adSRaju Lakkaraju int ret;
100246b777adSRaju Lakkaraju
100346b777adSRaju Lakkaraju mpllctrl0 = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
100446b777adSRaju Lakkaraju VR_MII_GEN2_4_MPLL_CTRL0);
100546b777adSRaju Lakkaraju if (mpllctrl0 < 0)
100646b777adSRaju Lakkaraju return mpllctrl0;
100746b777adSRaju Lakkaraju
100846b777adSRaju Lakkaraju mpllctrl0 &= ~VR_MII_MPLL_CTRL0_USE_REFCLK_PAD_;
100946b777adSRaju Lakkaraju if (baud == VR_MII_BAUD_RATE_1P25GBPS) {
101046b777adSRaju Lakkaraju mpllctrl1 = VR_MII_MPLL_MULTIPLIER_100;
101146b777adSRaju Lakkaraju /* mpll_baud_clk/4 */
101246b777adSRaju Lakkaraju miscctrl1 = 0xA;
101346b777adSRaju Lakkaraju } else {
101446b777adSRaju Lakkaraju mpllctrl1 = VR_MII_MPLL_MULTIPLIER_125;
101546b777adSRaju Lakkaraju /* mpll_baud_clk/2 */
101646b777adSRaju Lakkaraju miscctrl1 = 0x5;
101746b777adSRaju Lakkaraju }
101846b777adSRaju Lakkaraju
101946b777adSRaju Lakkaraju ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
102046b777adSRaju Lakkaraju VR_MII_GEN2_4_MPLL_CTRL0, mpllctrl0);
102146b777adSRaju Lakkaraju if (ret < 0)
102246b777adSRaju Lakkaraju return ret;
102346b777adSRaju Lakkaraju
102446b777adSRaju Lakkaraju ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
102546b777adSRaju Lakkaraju VR_MII_GEN2_4_MPLL_CTRL1, mpllctrl1);
102646b777adSRaju Lakkaraju if (ret < 0)
102746b777adSRaju Lakkaraju return ret;
102846b777adSRaju Lakkaraju
102946b777adSRaju Lakkaraju return lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
103046b777adSRaju Lakkaraju VR_MII_GEN2_4_MISC_CTRL1, miscctrl1);
103146b777adSRaju Lakkaraju }
103246b777adSRaju Lakkaraju
lan743x_sgmii_2_5G_mode_set(struct lan743x_adapter * adapter,bool enable)103346b777adSRaju Lakkaraju static int lan743x_sgmii_2_5G_mode_set(struct lan743x_adapter *adapter,
103446b777adSRaju Lakkaraju bool enable)
103546b777adSRaju Lakkaraju {
103646b777adSRaju Lakkaraju if (enable)
103746b777adSRaju Lakkaraju return lan743x_sgmii_mpll_set(adapter,
103846b777adSRaju Lakkaraju VR_MII_BAUD_RATE_3P125GBPS);
103946b777adSRaju Lakkaraju else
104046b777adSRaju Lakkaraju return lan743x_sgmii_mpll_set(adapter,
104146b777adSRaju Lakkaraju VR_MII_BAUD_RATE_1P25GBPS);
104246b777adSRaju Lakkaraju }
104346b777adSRaju Lakkaraju
lan743x_is_sgmii_2_5G_mode(struct lan743x_adapter * adapter,bool * status)104446b777adSRaju Lakkaraju static int lan743x_is_sgmii_2_5G_mode(struct lan743x_adapter *adapter,
104546b777adSRaju Lakkaraju bool *status)
104646b777adSRaju Lakkaraju {
104746b777adSRaju Lakkaraju int ret;
104846b777adSRaju Lakkaraju
104946b777adSRaju Lakkaraju ret = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
105046b777adSRaju Lakkaraju VR_MII_GEN2_4_MPLL_CTRL1);
105146b777adSRaju Lakkaraju if (ret < 0)
105246b777adSRaju Lakkaraju return ret;
105346b777adSRaju Lakkaraju
105446b777adSRaju Lakkaraju if (ret == VR_MII_MPLL_MULTIPLIER_125 ||
105546b777adSRaju Lakkaraju ret == VR_MII_MPLL_MULTIPLIER_50)
105646b777adSRaju Lakkaraju *status = true;
105746b777adSRaju Lakkaraju else
105846b777adSRaju Lakkaraju *status = false;
105946b777adSRaju Lakkaraju
106046b777adSRaju Lakkaraju return 0;
106146b777adSRaju Lakkaraju }
106246b777adSRaju Lakkaraju
lan743x_sgmii_aneg_update(struct lan743x_adapter * adapter)106346b777adSRaju Lakkaraju static int lan743x_sgmii_aneg_update(struct lan743x_adapter *adapter)
106446b777adSRaju Lakkaraju {
106546b777adSRaju Lakkaraju enum lan743x_sgmii_lsd lsd = adapter->sgmii_lsd;
106646b777adSRaju Lakkaraju int mii_ctrl;
106746b777adSRaju Lakkaraju int dgt_ctrl;
106846b777adSRaju Lakkaraju int an_ctrl;
106946b777adSRaju Lakkaraju int ret;
107046b777adSRaju Lakkaraju
107146b777adSRaju Lakkaraju if (lsd == LINK_2500_MASTER || lsd == LINK_2500_SLAVE)
107246b777adSRaju Lakkaraju /* Switch to 2.5 Gbps */
107346b777adSRaju Lakkaraju ret = lan743x_sgmii_2_5G_mode_set(adapter, true);
107446b777adSRaju Lakkaraju else
107546b777adSRaju Lakkaraju /* Switch to 10/100/1000 Mbps clock */
107646b777adSRaju Lakkaraju ret = lan743x_sgmii_2_5G_mode_set(adapter, false);
107746b777adSRaju Lakkaraju if (ret < 0)
107846b777adSRaju Lakkaraju return ret;
107946b777adSRaju Lakkaraju
108046b777adSRaju Lakkaraju /* Enable SGMII Auto NEG */
108146b777adSRaju Lakkaraju mii_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR);
108246b777adSRaju Lakkaraju if (mii_ctrl < 0)
108346b777adSRaju Lakkaraju return mii_ctrl;
108446b777adSRaju Lakkaraju
108546b777adSRaju Lakkaraju an_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, VR_MII_AN_CTRL);
108646b777adSRaju Lakkaraju if (an_ctrl < 0)
108746b777adSRaju Lakkaraju return an_ctrl;
108846b777adSRaju Lakkaraju
108946b777adSRaju Lakkaraju dgt_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
109046b777adSRaju Lakkaraju VR_MII_DIG_CTRL1);
109146b777adSRaju Lakkaraju if (dgt_ctrl < 0)
109246b777adSRaju Lakkaraju return dgt_ctrl;
109346b777adSRaju Lakkaraju
109446b777adSRaju Lakkaraju if (lsd == LINK_2500_MASTER || lsd == LINK_2500_SLAVE) {
109546b777adSRaju Lakkaraju mii_ctrl &= ~(BMCR_ANENABLE | BMCR_ANRESTART | BMCR_SPEED100);
109646b777adSRaju Lakkaraju mii_ctrl |= BMCR_SPEED1000;
109746b777adSRaju Lakkaraju dgt_ctrl |= VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_;
109846b777adSRaju Lakkaraju dgt_ctrl &= ~VR_MII_DIG_CTRL1_MAC_AUTO_SW_;
109946b777adSRaju Lakkaraju /* In order for Auto-Negotiation to operate properly at
110046b777adSRaju Lakkaraju * 2.5 Gbps the 1.6ms link timer values must be adjusted
110146b777adSRaju Lakkaraju * The VR_MII_LINK_TIMER_CTRL Register must be set to
110246b777adSRaju Lakkaraju * 16'h7A1 and The CL37_TMR_OVR_RIDE bit of the
110346b777adSRaju Lakkaraju * VR_MII_DIG_CTRL1 Register set to 1
110446b777adSRaju Lakkaraju */
110546b777adSRaju Lakkaraju ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
110646b777adSRaju Lakkaraju VR_MII_LINK_TIMER_CTRL, 0x7A1);
110746b777adSRaju Lakkaraju if (ret < 0)
110846b777adSRaju Lakkaraju return ret;
110946b777adSRaju Lakkaraju } else {
111046b777adSRaju Lakkaraju mii_ctrl |= (BMCR_ANENABLE | BMCR_ANRESTART);
111146b777adSRaju Lakkaraju an_ctrl &= ~VR_MII_AN_CTRL_SGMII_LINK_STS_;
111246b777adSRaju Lakkaraju dgt_ctrl &= ~VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_;
111346b777adSRaju Lakkaraju dgt_ctrl |= VR_MII_DIG_CTRL1_MAC_AUTO_SW_;
111446b777adSRaju Lakkaraju }
111546b777adSRaju Lakkaraju
111646b777adSRaju Lakkaraju ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR,
111746b777adSRaju Lakkaraju mii_ctrl);
111846b777adSRaju Lakkaraju if (ret < 0)
111946b777adSRaju Lakkaraju return ret;
112046b777adSRaju Lakkaraju
112146b777adSRaju Lakkaraju ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
112246b777adSRaju Lakkaraju VR_MII_DIG_CTRL1, dgt_ctrl);
112346b777adSRaju Lakkaraju if (ret < 0)
112446b777adSRaju Lakkaraju return ret;
112546b777adSRaju Lakkaraju
112646b777adSRaju Lakkaraju return lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
112746b777adSRaju Lakkaraju VR_MII_AN_CTRL, an_ctrl);
112846b777adSRaju Lakkaraju }
112946b777adSRaju Lakkaraju
lan743x_pcs_seq_state(struct lan743x_adapter * adapter,u8 state)113046b777adSRaju Lakkaraju static int lan743x_pcs_seq_state(struct lan743x_adapter *adapter, u8 state)
113146b777adSRaju Lakkaraju {
113246b777adSRaju Lakkaraju u8 wait_cnt = 0;
113346b777adSRaju Lakkaraju u32 dig_sts;
113446b777adSRaju Lakkaraju
113546b777adSRaju Lakkaraju do {
113646b777adSRaju Lakkaraju dig_sts = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
113746b777adSRaju Lakkaraju VR_MII_DIG_STS);
113846b777adSRaju Lakkaraju if (((dig_sts & VR_MII_DIG_STS_PSEQ_STATE_MASK_) >>
113946b777adSRaju Lakkaraju VR_MII_DIG_STS_PSEQ_STATE_POS_) == state)
114046b777adSRaju Lakkaraju break;
114146b777adSRaju Lakkaraju usleep_range(1000, 2000);
114246b777adSRaju Lakkaraju } while (wait_cnt++ < 10);
114346b777adSRaju Lakkaraju
114446b777adSRaju Lakkaraju if (wait_cnt >= 10)
114546b777adSRaju Lakkaraju return -ETIMEDOUT;
114646b777adSRaju Lakkaraju
114746b777adSRaju Lakkaraju return 0;
114846b777adSRaju Lakkaraju }
114946b777adSRaju Lakkaraju
lan743x_sgmii_config(struct lan743x_adapter * adapter)115046b777adSRaju Lakkaraju static int lan743x_sgmii_config(struct lan743x_adapter *adapter)
115146b777adSRaju Lakkaraju {
115246b777adSRaju Lakkaraju struct net_device *netdev = adapter->netdev;
115346b777adSRaju Lakkaraju struct phy_device *phydev = netdev->phydev;
115446b777adSRaju Lakkaraju enum lan743x_sgmii_lsd lsd = POWER_DOWN;
115546b777adSRaju Lakkaraju int mii_ctl;
115646b777adSRaju Lakkaraju bool status;
115746b777adSRaju Lakkaraju int ret;
115846b777adSRaju Lakkaraju
115946b777adSRaju Lakkaraju switch (phydev->speed) {
116046b777adSRaju Lakkaraju case SPEED_2500:
116146b777adSRaju Lakkaraju if (phydev->master_slave_state == MASTER_SLAVE_STATE_MASTER)
116246b777adSRaju Lakkaraju lsd = LINK_2500_MASTER;
116346b777adSRaju Lakkaraju else
116446b777adSRaju Lakkaraju lsd = LINK_2500_SLAVE;
116546b777adSRaju Lakkaraju break;
116646b777adSRaju Lakkaraju case SPEED_1000:
116746b777adSRaju Lakkaraju if (phydev->master_slave_state == MASTER_SLAVE_STATE_MASTER)
116846b777adSRaju Lakkaraju lsd = LINK_1000_MASTER;
116946b777adSRaju Lakkaraju else
117046b777adSRaju Lakkaraju lsd = LINK_1000_SLAVE;
117146b777adSRaju Lakkaraju break;
117246b777adSRaju Lakkaraju case SPEED_100:
117346b777adSRaju Lakkaraju if (phydev->duplex)
117446b777adSRaju Lakkaraju lsd = LINK_100FD;
117546b777adSRaju Lakkaraju else
117646b777adSRaju Lakkaraju lsd = LINK_100HD;
117746b777adSRaju Lakkaraju break;
117846b777adSRaju Lakkaraju case SPEED_10:
117946b777adSRaju Lakkaraju if (phydev->duplex)
118046b777adSRaju Lakkaraju lsd = LINK_10FD;
118146b777adSRaju Lakkaraju else
118246b777adSRaju Lakkaraju lsd = LINK_10HD;
118346b777adSRaju Lakkaraju break;
118446b777adSRaju Lakkaraju default:
118546b777adSRaju Lakkaraju netif_err(adapter, drv, adapter->netdev,
118646b777adSRaju Lakkaraju "Invalid speed %d\n", phydev->speed);
118746b777adSRaju Lakkaraju return -EINVAL;
118846b777adSRaju Lakkaraju }
118946b777adSRaju Lakkaraju
119046b777adSRaju Lakkaraju adapter->sgmii_lsd = lsd;
119146b777adSRaju Lakkaraju ret = lan743x_sgmii_aneg_update(adapter);
119246b777adSRaju Lakkaraju if (ret < 0) {
119346b777adSRaju Lakkaraju netif_err(adapter, drv, adapter->netdev,
119446b777adSRaju Lakkaraju "error %d SGMII cfg failed\n", ret);
119546b777adSRaju Lakkaraju return ret;
119646b777adSRaju Lakkaraju }
119746b777adSRaju Lakkaraju
119846b777adSRaju Lakkaraju ret = lan743x_is_sgmii_2_5G_mode(adapter, &status);
119946b777adSRaju Lakkaraju if (ret < 0) {
120046b777adSRaju Lakkaraju netif_err(adapter, drv, adapter->netdev,
120146b777adSRaju Lakkaraju "erro %d SGMII get mode failed\n", ret);
120246b777adSRaju Lakkaraju return ret;
120346b777adSRaju Lakkaraju }
120446b777adSRaju Lakkaraju
120546b777adSRaju Lakkaraju if (status)
120646b777adSRaju Lakkaraju netif_dbg(adapter, drv, adapter->netdev,
120746b777adSRaju Lakkaraju "SGMII 2.5G mode enable\n");
120846b777adSRaju Lakkaraju else
120946b777adSRaju Lakkaraju netif_dbg(adapter, drv, adapter->netdev,
121046b777adSRaju Lakkaraju "SGMII 1G mode enable\n");
121146b777adSRaju Lakkaraju
121246b777adSRaju Lakkaraju /* SGMII/1000/2500BASE-X PCS power down */
121346b777adSRaju Lakkaraju mii_ctl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR);
1214b4cbd7a9SDan Carpenter if (mii_ctl < 0)
1215b4cbd7a9SDan Carpenter return mii_ctl;
121646b777adSRaju Lakkaraju
121746b777adSRaju Lakkaraju mii_ctl |= BMCR_PDOWN;
121846b777adSRaju Lakkaraju ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl);
121946b777adSRaju Lakkaraju if (ret < 0)
122046b777adSRaju Lakkaraju return ret;
122146b777adSRaju Lakkaraju
122246b777adSRaju Lakkaraju ret = lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_DOWN);
122346b777adSRaju Lakkaraju if (ret < 0)
122446b777adSRaju Lakkaraju return ret;
122546b777adSRaju Lakkaraju
122646b777adSRaju Lakkaraju /* SGMII/1000/2500BASE-X PCS power up */
122746b777adSRaju Lakkaraju mii_ctl &= ~BMCR_PDOWN;
122846b777adSRaju Lakkaraju ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl);
122946b777adSRaju Lakkaraju if (ret < 0)
123046b777adSRaju Lakkaraju return ret;
123146b777adSRaju Lakkaraju
123246b777adSRaju Lakkaraju ret = lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_UP);
123346b777adSRaju Lakkaraju if (ret < 0)
123446b777adSRaju Lakkaraju return ret;
123546b777adSRaju Lakkaraju
123646b777adSRaju Lakkaraju return 0;
123746b777adSRaju Lakkaraju }
123846b777adSRaju Lakkaraju
lan743x_mac_set_address(struct lan743x_adapter * adapter,u8 * addr)123923f0703cSBryan Whitehead static void lan743x_mac_set_address(struct lan743x_adapter *adapter,
124023f0703cSBryan Whitehead u8 *addr)
124123f0703cSBryan Whitehead {
124223f0703cSBryan Whitehead u32 addr_lo, addr_hi;
124323f0703cSBryan Whitehead
124423f0703cSBryan Whitehead addr_lo = addr[0] |
124523f0703cSBryan Whitehead addr[1] << 8 |
124623f0703cSBryan Whitehead addr[2] << 16 |
124723f0703cSBryan Whitehead addr[3] << 24;
124823f0703cSBryan Whitehead addr_hi = addr[4] |
124923f0703cSBryan Whitehead addr[5] << 8;
125023f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_RX_ADDRL, addr_lo);
125123f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_RX_ADDRH, addr_hi);
125223f0703cSBryan Whitehead
125323f0703cSBryan Whitehead ether_addr_copy(adapter->mac_address, addr);
125423f0703cSBryan Whitehead netif_info(adapter, drv, adapter->netdev,
125523f0703cSBryan Whitehead "MAC address set to %pM\n", addr);
125623f0703cSBryan Whitehead }
125723f0703cSBryan Whitehead
lan743x_mac_init(struct lan743x_adapter * adapter)125823f0703cSBryan Whitehead static int lan743x_mac_init(struct lan743x_adapter *adapter)
125923f0703cSBryan Whitehead {
126023f0703cSBryan Whitehead bool mac_address_valid = true;
126123f0703cSBryan Whitehead struct net_device *netdev;
126223f0703cSBryan Whitehead u32 mac_addr_hi = 0;
126323f0703cSBryan Whitehead u32 mac_addr_lo = 0;
126423f0703cSBryan Whitehead u32 data;
126523f0703cSBryan Whitehead
126623f0703cSBryan Whitehead netdev = adapter->netdev;
126723f0703cSBryan Whitehead
12686f197fb6SRoelof Berg /* disable auto duplex, and speed detection. Phylib does that */
126923f0703cSBryan Whitehead data = lan743x_csr_read(adapter, MAC_CR);
12706f197fb6SRoelof Berg data &= ~(MAC_CR_ADD_ | MAC_CR_ASD_);
127123f0703cSBryan Whitehead data |= MAC_CR_CNTR_RST_;
127223f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_CR, data);
127323f0703cSBryan Whitehead
1274c90834cdSTim Harvey if (!is_valid_ether_addr(adapter->mac_address)) {
127523f0703cSBryan Whitehead mac_addr_hi = lan743x_csr_read(adapter, MAC_RX_ADDRH);
127623f0703cSBryan Whitehead mac_addr_lo = lan743x_csr_read(adapter, MAC_RX_ADDRL);
127723f0703cSBryan Whitehead adapter->mac_address[0] = mac_addr_lo & 0xFF;
127823f0703cSBryan Whitehead adapter->mac_address[1] = (mac_addr_lo >> 8) & 0xFF;
127923f0703cSBryan Whitehead adapter->mac_address[2] = (mac_addr_lo >> 16) & 0xFF;
128023f0703cSBryan Whitehead adapter->mac_address[3] = (mac_addr_lo >> 24) & 0xFF;
128123f0703cSBryan Whitehead adapter->mac_address[4] = mac_addr_hi & 0xFF;
128223f0703cSBryan Whitehead adapter->mac_address[5] = (mac_addr_hi >> 8) & 0xFF;
128323f0703cSBryan Whitehead
128423f0703cSBryan Whitehead if (((mac_addr_hi & 0x0000FFFF) == 0x0000FFFF) &&
128523f0703cSBryan Whitehead mac_addr_lo == 0xFFFFFFFF) {
128623f0703cSBryan Whitehead mac_address_valid = false;
128723f0703cSBryan Whitehead } else if (!is_valid_ether_addr(adapter->mac_address)) {
128823f0703cSBryan Whitehead mac_address_valid = false;
128923f0703cSBryan Whitehead }
129023f0703cSBryan Whitehead
129123f0703cSBryan Whitehead if (!mac_address_valid)
12926c1f0a1fSJoe Perches eth_random_addr(adapter->mac_address);
1293c90834cdSTim Harvey }
129423f0703cSBryan Whitehead lan743x_mac_set_address(adapter, adapter->mac_address);
1295f3956ebbSJakub Kicinski eth_hw_addr_set(netdev, adapter->mac_address);
1296c90834cdSTim Harvey
129723f0703cSBryan Whitehead return 0;
129823f0703cSBryan Whitehead }
129923f0703cSBryan Whitehead
lan743x_mac_open(struct lan743x_adapter * adapter)130023f0703cSBryan Whitehead static int lan743x_mac_open(struct lan743x_adapter *adapter)
130123f0703cSBryan Whitehead {
130223f0703cSBryan Whitehead u32 temp;
130323f0703cSBryan Whitehead
130423f0703cSBryan Whitehead temp = lan743x_csr_read(adapter, MAC_RX);
130523f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_RX, temp | MAC_RX_RXEN_);
130623f0703cSBryan Whitehead temp = lan743x_csr_read(adapter, MAC_TX);
130723f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_TX, temp | MAC_TX_TXEN_);
1308585bd812SXu Wang return 0;
130923f0703cSBryan Whitehead }
131023f0703cSBryan Whitehead
lan743x_mac_close(struct lan743x_adapter * adapter)131123f0703cSBryan Whitehead static void lan743x_mac_close(struct lan743x_adapter *adapter)
131223f0703cSBryan Whitehead {
131323f0703cSBryan Whitehead u32 temp;
131423f0703cSBryan Whitehead
131523f0703cSBryan Whitehead temp = lan743x_csr_read(adapter, MAC_TX);
131623f0703cSBryan Whitehead temp &= ~MAC_TX_TXEN_;
131723f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_TX, temp);
131823f0703cSBryan Whitehead lan743x_csr_wait_for_bit(adapter, MAC_TX, MAC_TX_TXD_,
131923f0703cSBryan Whitehead 1, 1000, 20000, 100);
132023f0703cSBryan Whitehead
132123f0703cSBryan Whitehead temp = lan743x_csr_read(adapter, MAC_RX);
132223f0703cSBryan Whitehead temp &= ~MAC_RX_RXEN_;
132323f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_RX, temp);
132423f0703cSBryan Whitehead lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_,
132523f0703cSBryan Whitehead 1, 1000, 20000, 100);
132623f0703cSBryan Whitehead }
132723f0703cSBryan Whitehead
lan743x_mac_flow_ctrl_set_enables(struct lan743x_adapter * adapter,bool tx_enable,bool rx_enable)1328cdc04540SRaju Lakkaraju void lan743x_mac_flow_ctrl_set_enables(struct lan743x_adapter *adapter,
132923f0703cSBryan Whitehead bool tx_enable, bool rx_enable)
133023f0703cSBryan Whitehead {
133123f0703cSBryan Whitehead u32 flow_setting = 0;
133223f0703cSBryan Whitehead
133323f0703cSBryan Whitehead /* set maximum pause time because when fifo space frees
133423f0703cSBryan Whitehead * up a zero value pause frame will be sent to release the pause
133523f0703cSBryan Whitehead */
133623f0703cSBryan Whitehead flow_setting = MAC_FLOW_CR_FCPT_MASK_;
133723f0703cSBryan Whitehead if (tx_enable)
133823f0703cSBryan Whitehead flow_setting |= MAC_FLOW_CR_TX_FCEN_;
133923f0703cSBryan Whitehead if (rx_enable)
134023f0703cSBryan Whitehead flow_setting |= MAC_FLOW_CR_RX_FCEN_;
134123f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_FLOW, flow_setting);
134223f0703cSBryan Whitehead }
134323f0703cSBryan Whitehead
lan743x_mac_set_mtu(struct lan743x_adapter * adapter,int new_mtu)134423f0703cSBryan Whitehead static int lan743x_mac_set_mtu(struct lan743x_adapter *adapter, int new_mtu)
134523f0703cSBryan Whitehead {
134623f0703cSBryan Whitehead int enabled = 0;
134723f0703cSBryan Whitehead u32 mac_rx = 0;
134823f0703cSBryan Whitehead
134923f0703cSBryan Whitehead mac_rx = lan743x_csr_read(adapter, MAC_RX);
135023f0703cSBryan Whitehead if (mac_rx & MAC_RX_RXEN_) {
135123f0703cSBryan Whitehead enabled = 1;
135223f0703cSBryan Whitehead if (mac_rx & MAC_RX_RXD_) {
135323f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_RX, mac_rx);
135423f0703cSBryan Whitehead mac_rx &= ~MAC_RX_RXD_;
135523f0703cSBryan Whitehead }
135623f0703cSBryan Whitehead mac_rx &= ~MAC_RX_RXEN_;
135723f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_RX, mac_rx);
135823f0703cSBryan Whitehead lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_,
135923f0703cSBryan Whitehead 1, 1000, 20000, 100);
136023f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_RX, mac_rx | MAC_RX_RXD_);
136123f0703cSBryan Whitehead }
136223f0703cSBryan Whitehead
136323f0703cSBryan Whitehead mac_rx &= ~(MAC_RX_MAX_SIZE_MASK_);
13643bc41d6dSSven Van Asbroeck mac_rx |= (((new_mtu + ETH_HLEN + ETH_FCS_LEN)
13653bc41d6dSSven Van Asbroeck << MAC_RX_MAX_SIZE_SHIFT_) & MAC_RX_MAX_SIZE_MASK_);
136623f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_RX, mac_rx);
136723f0703cSBryan Whitehead
136823f0703cSBryan Whitehead if (enabled) {
136923f0703cSBryan Whitehead mac_rx |= MAC_RX_RXEN_;
137023f0703cSBryan Whitehead lan743x_csr_write(adapter, MAC_RX, mac_rx);
137123f0703cSBryan Whitehead }
137223f0703cSBryan Whitehead return 0;
137323f0703cSBryan Whitehead }
137423f0703cSBryan Whitehead
137523f0703cSBryan Whitehead /* PHY */
lan743x_phy_reset(struct lan743x_adapter * adapter)137623f0703cSBryan Whitehead static int lan743x_phy_reset(struct lan743x_adapter *adapter)
137723f0703cSBryan Whitehead {
137823f0703cSBryan Whitehead u32 data;
137923f0703cSBryan Whitehead
138023f0703cSBryan Whitehead /* Only called with in probe, and before mdiobus_register */
138123f0703cSBryan Whitehead
138223f0703cSBryan Whitehead data = lan743x_csr_read(adapter, PMT_CTL);
138323f0703cSBryan Whitehead data |= PMT_CTL_ETH_PHY_RST_;
138423f0703cSBryan Whitehead lan743x_csr_write(adapter, PMT_CTL, data);
138523f0703cSBryan Whitehead
138623f0703cSBryan Whitehead return readx_poll_timeout(LAN743X_CSR_READ_OP, PMT_CTL, data,
138723f0703cSBryan Whitehead (!(data & PMT_CTL_ETH_PHY_RST_) &&
138823f0703cSBryan Whitehead (data & PMT_CTL_READY_)),
138923f0703cSBryan Whitehead 50000, 1000000);
139023f0703cSBryan Whitehead }
139123f0703cSBryan Whitehead
lan743x_phy_update_flowcontrol(struct lan743x_adapter * adapter,u16 local_adv,u16 remote_adv)139223f0703cSBryan Whitehead static void lan743x_phy_update_flowcontrol(struct lan743x_adapter *adapter,
1393ddb826c2SHeiner Kallweit u16 local_adv, u16 remote_adv)
139423f0703cSBryan Whitehead {
139523f0703cSBryan Whitehead struct lan743x_phy *phy = &adapter->phy;
139623f0703cSBryan Whitehead u8 cap;
139723f0703cSBryan Whitehead
139823f0703cSBryan Whitehead if (phy->fc_autoneg)
139923f0703cSBryan Whitehead cap = mii_resolve_flowctrl_fdx(local_adv, remote_adv);
140023f0703cSBryan Whitehead else
140123f0703cSBryan Whitehead cap = phy->fc_request_control;
140223f0703cSBryan Whitehead
140323f0703cSBryan Whitehead lan743x_mac_flow_ctrl_set_enables(adapter,
140423f0703cSBryan Whitehead cap & FLOW_CTRL_TX,
140523f0703cSBryan Whitehead cap & FLOW_CTRL_RX);
140623f0703cSBryan Whitehead }
140723f0703cSBryan Whitehead
lan743x_phy_init(struct lan743x_adapter * adapter)140823f0703cSBryan Whitehead static int lan743x_phy_init(struct lan743x_adapter *adapter)
140923f0703cSBryan Whitehead {
14108e8af97aSColin Ian King return lan743x_phy_reset(adapter);
141123f0703cSBryan Whitehead }
141223f0703cSBryan Whitehead
lan743x_phy_link_status_change(struct net_device * netdev)141323f0703cSBryan Whitehead static void lan743x_phy_link_status_change(struct net_device *netdev)
141423f0703cSBryan Whitehead {
141523f0703cSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
141623f0703cSBryan Whitehead struct phy_device *phydev = netdev->phydev;
14176f197fb6SRoelof Berg u32 data;
141823f0703cSBryan Whitehead
141923f0703cSBryan Whitehead phy_print_status(phydev);
142023f0703cSBryan Whitehead if (phydev->state == PHY_RUNNING) {
142123f0703cSBryan Whitehead int remote_advertisement = 0;
142223f0703cSBryan Whitehead int local_advertisement = 0;
142323f0703cSBryan Whitehead
14246f197fb6SRoelof Berg data = lan743x_csr_read(adapter, MAC_CR);
14256f197fb6SRoelof Berg
14266f197fb6SRoelof Berg /* set duplex mode */
14276f197fb6SRoelof Berg if (phydev->duplex)
14286f197fb6SRoelof Berg data |= MAC_CR_DPX_;
14296f197fb6SRoelof Berg else
14306f197fb6SRoelof Berg data &= ~MAC_CR_DPX_;
14316f197fb6SRoelof Berg
14326f197fb6SRoelof Berg /* set bus speed */
14336f197fb6SRoelof Berg switch (phydev->speed) {
14346f197fb6SRoelof Berg case SPEED_10:
14356f197fb6SRoelof Berg data &= ~MAC_CR_CFG_H_;
14366f197fb6SRoelof Berg data &= ~MAC_CR_CFG_L_;
14376f197fb6SRoelof Berg break;
14386f197fb6SRoelof Berg case SPEED_100:
14396f197fb6SRoelof Berg data &= ~MAC_CR_CFG_H_;
14406f197fb6SRoelof Berg data |= MAC_CR_CFG_L_;
14416f197fb6SRoelof Berg break;
14426f197fb6SRoelof Berg case SPEED_1000:
14436f197fb6SRoelof Berg data |= MAC_CR_CFG_H_;
14447cdee28cSRoelof Berg data &= ~MAC_CR_CFG_L_;
14456f197fb6SRoelof Berg break;
144646b777adSRaju Lakkaraju case SPEED_2500:
144746b777adSRaju Lakkaraju data |= MAC_CR_CFG_H_;
144846b777adSRaju Lakkaraju data |= MAC_CR_CFG_L_;
144946b777adSRaju Lakkaraju break;
14506f197fb6SRoelof Berg }
14516f197fb6SRoelof Berg lan743x_csr_write(adapter, MAC_CR, data);
14526f197fb6SRoelof Berg
1453a0071840SBryan Whitehead local_advertisement =
1454a0071840SBryan Whitehead linkmode_adv_to_mii_adv_t(phydev->advertising);
1455a0071840SBryan Whitehead remote_advertisement =
1456a0071840SBryan Whitehead linkmode_adv_to_mii_adv_t(phydev->lp_advertising);
145723f0703cSBryan Whitehead
1458ddb826c2SHeiner Kallweit lan743x_phy_update_flowcontrol(adapter, local_advertisement,
145923f0703cSBryan Whitehead remote_advertisement);
1460ddb826c2SHeiner Kallweit lan743x_ptp_update_latency(adapter, phydev->speed);
146146b777adSRaju Lakkaraju if (phydev->interface == PHY_INTERFACE_MODE_SGMII ||
146246b777adSRaju Lakkaraju phydev->interface == PHY_INTERFACE_MODE_1000BASEX ||
146346b777adSRaju Lakkaraju phydev->interface == PHY_INTERFACE_MODE_2500BASEX)
146446b777adSRaju Lakkaraju lan743x_sgmii_config(adapter);
146523f0703cSBryan Whitehead }
146623f0703cSBryan Whitehead }
146723f0703cSBryan Whitehead
lan743x_phy_close(struct lan743x_adapter * adapter)146823f0703cSBryan Whitehead static void lan743x_phy_close(struct lan743x_adapter *adapter)
146923f0703cSBryan Whitehead {
147023f0703cSBryan Whitehead struct net_device *netdev = adapter->netdev;
147123f0703cSBryan Whitehead
147223f0703cSBryan Whitehead phy_stop(netdev->phydev);
147323f0703cSBryan Whitehead phy_disconnect(netdev->phydev);
147423f0703cSBryan Whitehead }
147523f0703cSBryan Whitehead
lan743x_phy_interface_select(struct lan743x_adapter * adapter)1476e86c7210SPavithra Sathyanarayanan static void lan743x_phy_interface_select(struct lan743x_adapter *adapter)
1477e86c7210SPavithra Sathyanarayanan {
1478e86c7210SPavithra Sathyanarayanan u32 id_rev;
1479e86c7210SPavithra Sathyanarayanan u32 data;
1480e86c7210SPavithra Sathyanarayanan
1481e86c7210SPavithra Sathyanarayanan data = lan743x_csr_read(adapter, MAC_CR);
1482e86c7210SPavithra Sathyanarayanan id_rev = adapter->csr.id_rev & ID_REV_ID_MASK_;
1483e86c7210SPavithra Sathyanarayanan
1484e86c7210SPavithra Sathyanarayanan if (adapter->is_pci11x1x && adapter->is_sgmii_en)
1485e86c7210SPavithra Sathyanarayanan adapter->phy_interface = PHY_INTERFACE_MODE_SGMII;
1486e86c7210SPavithra Sathyanarayanan else if (id_rev == ID_REV_ID_LAN7430_)
1487e86c7210SPavithra Sathyanarayanan adapter->phy_interface = PHY_INTERFACE_MODE_GMII;
1488e86c7210SPavithra Sathyanarayanan else if ((id_rev == ID_REV_ID_LAN7431_) && (data & MAC_CR_MII_EN_))
1489e86c7210SPavithra Sathyanarayanan adapter->phy_interface = PHY_INTERFACE_MODE_MII;
1490e86c7210SPavithra Sathyanarayanan else
1491e86c7210SPavithra Sathyanarayanan adapter->phy_interface = PHY_INTERFACE_MODE_RGMII;
1492e86c7210SPavithra Sathyanarayanan }
1493e86c7210SPavithra Sathyanarayanan
lan743x_phy_open(struct lan743x_adapter * adapter)149423f0703cSBryan Whitehead static int lan743x_phy_open(struct lan743x_adapter *adapter)
149523f0703cSBryan Whitehead {
14967c3e2b77SSven Van Asbroeck struct net_device *netdev = adapter->netdev;
149723f0703cSBryan Whitehead struct lan743x_phy *phy = &adapter->phy;
1498624864fbSPavithra Sathyanarayanan struct fixed_phy_status fphy_status = {
1499624864fbSPavithra Sathyanarayanan .link = 1,
1500624864fbSPavithra Sathyanarayanan .speed = SPEED_1000,
1501624864fbSPavithra Sathyanarayanan .duplex = DUPLEX_FULL,
1502624864fbSPavithra Sathyanarayanan };
15037c3e2b77SSven Van Asbroeck struct phy_device *phydev;
150423f0703cSBryan Whitehead int ret = -EIO;
150523f0703cSBryan Whitehead
1506902a66e0SSven Van Asbroeck /* try devicetree phy, or fixed link */
15077c3e2b77SSven Van Asbroeck phydev = of_phy_get_and_connect(netdev, adapter->pdev->dev.of_node,
15087c3e2b77SSven Van Asbroeck lan743x_phy_link_status_change);
1509902a66e0SSven Van Asbroeck
1510902a66e0SSven Van Asbroeck if (!phydev) {
1511902a66e0SSven Van Asbroeck /* try internal phy */
151223f0703cSBryan Whitehead phydev = phy_find_first(adapter->mdiobus);
1513624864fbSPavithra Sathyanarayanan if (!phydev) {
1514624864fbSPavithra Sathyanarayanan if ((adapter->csr.id_rev & ID_REV_ID_MASK_) ==
1515624864fbSPavithra Sathyanarayanan ID_REV_ID_LAN7431_) {
1516624864fbSPavithra Sathyanarayanan phydev = fixed_phy_register(PHY_POLL,
1517624864fbSPavithra Sathyanarayanan &fphy_status, NULL);
1518624864fbSPavithra Sathyanarayanan if (IS_ERR(phydev)) {
1519624864fbSPavithra Sathyanarayanan netdev_err(netdev, "No PHY/fixed_PHY found\n");
1520294f48e9SRuan Jinjie return PTR_ERR(phydev);
1521624864fbSPavithra Sathyanarayanan }
1522624864fbSPavithra Sathyanarayanan } else {
152323f0703cSBryan Whitehead goto return_error;
1524624864fbSPavithra Sathyanarayanan }
1525624864fbSPavithra Sathyanarayanan }
152623f0703cSBryan Whitehead
1527e86c7210SPavithra Sathyanarayanan lan743x_phy_interface_select(adapter);
1528e86c7210SPavithra Sathyanarayanan
152979dfeb29SRaju Lakkaraju ret = phy_connect_direct(netdev, phydev,
153079dfeb29SRaju Lakkaraju lan743x_phy_link_status_change,
1531e86c7210SPavithra Sathyanarayanan adapter->phy_interface);
153223f0703cSBryan Whitehead if (ret)
153323f0703cSBryan Whitehead goto return_error;
15346f197fb6SRoelof Berg }
153523f0703cSBryan Whitehead
153623f0703cSBryan Whitehead /* MAC doesn't support 1000T Half */
153741124fa6SAndrew Lunn phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
153823f0703cSBryan Whitehead
153923f0703cSBryan Whitehead /* support both flow controls */
1540af8d9bb2SAndrew Lunn phy_support_asym_pause(phydev);
154123f0703cSBryan Whitehead phy->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX);
154223f0703cSBryan Whitehead phy->fc_autoneg = phydev->autoneg;
154323f0703cSBryan Whitehead
154423f0703cSBryan Whitehead phy_start(phydev);
154523f0703cSBryan Whitehead phy_start_aneg(phydev);
15467c3e2b77SSven Van Asbroeck phy_attached_info(phydev);
154723f0703cSBryan Whitehead return 0;
154823f0703cSBryan Whitehead
154923f0703cSBryan Whitehead return_error:
155023f0703cSBryan Whitehead return ret;
155123f0703cSBryan Whitehead }
155223f0703cSBryan Whitehead
lan743x_rfe_open(struct lan743x_adapter * adapter)155343e8fe9bSBryan Whitehead static void lan743x_rfe_open(struct lan743x_adapter *adapter)
155443e8fe9bSBryan Whitehead {
155543e8fe9bSBryan Whitehead lan743x_csr_write(adapter, RFE_RSS_CFG,
155643e8fe9bSBryan Whitehead RFE_RSS_CFG_UDP_IPV6_EX_ |
155743e8fe9bSBryan Whitehead RFE_RSS_CFG_TCP_IPV6_EX_ |
155843e8fe9bSBryan Whitehead RFE_RSS_CFG_IPV6_EX_ |
155943e8fe9bSBryan Whitehead RFE_RSS_CFG_UDP_IPV6_ |
156043e8fe9bSBryan Whitehead RFE_RSS_CFG_TCP_IPV6_ |
156143e8fe9bSBryan Whitehead RFE_RSS_CFG_IPV6_ |
156243e8fe9bSBryan Whitehead RFE_RSS_CFG_UDP_IPV4_ |
156343e8fe9bSBryan Whitehead RFE_RSS_CFG_TCP_IPV4_ |
156443e8fe9bSBryan Whitehead RFE_RSS_CFG_IPV4_ |
156543e8fe9bSBryan Whitehead RFE_RSS_CFG_VALID_HASH_BITS_ |
156643e8fe9bSBryan Whitehead RFE_RSS_CFG_RSS_QUEUE_ENABLE_ |
156743e8fe9bSBryan Whitehead RFE_RSS_CFG_RSS_HASH_STORE_ |
156843e8fe9bSBryan Whitehead RFE_RSS_CFG_RSS_ENABLE_);
156943e8fe9bSBryan Whitehead }
157043e8fe9bSBryan Whitehead
lan743x_rfe_update_mac_address(struct lan743x_adapter * adapter)157123f0703cSBryan Whitehead static void lan743x_rfe_update_mac_address(struct lan743x_adapter *adapter)
157223f0703cSBryan Whitehead {
157323f0703cSBryan Whitehead u8 *mac_addr;
157423f0703cSBryan Whitehead u32 mac_addr_hi = 0;
157523f0703cSBryan Whitehead u32 mac_addr_lo = 0;
157623f0703cSBryan Whitehead
157723f0703cSBryan Whitehead /* Add mac address to perfect Filter */
157823f0703cSBryan Whitehead mac_addr = adapter->mac_address;
157923f0703cSBryan Whitehead mac_addr_lo = ((((u32)(mac_addr[0])) << 0) |
158023f0703cSBryan Whitehead (((u32)(mac_addr[1])) << 8) |
158123f0703cSBryan Whitehead (((u32)(mac_addr[2])) << 16) |
158223f0703cSBryan Whitehead (((u32)(mac_addr[3])) << 24));
158323f0703cSBryan Whitehead mac_addr_hi = ((((u32)(mac_addr[4])) << 0) |
158423f0703cSBryan Whitehead (((u32)(mac_addr[5])) << 8));
158523f0703cSBryan Whitehead
158623f0703cSBryan Whitehead lan743x_csr_write(adapter, RFE_ADDR_FILT_LO(0), mac_addr_lo);
158723f0703cSBryan Whitehead lan743x_csr_write(adapter, RFE_ADDR_FILT_HI(0),
158823f0703cSBryan Whitehead mac_addr_hi | RFE_ADDR_FILT_HI_VALID_);
158923f0703cSBryan Whitehead }
159023f0703cSBryan Whitehead
lan743x_rfe_set_multicast(struct lan743x_adapter * adapter)159123f0703cSBryan Whitehead static void lan743x_rfe_set_multicast(struct lan743x_adapter *adapter)
159223f0703cSBryan Whitehead {
159323f0703cSBryan Whitehead struct net_device *netdev = adapter->netdev;
159423f0703cSBryan Whitehead u32 hash_table[DP_SEL_VHF_HASH_LEN];
159523f0703cSBryan Whitehead u32 rfctl;
159623f0703cSBryan Whitehead u32 data;
159723f0703cSBryan Whitehead
159823f0703cSBryan Whitehead rfctl = lan743x_csr_read(adapter, RFE_CTL);
159923f0703cSBryan Whitehead rfctl &= ~(RFE_CTL_AU_ | RFE_CTL_AM_ |
160023f0703cSBryan Whitehead RFE_CTL_DA_PERFECT_ | RFE_CTL_MCAST_HASH_);
160123f0703cSBryan Whitehead rfctl |= RFE_CTL_AB_;
160223f0703cSBryan Whitehead if (netdev->flags & IFF_PROMISC) {
160323f0703cSBryan Whitehead rfctl |= RFE_CTL_AM_ | RFE_CTL_AU_;
160423f0703cSBryan Whitehead } else {
160523f0703cSBryan Whitehead if (netdev->flags & IFF_ALLMULTI)
160623f0703cSBryan Whitehead rfctl |= RFE_CTL_AM_;
160723f0703cSBryan Whitehead }
160823f0703cSBryan Whitehead
1609cd691050SRaju Lakkaraju if (netdev->features & NETIF_F_RXCSUM)
1610cd691050SRaju Lakkaraju rfctl |= RFE_CTL_IP_COE_ | RFE_CTL_TCP_UDP_COE_;
1611cd691050SRaju Lakkaraju
161223f0703cSBryan Whitehead memset(hash_table, 0, DP_SEL_VHF_HASH_LEN * sizeof(u32));
161323f0703cSBryan Whitehead if (netdev_mc_count(netdev)) {
161423f0703cSBryan Whitehead struct netdev_hw_addr *ha;
161523f0703cSBryan Whitehead int i;
161623f0703cSBryan Whitehead
161723f0703cSBryan Whitehead rfctl |= RFE_CTL_DA_PERFECT_;
161823f0703cSBryan Whitehead i = 1;
161923f0703cSBryan Whitehead netdev_for_each_mc_addr(ha, netdev) {
162023f0703cSBryan Whitehead /* set first 32 into Perfect Filter */
162123f0703cSBryan Whitehead if (i < 33) {
162223f0703cSBryan Whitehead lan743x_csr_write(adapter,
162323f0703cSBryan Whitehead RFE_ADDR_FILT_HI(i), 0);
162423f0703cSBryan Whitehead data = ha->addr[3];
162523f0703cSBryan Whitehead data = ha->addr[2] | (data << 8);
162623f0703cSBryan Whitehead data = ha->addr[1] | (data << 8);
162723f0703cSBryan Whitehead data = ha->addr[0] | (data << 8);
162823f0703cSBryan Whitehead lan743x_csr_write(adapter,
162923f0703cSBryan Whitehead RFE_ADDR_FILT_LO(i), data);
163023f0703cSBryan Whitehead data = ha->addr[5];
163123f0703cSBryan Whitehead data = ha->addr[4] | (data << 8);
163223f0703cSBryan Whitehead data |= RFE_ADDR_FILT_HI_VALID_;
163323f0703cSBryan Whitehead lan743x_csr_write(adapter,
163423f0703cSBryan Whitehead RFE_ADDR_FILT_HI(i), data);
163523f0703cSBryan Whitehead } else {
163623f0703cSBryan Whitehead u32 bitnum = (ether_crc(ETH_ALEN, ha->addr) >>
163723f0703cSBryan Whitehead 23) & 0x1FF;
163823f0703cSBryan Whitehead hash_table[bitnum / 32] |= (1 << (bitnum % 32));
163923f0703cSBryan Whitehead rfctl |= RFE_CTL_MCAST_HASH_;
164023f0703cSBryan Whitehead }
164123f0703cSBryan Whitehead i++;
164223f0703cSBryan Whitehead }
164323f0703cSBryan Whitehead }
164423f0703cSBryan Whitehead
164523f0703cSBryan Whitehead lan743x_dp_write(adapter, DP_SEL_RFE_RAM,
164623f0703cSBryan Whitehead DP_SEL_VHF_VLAN_LEN,
164723f0703cSBryan Whitehead DP_SEL_VHF_HASH_LEN, hash_table);
164823f0703cSBryan Whitehead lan743x_csr_write(adapter, RFE_CTL, rfctl);
164923f0703cSBryan Whitehead }
165023f0703cSBryan Whitehead
lan743x_dmac_init(struct lan743x_adapter * adapter)165123f0703cSBryan Whitehead static int lan743x_dmac_init(struct lan743x_adapter *adapter)
165223f0703cSBryan Whitehead {
165323f0703cSBryan Whitehead u32 data = 0;
165423f0703cSBryan Whitehead
165523f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_CMD, DMAC_CMD_SWR_);
165623f0703cSBryan Whitehead lan743x_csr_wait_for_bit(adapter, DMAC_CMD, DMAC_CMD_SWR_,
165723f0703cSBryan Whitehead 0, 1000, 20000, 100);
165823f0703cSBryan Whitehead switch (DEFAULT_DMA_DESCRIPTOR_SPACING) {
165923f0703cSBryan Whitehead case DMA_DESCRIPTOR_SPACING_16:
166023f0703cSBryan Whitehead data = DMAC_CFG_MAX_DSPACE_16_;
166123f0703cSBryan Whitehead break;
166223f0703cSBryan Whitehead case DMA_DESCRIPTOR_SPACING_32:
166323f0703cSBryan Whitehead data = DMAC_CFG_MAX_DSPACE_32_;
166423f0703cSBryan Whitehead break;
166523f0703cSBryan Whitehead case DMA_DESCRIPTOR_SPACING_64:
166623f0703cSBryan Whitehead data = DMAC_CFG_MAX_DSPACE_64_;
166723f0703cSBryan Whitehead break;
166823f0703cSBryan Whitehead case DMA_DESCRIPTOR_SPACING_128:
166923f0703cSBryan Whitehead data = DMAC_CFG_MAX_DSPACE_128_;
167023f0703cSBryan Whitehead break;
167123f0703cSBryan Whitehead default:
167223f0703cSBryan Whitehead return -EPERM;
167323f0703cSBryan Whitehead }
167423f0703cSBryan Whitehead if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0))
167523f0703cSBryan Whitehead data |= DMAC_CFG_COAL_EN_;
167623f0703cSBryan Whitehead data |= DMAC_CFG_CH_ARB_SEL_RX_HIGH_;
167723f0703cSBryan Whitehead data |= DMAC_CFG_MAX_READ_REQ_SET_(6);
167823f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_CFG, data);
167923f0703cSBryan Whitehead data = DMAC_COAL_CFG_TIMER_LIMIT_SET_(1);
168023f0703cSBryan Whitehead data |= DMAC_COAL_CFG_TIMER_TX_START_;
168123f0703cSBryan Whitehead data |= DMAC_COAL_CFG_FLUSH_INTS_;
168223f0703cSBryan Whitehead data |= DMAC_COAL_CFG_INT_EXIT_COAL_;
168323f0703cSBryan Whitehead data |= DMAC_COAL_CFG_CSR_EXIT_COAL_;
168423f0703cSBryan Whitehead data |= DMAC_COAL_CFG_TX_THRES_SET_(0x0A);
168523f0703cSBryan Whitehead data |= DMAC_COAL_CFG_RX_THRES_SET_(0x0C);
168623f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_COAL_CFG, data);
168723f0703cSBryan Whitehead data = DMAC_OBFF_TX_THRES_SET_(0x08);
168823f0703cSBryan Whitehead data |= DMAC_OBFF_RX_THRES_SET_(0x0A);
168923f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_OBFF_CFG, data);
169023f0703cSBryan Whitehead return 0;
169123f0703cSBryan Whitehead }
169223f0703cSBryan Whitehead
lan743x_dmac_tx_get_state(struct lan743x_adapter * adapter,int tx_channel)169323f0703cSBryan Whitehead static int lan743x_dmac_tx_get_state(struct lan743x_adapter *adapter,
169423f0703cSBryan Whitehead int tx_channel)
169523f0703cSBryan Whitehead {
169623f0703cSBryan Whitehead u32 dmac_cmd = 0;
169723f0703cSBryan Whitehead
169823f0703cSBryan Whitehead dmac_cmd = lan743x_csr_read(adapter, DMAC_CMD);
169923f0703cSBryan Whitehead return DMAC_CHANNEL_STATE_SET((dmac_cmd &
170023f0703cSBryan Whitehead DMAC_CMD_START_T_(tx_channel)),
170123f0703cSBryan Whitehead (dmac_cmd &
170223f0703cSBryan Whitehead DMAC_CMD_STOP_T_(tx_channel)));
170323f0703cSBryan Whitehead }
170423f0703cSBryan Whitehead
lan743x_dmac_tx_wait_till_stopped(struct lan743x_adapter * adapter,int tx_channel)170523f0703cSBryan Whitehead static int lan743x_dmac_tx_wait_till_stopped(struct lan743x_adapter *adapter,
170623f0703cSBryan Whitehead int tx_channel)
170723f0703cSBryan Whitehead {
170823f0703cSBryan Whitehead int timeout = 100;
170923f0703cSBryan Whitehead int result = 0;
171023f0703cSBryan Whitehead
171123f0703cSBryan Whitehead while (timeout &&
171223f0703cSBryan Whitehead ((result = lan743x_dmac_tx_get_state(adapter, tx_channel)) ==
171323f0703cSBryan Whitehead DMAC_CHANNEL_STATE_STOP_PENDING)) {
171423f0703cSBryan Whitehead usleep_range(1000, 20000);
171523f0703cSBryan Whitehead timeout--;
171623f0703cSBryan Whitehead }
171723f0703cSBryan Whitehead if (result == DMAC_CHANNEL_STATE_STOP_PENDING)
171823f0703cSBryan Whitehead result = -ENODEV;
171923f0703cSBryan Whitehead return result;
172023f0703cSBryan Whitehead }
172123f0703cSBryan Whitehead
lan743x_dmac_rx_get_state(struct lan743x_adapter * adapter,int rx_channel)172223f0703cSBryan Whitehead static int lan743x_dmac_rx_get_state(struct lan743x_adapter *adapter,
172323f0703cSBryan Whitehead int rx_channel)
172423f0703cSBryan Whitehead {
172523f0703cSBryan Whitehead u32 dmac_cmd = 0;
172623f0703cSBryan Whitehead
172723f0703cSBryan Whitehead dmac_cmd = lan743x_csr_read(adapter, DMAC_CMD);
172823f0703cSBryan Whitehead return DMAC_CHANNEL_STATE_SET((dmac_cmd &
172923f0703cSBryan Whitehead DMAC_CMD_START_R_(rx_channel)),
173023f0703cSBryan Whitehead (dmac_cmd &
173123f0703cSBryan Whitehead DMAC_CMD_STOP_R_(rx_channel)));
173223f0703cSBryan Whitehead }
173323f0703cSBryan Whitehead
lan743x_dmac_rx_wait_till_stopped(struct lan743x_adapter * adapter,int rx_channel)173423f0703cSBryan Whitehead static int lan743x_dmac_rx_wait_till_stopped(struct lan743x_adapter *adapter,
173523f0703cSBryan Whitehead int rx_channel)
173623f0703cSBryan Whitehead {
173723f0703cSBryan Whitehead int timeout = 100;
173823f0703cSBryan Whitehead int result = 0;
173923f0703cSBryan Whitehead
174023f0703cSBryan Whitehead while (timeout &&
174123f0703cSBryan Whitehead ((result = lan743x_dmac_rx_get_state(adapter, rx_channel)) ==
174223f0703cSBryan Whitehead DMAC_CHANNEL_STATE_STOP_PENDING)) {
174323f0703cSBryan Whitehead usleep_range(1000, 20000);
174423f0703cSBryan Whitehead timeout--;
174523f0703cSBryan Whitehead }
174623f0703cSBryan Whitehead if (result == DMAC_CHANNEL_STATE_STOP_PENDING)
174723f0703cSBryan Whitehead result = -ENODEV;
174823f0703cSBryan Whitehead return result;
174923f0703cSBryan Whitehead }
175023f0703cSBryan Whitehead
lan743x_tx_release_desc(struct lan743x_tx * tx,int descriptor_index,bool cleanup)175123f0703cSBryan Whitehead static void lan743x_tx_release_desc(struct lan743x_tx *tx,
175223f0703cSBryan Whitehead int descriptor_index, bool cleanup)
175323f0703cSBryan Whitehead {
175423f0703cSBryan Whitehead struct lan743x_tx_buffer_info *buffer_info = NULL;
175523f0703cSBryan Whitehead struct lan743x_tx_descriptor *descriptor = NULL;
175623f0703cSBryan Whitehead u32 descriptor_type = 0;
175707624df1SBryan Whitehead bool ignore_sync;
175823f0703cSBryan Whitehead
175923f0703cSBryan Whitehead descriptor = &tx->ring_cpu_ptr[descriptor_index];
176023f0703cSBryan Whitehead buffer_info = &tx->buffer_info[descriptor_index];
176123f0703cSBryan Whitehead if (!(buffer_info->flags & TX_BUFFER_INFO_FLAG_ACTIVE))
176223f0703cSBryan Whitehead goto done;
176323f0703cSBryan Whitehead
176446251282SAlexey Denisov descriptor_type = le32_to_cpu(descriptor->data0) &
176523f0703cSBryan Whitehead TX_DESC_DATA0_DTYPE_MASK_;
176623f0703cSBryan Whitehead if (descriptor_type == TX_DESC_DATA0_DTYPE_DATA_)
176723f0703cSBryan Whitehead goto clean_up_data_descriptor;
176823f0703cSBryan Whitehead else
176923f0703cSBryan Whitehead goto clear_active;
177023f0703cSBryan Whitehead
177123f0703cSBryan Whitehead clean_up_data_descriptor:
177223f0703cSBryan Whitehead if (buffer_info->dma_ptr) {
177323f0703cSBryan Whitehead if (buffer_info->flags &
177423f0703cSBryan Whitehead TX_BUFFER_INFO_FLAG_SKB_FRAGMENT) {
177523f0703cSBryan Whitehead dma_unmap_page(&tx->adapter->pdev->dev,
177623f0703cSBryan Whitehead buffer_info->dma_ptr,
177723f0703cSBryan Whitehead buffer_info->buffer_length,
177823f0703cSBryan Whitehead DMA_TO_DEVICE);
177923f0703cSBryan Whitehead } else {
178023f0703cSBryan Whitehead dma_unmap_single(&tx->adapter->pdev->dev,
178123f0703cSBryan Whitehead buffer_info->dma_ptr,
178223f0703cSBryan Whitehead buffer_info->buffer_length,
178323f0703cSBryan Whitehead DMA_TO_DEVICE);
178423f0703cSBryan Whitehead }
178523f0703cSBryan Whitehead buffer_info->dma_ptr = 0;
178623f0703cSBryan Whitehead buffer_info->buffer_length = 0;
178723f0703cSBryan Whitehead }
178807624df1SBryan Whitehead if (!buffer_info->skb)
178907624df1SBryan Whitehead goto clear_active;
179007624df1SBryan Whitehead
179107624df1SBryan Whitehead if (!(buffer_info->flags & TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED)) {
1792e35df62eSSven Van Asbroeck dev_kfree_skb_any(buffer_info->skb);
179307624df1SBryan Whitehead goto clear_skb;
179423f0703cSBryan Whitehead }
179523f0703cSBryan Whitehead
179607624df1SBryan Whitehead if (cleanup) {
179707624df1SBryan Whitehead lan743x_ptp_unrequest_tx_timestamp(tx->adapter);
1798e35df62eSSven Van Asbroeck dev_kfree_skb_any(buffer_info->skb);
179907624df1SBryan Whitehead } else {
180007624df1SBryan Whitehead ignore_sync = (buffer_info->flags &
180107624df1SBryan Whitehead TX_BUFFER_INFO_FLAG_IGNORE_SYNC) != 0;
180207624df1SBryan Whitehead lan743x_ptp_tx_timestamp_skb(tx->adapter,
180307624df1SBryan Whitehead buffer_info->skb, ignore_sync);
180407624df1SBryan Whitehead }
180507624df1SBryan Whitehead
180607624df1SBryan Whitehead clear_skb:
180707624df1SBryan Whitehead buffer_info->skb = NULL;
180807624df1SBryan Whitehead
180923f0703cSBryan Whitehead clear_active:
181023f0703cSBryan Whitehead buffer_info->flags &= ~TX_BUFFER_INFO_FLAG_ACTIVE;
181123f0703cSBryan Whitehead
181223f0703cSBryan Whitehead done:
181323f0703cSBryan Whitehead memset(buffer_info, 0, sizeof(*buffer_info));
181423f0703cSBryan Whitehead memset(descriptor, 0, sizeof(*descriptor));
181523f0703cSBryan Whitehead }
181623f0703cSBryan Whitehead
lan743x_tx_next_index(struct lan743x_tx * tx,int index)181723f0703cSBryan Whitehead static int lan743x_tx_next_index(struct lan743x_tx *tx, int index)
181823f0703cSBryan Whitehead {
181923f0703cSBryan Whitehead return ((++index) % tx->ring_size);
182023f0703cSBryan Whitehead }
182123f0703cSBryan Whitehead
lan743x_tx_release_completed_descriptors(struct lan743x_tx * tx)182223f0703cSBryan Whitehead static void lan743x_tx_release_completed_descriptors(struct lan743x_tx *tx)
182323f0703cSBryan Whitehead {
182446251282SAlexey Denisov while (le32_to_cpu(*tx->head_cpu_ptr) != (tx->last_head)) {
182523f0703cSBryan Whitehead lan743x_tx_release_desc(tx, tx->last_head, false);
182623f0703cSBryan Whitehead tx->last_head = lan743x_tx_next_index(tx, tx->last_head);
182723f0703cSBryan Whitehead }
182823f0703cSBryan Whitehead }
182923f0703cSBryan Whitehead
lan743x_tx_release_all_descriptors(struct lan743x_tx * tx)183023f0703cSBryan Whitehead static void lan743x_tx_release_all_descriptors(struct lan743x_tx *tx)
183123f0703cSBryan Whitehead {
183223f0703cSBryan Whitehead u32 original_head = 0;
183323f0703cSBryan Whitehead
183423f0703cSBryan Whitehead original_head = tx->last_head;
183523f0703cSBryan Whitehead do {
183623f0703cSBryan Whitehead lan743x_tx_release_desc(tx, tx->last_head, true);
183723f0703cSBryan Whitehead tx->last_head = lan743x_tx_next_index(tx, tx->last_head);
183823f0703cSBryan Whitehead } while (tx->last_head != original_head);
183923f0703cSBryan Whitehead memset(tx->ring_cpu_ptr, 0,
184023f0703cSBryan Whitehead sizeof(*tx->ring_cpu_ptr) * (tx->ring_size));
184123f0703cSBryan Whitehead memset(tx->buffer_info, 0,
184223f0703cSBryan Whitehead sizeof(*tx->buffer_info) * (tx->ring_size));
184323f0703cSBryan Whitehead }
184423f0703cSBryan Whitehead
lan743x_tx_get_desc_cnt(struct lan743x_tx * tx,struct sk_buff * skb)184523f0703cSBryan Whitehead static int lan743x_tx_get_desc_cnt(struct lan743x_tx *tx,
184623f0703cSBryan Whitehead struct sk_buff *skb)
184723f0703cSBryan Whitehead {
184823f0703cSBryan Whitehead int result = 1; /* 1 for the main skb buffer */
184923f0703cSBryan Whitehead int nr_frags = 0;
185023f0703cSBryan Whitehead
185123f0703cSBryan Whitehead if (skb_is_gso(skb))
185223f0703cSBryan Whitehead result++; /* requires an extension descriptor */
185323f0703cSBryan Whitehead nr_frags = skb_shinfo(skb)->nr_frags;
185423f0703cSBryan Whitehead result += nr_frags; /* 1 for each fragment buffer */
185523f0703cSBryan Whitehead return result;
185623f0703cSBryan Whitehead }
185723f0703cSBryan Whitehead
lan743x_tx_get_avail_desc(struct lan743x_tx * tx)185823f0703cSBryan Whitehead static int lan743x_tx_get_avail_desc(struct lan743x_tx *tx)
185923f0703cSBryan Whitehead {
186023f0703cSBryan Whitehead int last_head = tx->last_head;
186123f0703cSBryan Whitehead int last_tail = tx->last_tail;
186223f0703cSBryan Whitehead
186323f0703cSBryan Whitehead if (last_tail >= last_head)
186423f0703cSBryan Whitehead return tx->ring_size - last_tail + last_head - 1;
186523f0703cSBryan Whitehead else
186623f0703cSBryan Whitehead return last_head - last_tail - 1;
186723f0703cSBryan Whitehead }
186823f0703cSBryan Whitehead
lan743x_tx_set_timestamping_mode(struct lan743x_tx * tx,bool enable_timestamping,bool enable_onestep_sync)186907624df1SBryan Whitehead void lan743x_tx_set_timestamping_mode(struct lan743x_tx *tx,
187007624df1SBryan Whitehead bool enable_timestamping,
187107624df1SBryan Whitehead bool enable_onestep_sync)
187207624df1SBryan Whitehead {
187307624df1SBryan Whitehead if (enable_timestamping)
187407624df1SBryan Whitehead tx->ts_flags |= TX_TS_FLAG_TIMESTAMPING_ENABLED;
187507624df1SBryan Whitehead else
187607624df1SBryan Whitehead tx->ts_flags &= ~TX_TS_FLAG_TIMESTAMPING_ENABLED;
187707624df1SBryan Whitehead if (enable_onestep_sync)
187807624df1SBryan Whitehead tx->ts_flags |= TX_TS_FLAG_ONE_STEP_SYNC;
187907624df1SBryan Whitehead else
188007624df1SBryan Whitehead tx->ts_flags &= ~TX_TS_FLAG_ONE_STEP_SYNC;
188107624df1SBryan Whitehead }
188207624df1SBryan 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)188323f0703cSBryan Whitehead static int lan743x_tx_frame_start(struct lan743x_tx *tx,
188423f0703cSBryan Whitehead unsigned char *first_buffer,
188523f0703cSBryan Whitehead unsigned int first_buffer_length,
188623f0703cSBryan Whitehead unsigned int frame_length,
188707624df1SBryan Whitehead bool time_stamp,
188823f0703cSBryan Whitehead bool check_sum)
188923f0703cSBryan Whitehead {
189023f0703cSBryan Whitehead /* called only from within lan743x_tx_xmit_frame.
189123f0703cSBryan Whitehead * assuming tx->ring_lock has already been acquired.
189223f0703cSBryan Whitehead */
189323f0703cSBryan Whitehead struct lan743x_tx_descriptor *tx_descriptor = NULL;
189423f0703cSBryan Whitehead struct lan743x_tx_buffer_info *buffer_info = NULL;
189523f0703cSBryan Whitehead struct lan743x_adapter *adapter = tx->adapter;
189623f0703cSBryan Whitehead struct device *dev = &adapter->pdev->dev;
189723f0703cSBryan Whitehead dma_addr_t dma_ptr;
189823f0703cSBryan Whitehead
189923f0703cSBryan Whitehead tx->frame_flags |= TX_FRAME_FLAG_IN_PROGRESS;
190023f0703cSBryan Whitehead tx->frame_first = tx->last_tail;
190123f0703cSBryan Whitehead tx->frame_tail = tx->frame_first;
190223f0703cSBryan Whitehead
190323f0703cSBryan Whitehead tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
190423f0703cSBryan Whitehead buffer_info = &tx->buffer_info[tx->frame_tail];
190523f0703cSBryan Whitehead dma_ptr = dma_map_single(dev, first_buffer, first_buffer_length,
190623f0703cSBryan Whitehead DMA_TO_DEVICE);
190723f0703cSBryan Whitehead if (dma_mapping_error(dev, dma_ptr))
190823f0703cSBryan Whitehead return -ENOMEM;
190923f0703cSBryan Whitehead
191046251282SAlexey Denisov tx_descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(dma_ptr));
191146251282SAlexey Denisov tx_descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(dma_ptr));
191246251282SAlexey Denisov tx_descriptor->data3 = cpu_to_le32((frame_length << 16) &
191346251282SAlexey Denisov TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_);
191423f0703cSBryan Whitehead
191523f0703cSBryan Whitehead buffer_info->skb = NULL;
191623f0703cSBryan Whitehead buffer_info->dma_ptr = dma_ptr;
191723f0703cSBryan Whitehead buffer_info->buffer_length = first_buffer_length;
191823f0703cSBryan Whitehead buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE;
191923f0703cSBryan Whitehead
192023f0703cSBryan Whitehead tx->frame_data0 = (first_buffer_length &
192123f0703cSBryan Whitehead TX_DESC_DATA0_BUF_LENGTH_MASK_) |
192223f0703cSBryan Whitehead TX_DESC_DATA0_DTYPE_DATA_ |
192323f0703cSBryan Whitehead TX_DESC_DATA0_FS_ |
192423f0703cSBryan Whitehead TX_DESC_DATA0_FCS_;
192507624df1SBryan Whitehead if (time_stamp)
192607624df1SBryan Whitehead tx->frame_data0 |= TX_DESC_DATA0_TSE_;
192723f0703cSBryan Whitehead
192823f0703cSBryan Whitehead if (check_sum)
192923f0703cSBryan Whitehead tx->frame_data0 |= TX_DESC_DATA0_ICE_ |
193023f0703cSBryan Whitehead TX_DESC_DATA0_IPE_ |
193123f0703cSBryan Whitehead TX_DESC_DATA0_TPE_;
193223f0703cSBryan Whitehead
193323f0703cSBryan Whitehead /* data0 will be programmed in one of other frame assembler functions */
193423f0703cSBryan Whitehead return 0;
193523f0703cSBryan Whitehead }
193623f0703cSBryan Whitehead
lan743x_tx_frame_add_lso(struct lan743x_tx * tx,unsigned int frame_length,int nr_frags)193723f0703cSBryan Whitehead static void lan743x_tx_frame_add_lso(struct lan743x_tx *tx,
193890490ef7SBryan Whitehead unsigned int frame_length,
193990490ef7SBryan Whitehead int nr_frags)
194023f0703cSBryan Whitehead {
194123f0703cSBryan Whitehead /* called only from within lan743x_tx_xmit_frame.
194223f0703cSBryan Whitehead * assuming tx->ring_lock has already been acquired.
194323f0703cSBryan Whitehead */
194423f0703cSBryan Whitehead struct lan743x_tx_descriptor *tx_descriptor = NULL;
194523f0703cSBryan Whitehead struct lan743x_tx_buffer_info *buffer_info = NULL;
194623f0703cSBryan Whitehead
194723f0703cSBryan Whitehead /* wrap up previous descriptor */
194823f0703cSBryan Whitehead tx->frame_data0 |= TX_DESC_DATA0_EXT_;
194990490ef7SBryan Whitehead if (nr_frags <= 0) {
195090490ef7SBryan Whitehead tx->frame_data0 |= TX_DESC_DATA0_LS_;
195190490ef7SBryan Whitehead tx->frame_data0 |= TX_DESC_DATA0_IOC_;
195290490ef7SBryan Whitehead }
195323f0703cSBryan Whitehead tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
195446251282SAlexey Denisov tx_descriptor->data0 = cpu_to_le32(tx->frame_data0);
195523f0703cSBryan Whitehead
195623f0703cSBryan Whitehead /* move to next descriptor */
195723f0703cSBryan Whitehead tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail);
195823f0703cSBryan Whitehead tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
195923f0703cSBryan Whitehead buffer_info = &tx->buffer_info[tx->frame_tail];
196023f0703cSBryan Whitehead
196123f0703cSBryan Whitehead /* add extension descriptor */
196223f0703cSBryan Whitehead tx_descriptor->data1 = 0;
196323f0703cSBryan Whitehead tx_descriptor->data2 = 0;
196423f0703cSBryan Whitehead tx_descriptor->data3 = 0;
196523f0703cSBryan Whitehead
196623f0703cSBryan Whitehead buffer_info->skb = NULL;
196723f0703cSBryan Whitehead buffer_info->dma_ptr = 0;
196823f0703cSBryan Whitehead buffer_info->buffer_length = 0;
196923f0703cSBryan Whitehead buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE;
197023f0703cSBryan Whitehead
197123f0703cSBryan Whitehead tx->frame_data0 = (frame_length & TX_DESC_DATA0_EXT_PAY_LENGTH_MASK_) |
197223f0703cSBryan Whitehead TX_DESC_DATA0_DTYPE_EXT_ |
197323f0703cSBryan Whitehead TX_DESC_DATA0_EXT_LSO_;
197423f0703cSBryan Whitehead
197523f0703cSBryan Whitehead /* data0 will be programmed in one of other frame assembler functions */
197623f0703cSBryan Whitehead }
197723f0703cSBryan Whitehead
lan743x_tx_frame_add_fragment(struct lan743x_tx * tx,const skb_frag_t * fragment,unsigned int frame_length)197823f0703cSBryan Whitehead static int lan743x_tx_frame_add_fragment(struct lan743x_tx *tx,
1979d7840976SMatthew Wilcox (Oracle) const skb_frag_t *fragment,
198023f0703cSBryan Whitehead unsigned int frame_length)
198123f0703cSBryan Whitehead {
198223f0703cSBryan Whitehead /* called only from within lan743x_tx_xmit_frame
198323f0703cSBryan Whitehead * assuming tx->ring_lock has already been acquired
198423f0703cSBryan Whitehead */
198523f0703cSBryan Whitehead struct lan743x_tx_descriptor *tx_descriptor = NULL;
198623f0703cSBryan Whitehead struct lan743x_tx_buffer_info *buffer_info = NULL;
198723f0703cSBryan Whitehead struct lan743x_adapter *adapter = tx->adapter;
198823f0703cSBryan Whitehead struct device *dev = &adapter->pdev->dev;
198923f0703cSBryan Whitehead unsigned int fragment_length = 0;
199023f0703cSBryan Whitehead dma_addr_t dma_ptr;
199123f0703cSBryan Whitehead
199223f0703cSBryan Whitehead fragment_length = skb_frag_size(fragment);
199323f0703cSBryan Whitehead if (!fragment_length)
199423f0703cSBryan Whitehead return 0;
199523f0703cSBryan Whitehead
199623f0703cSBryan Whitehead /* wrap up previous descriptor */
199723f0703cSBryan Whitehead tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
199846251282SAlexey Denisov tx_descriptor->data0 = cpu_to_le32(tx->frame_data0);
199923f0703cSBryan Whitehead
200023f0703cSBryan Whitehead /* move to next descriptor */
200123f0703cSBryan Whitehead tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail);
200223f0703cSBryan Whitehead tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
200323f0703cSBryan Whitehead buffer_info = &tx->buffer_info[tx->frame_tail];
200423f0703cSBryan Whitehead dma_ptr = skb_frag_dma_map(dev, fragment,
200523f0703cSBryan Whitehead 0, fragment_length,
200623f0703cSBryan Whitehead DMA_TO_DEVICE);
200723f0703cSBryan Whitehead if (dma_mapping_error(dev, dma_ptr)) {
200823f0703cSBryan Whitehead int desc_index;
200923f0703cSBryan Whitehead
201023f0703cSBryan Whitehead /* cleanup all previously setup descriptors */
201123f0703cSBryan Whitehead desc_index = tx->frame_first;
201223f0703cSBryan Whitehead while (desc_index != tx->frame_tail) {
201323f0703cSBryan Whitehead lan743x_tx_release_desc(tx, desc_index, true);
201423f0703cSBryan Whitehead desc_index = lan743x_tx_next_index(tx, desc_index);
201523f0703cSBryan Whitehead }
201623f0703cSBryan Whitehead dma_wmb();
201723f0703cSBryan Whitehead tx->frame_flags &= ~TX_FRAME_FLAG_IN_PROGRESS;
201823f0703cSBryan Whitehead tx->frame_first = 0;
201923f0703cSBryan Whitehead tx->frame_data0 = 0;
202023f0703cSBryan Whitehead tx->frame_tail = 0;
202123f0703cSBryan Whitehead return -ENOMEM;
202223f0703cSBryan Whitehead }
202323f0703cSBryan Whitehead
202446251282SAlexey Denisov tx_descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(dma_ptr));
202546251282SAlexey Denisov tx_descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(dma_ptr));
202646251282SAlexey Denisov tx_descriptor->data3 = cpu_to_le32((frame_length << 16) &
202746251282SAlexey Denisov TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_);
202823f0703cSBryan Whitehead
202923f0703cSBryan Whitehead buffer_info->skb = NULL;
203023f0703cSBryan Whitehead buffer_info->dma_ptr = dma_ptr;
203123f0703cSBryan Whitehead buffer_info->buffer_length = fragment_length;
203223f0703cSBryan Whitehead buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE;
203323f0703cSBryan Whitehead buffer_info->flags |= TX_BUFFER_INFO_FLAG_SKB_FRAGMENT;
203423f0703cSBryan Whitehead
203523f0703cSBryan Whitehead tx->frame_data0 = (fragment_length & TX_DESC_DATA0_BUF_LENGTH_MASK_) |
203623f0703cSBryan Whitehead TX_DESC_DATA0_DTYPE_DATA_ |
203723f0703cSBryan Whitehead TX_DESC_DATA0_FCS_;
203823f0703cSBryan Whitehead
203923f0703cSBryan Whitehead /* data0 will be programmed in one of other frame assembler functions */
204023f0703cSBryan Whitehead return 0;
204123f0703cSBryan Whitehead }
204223f0703cSBryan Whitehead
lan743x_tx_frame_end(struct lan743x_tx * tx,struct sk_buff * skb,bool time_stamp,bool ignore_sync)204323f0703cSBryan Whitehead static void lan743x_tx_frame_end(struct lan743x_tx *tx,
204423f0703cSBryan Whitehead struct sk_buff *skb,
204507624df1SBryan Whitehead bool time_stamp,
204623f0703cSBryan Whitehead bool ignore_sync)
204723f0703cSBryan Whitehead {
204823f0703cSBryan Whitehead /* called only from within lan743x_tx_xmit_frame
204923f0703cSBryan Whitehead * assuming tx->ring_lock has already been acquired
205023f0703cSBryan Whitehead */
205123f0703cSBryan Whitehead struct lan743x_tx_descriptor *tx_descriptor = NULL;
205223f0703cSBryan Whitehead struct lan743x_tx_buffer_info *buffer_info = NULL;
205323f0703cSBryan Whitehead struct lan743x_adapter *adapter = tx->adapter;
205423f0703cSBryan Whitehead u32 tx_tail_flags = 0;
205523f0703cSBryan Whitehead
205623f0703cSBryan Whitehead /* wrap up previous descriptor */
205790490ef7SBryan Whitehead if ((tx->frame_data0 & TX_DESC_DATA0_DTYPE_MASK_) ==
205890490ef7SBryan Whitehead TX_DESC_DATA0_DTYPE_DATA_) {
205923f0703cSBryan Whitehead tx->frame_data0 |= TX_DESC_DATA0_LS_;
206023f0703cSBryan Whitehead tx->frame_data0 |= TX_DESC_DATA0_IOC_;
206190490ef7SBryan Whitehead }
206223f0703cSBryan Whitehead
206323f0703cSBryan Whitehead tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
206423f0703cSBryan Whitehead buffer_info = &tx->buffer_info[tx->frame_tail];
206523f0703cSBryan Whitehead buffer_info->skb = skb;
206607624df1SBryan Whitehead if (time_stamp)
206707624df1SBryan Whitehead buffer_info->flags |= TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED;
206823f0703cSBryan Whitehead if (ignore_sync)
206923f0703cSBryan Whitehead buffer_info->flags |= TX_BUFFER_INFO_FLAG_IGNORE_SYNC;
207023f0703cSBryan Whitehead
207146251282SAlexey Denisov tx_descriptor->data0 = cpu_to_le32(tx->frame_data0);
207223f0703cSBryan Whitehead tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail);
207323f0703cSBryan Whitehead tx->last_tail = tx->frame_tail;
207423f0703cSBryan Whitehead
207523f0703cSBryan Whitehead dma_wmb();
207623f0703cSBryan Whitehead
207723f0703cSBryan Whitehead if (tx->vector_flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET)
207823f0703cSBryan Whitehead tx_tail_flags |= TX_TAIL_SET_TOP_INT_VEC_EN_;
207923f0703cSBryan Whitehead if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET)
208023f0703cSBryan Whitehead tx_tail_flags |= TX_TAIL_SET_DMAC_INT_EN_ |
208123f0703cSBryan Whitehead TX_TAIL_SET_TOP_INT_EN_;
208223f0703cSBryan Whitehead
208323f0703cSBryan Whitehead lan743x_csr_write(adapter, TX_TAIL(tx->channel_number),
208423f0703cSBryan Whitehead tx_tail_flags | tx->frame_tail);
208523f0703cSBryan Whitehead tx->frame_flags &= ~TX_FRAME_FLAG_IN_PROGRESS;
208623f0703cSBryan Whitehead }
208723f0703cSBryan Whitehead
lan743x_tx_xmit_frame(struct lan743x_tx * tx,struct sk_buff * skb)208823f0703cSBryan Whitehead static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
208923f0703cSBryan Whitehead struct sk_buff *skb)
209023f0703cSBryan Whitehead {
209123f0703cSBryan Whitehead int required_number_of_descriptors = 0;
209223f0703cSBryan Whitehead unsigned int start_frame_length = 0;
2093721f80c4SRaju Lakkaraju netdev_tx_t retval = NETDEV_TX_OK;
209423f0703cSBryan Whitehead unsigned int frame_length = 0;
209523f0703cSBryan Whitehead unsigned int head_length = 0;
209623f0703cSBryan Whitehead unsigned long irq_flags = 0;
209707624df1SBryan Whitehead bool do_timestamp = false;
209823f0703cSBryan Whitehead bool ignore_sync = false;
2099721f80c4SRaju Lakkaraju struct netdev_queue *txq;
210023f0703cSBryan Whitehead int nr_frags = 0;
210123f0703cSBryan Whitehead bool gso = false;
210223f0703cSBryan Whitehead int j;
210323f0703cSBryan Whitehead
210423f0703cSBryan Whitehead required_number_of_descriptors = lan743x_tx_get_desc_cnt(tx, skb);
210523f0703cSBryan Whitehead
210623f0703cSBryan Whitehead spin_lock_irqsave(&tx->ring_lock, irq_flags);
210723f0703cSBryan Whitehead if (required_number_of_descriptors >
210823f0703cSBryan Whitehead lan743x_tx_get_avail_desc(tx)) {
210923f0703cSBryan Whitehead if (required_number_of_descriptors > (tx->ring_size - 1)) {
2110e35df62eSSven Van Asbroeck dev_kfree_skb_irq(skb);
211123f0703cSBryan Whitehead } else {
2112721f80c4SRaju Lakkaraju /* save how many descriptors we needed to restart the queue */
2113721f80c4SRaju Lakkaraju tx->rqd_descriptors = required_number_of_descriptors;
2114721f80c4SRaju Lakkaraju retval = NETDEV_TX_BUSY;
2115721f80c4SRaju Lakkaraju txq = netdev_get_tx_queue(tx->adapter->netdev,
2116721f80c4SRaju Lakkaraju tx->channel_number);
2117721f80c4SRaju Lakkaraju netif_tx_stop_queue(txq);
211823f0703cSBryan Whitehead }
211923f0703cSBryan Whitehead goto unlock;
212023f0703cSBryan Whitehead }
212123f0703cSBryan Whitehead
212223f0703cSBryan Whitehead /* space available, transmit skb */
212307624df1SBryan Whitehead if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
212407624df1SBryan Whitehead (tx->ts_flags & TX_TS_FLAG_TIMESTAMPING_ENABLED) &&
212507624df1SBryan Whitehead (lan743x_ptp_request_tx_timestamp(tx->adapter))) {
212607624df1SBryan Whitehead skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
212707624df1SBryan Whitehead do_timestamp = true;
212807624df1SBryan Whitehead if (tx->ts_flags & TX_TS_FLAG_ONE_STEP_SYNC)
212907624df1SBryan Whitehead ignore_sync = true;
213007624df1SBryan Whitehead }
213123f0703cSBryan Whitehead head_length = skb_headlen(skb);
213223f0703cSBryan Whitehead frame_length = skb_pagelen(skb);
213323f0703cSBryan Whitehead nr_frags = skb_shinfo(skb)->nr_frags;
213423f0703cSBryan Whitehead start_frame_length = frame_length;
213523f0703cSBryan Whitehead gso = skb_is_gso(skb);
213623f0703cSBryan Whitehead if (gso) {
213723f0703cSBryan Whitehead start_frame_length = max(skb_shinfo(skb)->gso_size,
213823f0703cSBryan Whitehead (unsigned short)8);
213923f0703cSBryan Whitehead }
214023f0703cSBryan Whitehead
214123f0703cSBryan Whitehead if (lan743x_tx_frame_start(tx,
214223f0703cSBryan Whitehead skb->data, head_length,
214323f0703cSBryan Whitehead start_frame_length,
214407624df1SBryan Whitehead do_timestamp,
214523f0703cSBryan Whitehead skb->ip_summed == CHECKSUM_PARTIAL)) {
2146e35df62eSSven Van Asbroeck dev_kfree_skb_irq(skb);
214723f0703cSBryan Whitehead goto unlock;
214823f0703cSBryan Whitehead }
2149bc1962e5SRaju Lakkaraju tx->frame_count++;
215023f0703cSBryan Whitehead
215123f0703cSBryan Whitehead if (gso)
215290490ef7SBryan Whitehead lan743x_tx_frame_add_lso(tx, frame_length, nr_frags);
215323f0703cSBryan Whitehead
215423f0703cSBryan Whitehead if (nr_frags <= 0)
215523f0703cSBryan Whitehead goto finish;
215623f0703cSBryan Whitehead
215723f0703cSBryan Whitehead for (j = 0; j < nr_frags; j++) {
2158d7840976SMatthew Wilcox (Oracle) const skb_frag_t *frag = &(skb_shinfo(skb)->frags[j]);
215923f0703cSBryan Whitehead
216023f0703cSBryan Whitehead if (lan743x_tx_frame_add_fragment(tx, frag, frame_length)) {
216123f0703cSBryan Whitehead /* upon error no need to call
216223f0703cSBryan Whitehead * lan743x_tx_frame_end
216323f0703cSBryan Whitehead * frame assembler clean up was performed inside
216423f0703cSBryan Whitehead * lan743x_tx_frame_add_fragment
216523f0703cSBryan Whitehead */
2166e35df62eSSven Van Asbroeck dev_kfree_skb_irq(skb);
216723f0703cSBryan Whitehead goto unlock;
216823f0703cSBryan Whitehead }
216923f0703cSBryan Whitehead }
217023f0703cSBryan Whitehead
217123f0703cSBryan Whitehead finish:
217207624df1SBryan Whitehead lan743x_tx_frame_end(tx, skb, do_timestamp, ignore_sync);
217323f0703cSBryan Whitehead
217423f0703cSBryan Whitehead unlock:
217523f0703cSBryan Whitehead spin_unlock_irqrestore(&tx->ring_lock, irq_flags);
2176721f80c4SRaju Lakkaraju return retval;
217723f0703cSBryan Whitehead }
217823f0703cSBryan Whitehead
lan743x_tx_napi_poll(struct napi_struct * napi,int weight)217923f0703cSBryan Whitehead static int lan743x_tx_napi_poll(struct napi_struct *napi, int weight)
218023f0703cSBryan Whitehead {
218123f0703cSBryan Whitehead struct lan743x_tx *tx = container_of(napi, struct lan743x_tx, napi);
218223f0703cSBryan Whitehead struct lan743x_adapter *adapter = tx->adapter;
218323f0703cSBryan Whitehead unsigned long irq_flags = 0;
2184721f80c4SRaju Lakkaraju struct netdev_queue *txq;
218523f0703cSBryan Whitehead u32 ioc_bit = 0;
218623f0703cSBryan Whitehead
218723f0703cSBryan Whitehead ioc_bit = DMAC_INT_BIT_TX_IOC_(tx->channel_number);
21887c8c0291SJesse Brandeburg lan743x_csr_read(adapter, DMAC_INT_STS);
218923f0703cSBryan Whitehead if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C)
219023f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_INT_STS, ioc_bit);
219123f0703cSBryan Whitehead spin_lock_irqsave(&tx->ring_lock, irq_flags);
219223f0703cSBryan Whitehead
219323f0703cSBryan Whitehead /* clean up tx ring */
219423f0703cSBryan Whitehead lan743x_tx_release_completed_descriptors(tx);
2195721f80c4SRaju Lakkaraju txq = netdev_get_tx_queue(adapter->netdev, tx->channel_number);
2196721f80c4SRaju Lakkaraju if (netif_tx_queue_stopped(txq)) {
2197721f80c4SRaju Lakkaraju if (tx->rqd_descriptors) {
2198721f80c4SRaju Lakkaraju if (tx->rqd_descriptors <=
2199721f80c4SRaju Lakkaraju lan743x_tx_get_avail_desc(tx)) {
2200721f80c4SRaju Lakkaraju tx->rqd_descriptors = 0;
2201721f80c4SRaju Lakkaraju netif_tx_wake_queue(txq);
2202721f80c4SRaju Lakkaraju }
220323f0703cSBryan Whitehead } else {
2204721f80c4SRaju Lakkaraju netif_tx_wake_queue(txq);
220523f0703cSBryan Whitehead }
220623f0703cSBryan Whitehead }
220723f0703cSBryan Whitehead spin_unlock_irqrestore(&tx->ring_lock, irq_flags);
220823f0703cSBryan Whitehead
2209cc592205SBryan Whitehead if (!napi_complete(napi))
221023f0703cSBryan Whitehead goto done;
221123f0703cSBryan Whitehead
221223f0703cSBryan Whitehead /* enable isr */
221323f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET,
221423f0703cSBryan Whitehead INT_BIT_DMA_TX_(tx->channel_number));
221523f0703cSBryan Whitehead lan743x_csr_read(adapter, INT_STS);
221623f0703cSBryan Whitehead
221723f0703cSBryan Whitehead done:
2218cc592205SBryan Whitehead return 0;
221923f0703cSBryan Whitehead }
222023f0703cSBryan Whitehead
lan743x_tx_ring_cleanup(struct lan743x_tx * tx)222123f0703cSBryan Whitehead static void lan743x_tx_ring_cleanup(struct lan743x_tx *tx)
222223f0703cSBryan Whitehead {
222323f0703cSBryan Whitehead if (tx->head_cpu_ptr) {
2224a3b7b493SChristophe JAILLET dma_free_coherent(&tx->adapter->pdev->dev,
2225a3b7b493SChristophe JAILLET sizeof(*tx->head_cpu_ptr), tx->head_cpu_ptr,
222623f0703cSBryan Whitehead tx->head_dma_ptr);
222723f0703cSBryan Whitehead tx->head_cpu_ptr = NULL;
222823f0703cSBryan Whitehead tx->head_dma_ptr = 0;
222923f0703cSBryan Whitehead }
223023f0703cSBryan Whitehead kfree(tx->buffer_info);
223123f0703cSBryan Whitehead tx->buffer_info = NULL;
223223f0703cSBryan Whitehead
223323f0703cSBryan Whitehead if (tx->ring_cpu_ptr) {
2234a3b7b493SChristophe JAILLET dma_free_coherent(&tx->adapter->pdev->dev,
2235a3b7b493SChristophe JAILLET tx->ring_allocation_size, tx->ring_cpu_ptr,
223623f0703cSBryan Whitehead tx->ring_dma_ptr);
223723f0703cSBryan Whitehead tx->ring_allocation_size = 0;
223823f0703cSBryan Whitehead tx->ring_cpu_ptr = NULL;
223923f0703cSBryan Whitehead tx->ring_dma_ptr = 0;
224023f0703cSBryan Whitehead }
224123f0703cSBryan Whitehead tx->ring_size = 0;
224223f0703cSBryan Whitehead }
224323f0703cSBryan Whitehead
lan743x_tx_ring_init(struct lan743x_tx * tx)224423f0703cSBryan Whitehead static int lan743x_tx_ring_init(struct lan743x_tx *tx)
224523f0703cSBryan Whitehead {
224623f0703cSBryan Whitehead size_t ring_allocation_size = 0;
224723f0703cSBryan Whitehead void *cpu_ptr = NULL;
224823f0703cSBryan Whitehead dma_addr_t dma_ptr;
224923f0703cSBryan Whitehead int ret = -ENOMEM;
225023f0703cSBryan Whitehead
225123f0703cSBryan Whitehead tx->ring_size = LAN743X_TX_RING_SIZE;
225223f0703cSBryan Whitehead if (tx->ring_size & ~TX_CFG_B_TX_RING_LEN_MASK_) {
225323f0703cSBryan Whitehead ret = -EINVAL;
225423f0703cSBryan Whitehead goto cleanup;
225523f0703cSBryan Whitehead }
225695a359c9SYuiko Oshino if (dma_set_mask_and_coherent(&tx->adapter->pdev->dev,
225795a359c9SYuiko Oshino DMA_BIT_MASK(64))) {
225895a359c9SYuiko Oshino dev_warn(&tx->adapter->pdev->dev,
225995a359c9SYuiko Oshino "lan743x_: No suitable DMA available\n");
226095a359c9SYuiko Oshino ret = -ENOMEM;
226195a359c9SYuiko Oshino goto cleanup;
226295a359c9SYuiko Oshino }
226323f0703cSBryan Whitehead ring_allocation_size = ALIGN(tx->ring_size *
226423f0703cSBryan Whitehead sizeof(struct lan743x_tx_descriptor),
226523f0703cSBryan Whitehead PAGE_SIZE);
226623f0703cSBryan Whitehead dma_ptr = 0;
2267a3b7b493SChristophe JAILLET cpu_ptr = dma_alloc_coherent(&tx->adapter->pdev->dev,
2268a3b7b493SChristophe JAILLET ring_allocation_size, &dma_ptr, GFP_KERNEL);
226923f0703cSBryan Whitehead if (!cpu_ptr) {
227023f0703cSBryan Whitehead ret = -ENOMEM;
227123f0703cSBryan Whitehead goto cleanup;
227223f0703cSBryan Whitehead }
227323f0703cSBryan Whitehead
227423f0703cSBryan Whitehead tx->ring_allocation_size = ring_allocation_size;
227523f0703cSBryan Whitehead tx->ring_cpu_ptr = (struct lan743x_tx_descriptor *)cpu_ptr;
227623f0703cSBryan Whitehead tx->ring_dma_ptr = dma_ptr;
227723f0703cSBryan Whitehead
227823f0703cSBryan Whitehead cpu_ptr = kcalloc(tx->ring_size, sizeof(*tx->buffer_info), GFP_KERNEL);
227923f0703cSBryan Whitehead if (!cpu_ptr) {
228023f0703cSBryan Whitehead ret = -ENOMEM;
228123f0703cSBryan Whitehead goto cleanup;
228223f0703cSBryan Whitehead }
228323f0703cSBryan Whitehead tx->buffer_info = (struct lan743x_tx_buffer_info *)cpu_ptr;
228423f0703cSBryan Whitehead dma_ptr = 0;
2285a3b7b493SChristophe JAILLET cpu_ptr = dma_alloc_coherent(&tx->adapter->pdev->dev,
2286a3b7b493SChristophe JAILLET sizeof(*tx->head_cpu_ptr), &dma_ptr,
2287a3b7b493SChristophe JAILLET GFP_KERNEL);
228823f0703cSBryan Whitehead if (!cpu_ptr) {
228923f0703cSBryan Whitehead ret = -ENOMEM;
229023f0703cSBryan Whitehead goto cleanup;
229123f0703cSBryan Whitehead }
229223f0703cSBryan Whitehead
229323f0703cSBryan Whitehead tx->head_cpu_ptr = cpu_ptr;
229423f0703cSBryan Whitehead tx->head_dma_ptr = dma_ptr;
229523f0703cSBryan Whitehead if (tx->head_dma_ptr & 0x3) {
229623f0703cSBryan Whitehead ret = -ENOMEM;
229723f0703cSBryan Whitehead goto cleanup;
229823f0703cSBryan Whitehead }
229923f0703cSBryan Whitehead
230023f0703cSBryan Whitehead return 0;
230123f0703cSBryan Whitehead
230223f0703cSBryan Whitehead cleanup:
230323f0703cSBryan Whitehead lan743x_tx_ring_cleanup(tx);
230423f0703cSBryan Whitehead return ret;
230523f0703cSBryan Whitehead }
230623f0703cSBryan Whitehead
lan743x_tx_close(struct lan743x_tx * tx)230723f0703cSBryan Whitehead static void lan743x_tx_close(struct lan743x_tx *tx)
230823f0703cSBryan Whitehead {
230923f0703cSBryan Whitehead struct lan743x_adapter *adapter = tx->adapter;
231023f0703cSBryan Whitehead
231123f0703cSBryan Whitehead lan743x_csr_write(adapter,
231223f0703cSBryan Whitehead DMAC_CMD,
231323f0703cSBryan Whitehead DMAC_CMD_STOP_T_(tx->channel_number));
231423f0703cSBryan Whitehead lan743x_dmac_tx_wait_till_stopped(adapter, tx->channel_number);
231523f0703cSBryan Whitehead
231623f0703cSBryan Whitehead lan743x_csr_write(adapter,
231723f0703cSBryan Whitehead DMAC_INT_EN_CLR,
231823f0703cSBryan Whitehead DMAC_INT_BIT_TX_IOC_(tx->channel_number));
231923f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR,
232023f0703cSBryan Whitehead INT_BIT_DMA_TX_(tx->channel_number));
232123f0703cSBryan Whitehead napi_disable(&tx->napi);
232223f0703cSBryan Whitehead netif_napi_del(&tx->napi);
232323f0703cSBryan Whitehead
232423f0703cSBryan Whitehead lan743x_csr_write(adapter, FCT_TX_CTL,
232523f0703cSBryan Whitehead FCT_TX_CTL_DIS_(tx->channel_number));
232623f0703cSBryan Whitehead lan743x_csr_wait_for_bit(adapter, FCT_TX_CTL,
232723f0703cSBryan Whitehead FCT_TX_CTL_EN_(tx->channel_number),
232823f0703cSBryan Whitehead 0, 1000, 20000, 100);
232923f0703cSBryan Whitehead
233023f0703cSBryan Whitehead lan743x_tx_release_all_descriptors(tx);
233123f0703cSBryan Whitehead
2332721f80c4SRaju Lakkaraju tx->rqd_descriptors = 0;
233323f0703cSBryan Whitehead
233423f0703cSBryan Whitehead lan743x_tx_ring_cleanup(tx);
233523f0703cSBryan Whitehead }
233623f0703cSBryan Whitehead
lan743x_tx_open(struct lan743x_tx * tx)233723f0703cSBryan Whitehead static int lan743x_tx_open(struct lan743x_tx *tx)
233823f0703cSBryan Whitehead {
233923f0703cSBryan Whitehead struct lan743x_adapter *adapter = NULL;
234023f0703cSBryan Whitehead u32 data = 0;
234123f0703cSBryan Whitehead int ret;
234223f0703cSBryan Whitehead
234323f0703cSBryan Whitehead adapter = tx->adapter;
234423f0703cSBryan Whitehead ret = lan743x_tx_ring_init(tx);
234523f0703cSBryan Whitehead if (ret)
234623f0703cSBryan Whitehead return ret;
234723f0703cSBryan Whitehead
234823f0703cSBryan Whitehead /* initialize fifo */
234923f0703cSBryan Whitehead lan743x_csr_write(adapter, FCT_TX_CTL,
235023f0703cSBryan Whitehead FCT_TX_CTL_RESET_(tx->channel_number));
235123f0703cSBryan Whitehead lan743x_csr_wait_for_bit(adapter, FCT_TX_CTL,
235223f0703cSBryan Whitehead FCT_TX_CTL_RESET_(tx->channel_number),
235323f0703cSBryan Whitehead 0, 1000, 20000, 100);
235423f0703cSBryan Whitehead
235523f0703cSBryan Whitehead /* enable fifo */
235623f0703cSBryan Whitehead lan743x_csr_write(adapter, FCT_TX_CTL,
235723f0703cSBryan Whitehead FCT_TX_CTL_EN_(tx->channel_number));
235823f0703cSBryan Whitehead
235923f0703cSBryan Whitehead /* reset tx channel */
236023f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_CMD,
236123f0703cSBryan Whitehead DMAC_CMD_TX_SWR_(tx->channel_number));
236223f0703cSBryan Whitehead lan743x_csr_wait_for_bit(adapter, DMAC_CMD,
236323f0703cSBryan Whitehead DMAC_CMD_TX_SWR_(tx->channel_number),
236423f0703cSBryan Whitehead 0, 1000, 20000, 100);
236523f0703cSBryan Whitehead
236623f0703cSBryan Whitehead /* Write TX_BASE_ADDR */
236723f0703cSBryan Whitehead lan743x_csr_write(adapter,
236823f0703cSBryan Whitehead TX_BASE_ADDRH(tx->channel_number),
236923f0703cSBryan Whitehead DMA_ADDR_HIGH32(tx->ring_dma_ptr));
237023f0703cSBryan Whitehead lan743x_csr_write(adapter,
237123f0703cSBryan Whitehead TX_BASE_ADDRL(tx->channel_number),
237223f0703cSBryan Whitehead DMA_ADDR_LOW32(tx->ring_dma_ptr));
237323f0703cSBryan Whitehead
237423f0703cSBryan Whitehead /* Write TX_CFG_B */
237523f0703cSBryan Whitehead data = lan743x_csr_read(adapter, TX_CFG_B(tx->channel_number));
237623f0703cSBryan Whitehead data &= ~TX_CFG_B_TX_RING_LEN_MASK_;
237723f0703cSBryan Whitehead data |= ((tx->ring_size) & TX_CFG_B_TX_RING_LEN_MASK_);
237823f0703cSBryan Whitehead if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0))
237923f0703cSBryan Whitehead data |= TX_CFG_B_TDMABL_512_;
238023f0703cSBryan Whitehead lan743x_csr_write(adapter, TX_CFG_B(tx->channel_number), data);
238123f0703cSBryan Whitehead
238223f0703cSBryan Whitehead /* Write TX_CFG_A */
238323f0703cSBryan Whitehead data = TX_CFG_A_TX_TMR_HPWB_SEL_IOC_ | TX_CFG_A_TX_HP_WB_EN_;
238423f0703cSBryan Whitehead if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) {
238523f0703cSBryan Whitehead data |= TX_CFG_A_TX_HP_WB_ON_INT_TMR_;
238623f0703cSBryan Whitehead data |= TX_CFG_A_TX_PF_THRES_SET_(0x10);
238723f0703cSBryan Whitehead data |= TX_CFG_A_TX_PF_PRI_THRES_SET_(0x04);
238823f0703cSBryan Whitehead data |= TX_CFG_A_TX_HP_WB_THRES_SET_(0x07);
238923f0703cSBryan Whitehead }
239023f0703cSBryan Whitehead lan743x_csr_write(adapter, TX_CFG_A(tx->channel_number), data);
239123f0703cSBryan Whitehead
239223f0703cSBryan Whitehead /* Write TX_HEAD_WRITEBACK_ADDR */
239323f0703cSBryan Whitehead lan743x_csr_write(adapter,
239423f0703cSBryan Whitehead TX_HEAD_WRITEBACK_ADDRH(tx->channel_number),
239523f0703cSBryan Whitehead DMA_ADDR_HIGH32(tx->head_dma_ptr));
239623f0703cSBryan Whitehead lan743x_csr_write(adapter,
239723f0703cSBryan Whitehead TX_HEAD_WRITEBACK_ADDRL(tx->channel_number),
239823f0703cSBryan Whitehead DMA_ADDR_LOW32(tx->head_dma_ptr));
239923f0703cSBryan Whitehead
240023f0703cSBryan Whitehead /* set last head */
240123f0703cSBryan Whitehead tx->last_head = lan743x_csr_read(adapter, TX_HEAD(tx->channel_number));
240223f0703cSBryan Whitehead
240323f0703cSBryan Whitehead /* write TX_TAIL */
240423f0703cSBryan Whitehead tx->last_tail = 0;
240523f0703cSBryan Whitehead lan743x_csr_write(adapter, TX_TAIL(tx->channel_number),
240623f0703cSBryan Whitehead (u32)(tx->last_tail));
240723f0703cSBryan Whitehead tx->vector_flags = lan743x_intr_get_vector_flags(adapter,
240823f0703cSBryan Whitehead INT_BIT_DMA_TX_
240923f0703cSBryan Whitehead (tx->channel_number));
24108d602e1aSJakub Kicinski netif_napi_add_tx_weight(adapter->netdev,
241123f0703cSBryan Whitehead &tx->napi, lan743x_tx_napi_poll,
2412721f80c4SRaju Lakkaraju NAPI_POLL_WEIGHT);
241323f0703cSBryan Whitehead napi_enable(&tx->napi);
241423f0703cSBryan Whitehead
241523f0703cSBryan Whitehead data = 0;
241623f0703cSBryan Whitehead if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR)
241723f0703cSBryan Whitehead data |= TX_CFG_C_TX_TOP_INT_EN_AUTO_CLR_;
241823f0703cSBryan Whitehead if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR)
241923f0703cSBryan Whitehead data |= TX_CFG_C_TX_DMA_INT_STS_AUTO_CLR_;
242023f0703cSBryan Whitehead if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C)
242123f0703cSBryan Whitehead data |= TX_CFG_C_TX_INT_STS_R2C_MODE_MASK_;
242223f0703cSBryan Whitehead if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C)
242323f0703cSBryan Whitehead data |= TX_CFG_C_TX_INT_EN_R2C_;
242423f0703cSBryan Whitehead lan743x_csr_write(adapter, TX_CFG_C(tx->channel_number), data);
242523f0703cSBryan Whitehead
242623f0703cSBryan Whitehead if (!(tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET))
242723f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET,
242823f0703cSBryan Whitehead INT_BIT_DMA_TX_(tx->channel_number));
242923f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_INT_EN_SET,
243023f0703cSBryan Whitehead DMAC_INT_BIT_TX_IOC_(tx->channel_number));
243123f0703cSBryan Whitehead
243223f0703cSBryan Whitehead /* start dmac channel */
243323f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_CMD,
243423f0703cSBryan Whitehead DMAC_CMD_START_T_(tx->channel_number));
243523f0703cSBryan Whitehead return 0;
243623f0703cSBryan Whitehead }
243723f0703cSBryan Whitehead
lan743x_rx_next_index(struct lan743x_rx * rx,int index)243823f0703cSBryan Whitehead static int lan743x_rx_next_index(struct lan743x_rx *rx, int index)
243923f0703cSBryan Whitehead {
244023f0703cSBryan Whitehead return ((++index) % rx->ring_size);
244123f0703cSBryan Whitehead }
244223f0703cSBryan Whitehead
lan743x_rx_update_tail(struct lan743x_rx * rx,int index)244357030a0bSSven Van Asbroeck static void lan743x_rx_update_tail(struct lan743x_rx *rx, int index)
244457030a0bSSven Van Asbroeck {
244557030a0bSSven Van Asbroeck /* update the tail once per 8 descriptors */
244657030a0bSSven Van Asbroeck if ((index & 7) == 7)
244757030a0bSSven Van Asbroeck lan743x_csr_write(rx->adapter, RX_TAIL(rx->channel_number),
244857030a0bSSven Van Asbroeck index);
244957030a0bSSven Van Asbroeck }
245057030a0bSSven Van Asbroeck
lan743x_rx_init_ring_element(struct lan743x_rx * rx,int index,gfp_t gfp)2451e8684db1SYuiko Oshino static int lan743x_rx_init_ring_element(struct lan743x_rx *rx, int index,
2452e8684db1SYuiko Oshino gfp_t gfp)
245323f0703cSBryan Whitehead {
2454a8db76d4SSven Van Asbroeck struct net_device *netdev = rx->adapter->netdev;
2455a8db76d4SSven Van Asbroeck struct device *dev = &rx->adapter->pdev->dev;
245623f0703cSBryan Whitehead struct lan743x_rx_buffer_info *buffer_info;
2457966df6deSSven Van Asbroeck unsigned int buffer_length, used_length;
245823f0703cSBryan Whitehead struct lan743x_rx_descriptor *descriptor;
2459a8db76d4SSven Van Asbroeck struct sk_buff *skb;
2460a8db76d4SSven Van Asbroeck dma_addr_t dma_ptr;
246123f0703cSBryan Whitehead
24623bc41d6dSSven Van Asbroeck buffer_length = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + RX_HEAD_PADDING;
2463a8db76d4SSven Van Asbroeck
246423f0703cSBryan Whitehead descriptor = &rx->ring_cpu_ptr[index];
246523f0703cSBryan Whitehead buffer_info = &rx->buffer_info[index];
2466e8684db1SYuiko Oshino skb = __netdev_alloc_skb(netdev, buffer_length, gfp);
2467a8db76d4SSven Van Asbroeck if (!skb)
246823f0703cSBryan Whitehead return -ENOMEM;
2469966df6deSSven Van Asbroeck dma_ptr = dma_map_single(dev, skb->data, buffer_length, DMA_FROM_DEVICE);
2470a8db76d4SSven Van Asbroeck if (dma_mapping_error(dev, dma_ptr)) {
2471a8db76d4SSven Van Asbroeck dev_kfree_skb_any(skb);
247223f0703cSBryan Whitehead return -ENOMEM;
247323f0703cSBryan Whitehead }
2474966df6deSSven Van Asbroeck if (buffer_info->dma_ptr) {
2475966df6deSSven Van Asbroeck /* sync used area of buffer only */
2476966df6deSSven Van Asbroeck if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_LS_)
2477966df6deSSven Van Asbroeck /* frame length is valid only if LS bit is set.
2478966df6deSSven Van Asbroeck * it's a safe upper bound for the used area in this
2479966df6deSSven Van Asbroeck * buffer.
2480966df6deSSven Van Asbroeck */
2481966df6deSSven Van Asbroeck used_length = min(RX_DESC_DATA0_FRAME_LENGTH_GET_
2482966df6deSSven Van Asbroeck (le32_to_cpu(descriptor->data0)),
2483966df6deSSven Van Asbroeck buffer_info->buffer_length);
2484966df6deSSven Van Asbroeck else
2485966df6deSSven Van Asbroeck used_length = buffer_info->buffer_length;
2486966df6deSSven Van Asbroeck dma_sync_single_for_cpu(dev, buffer_info->dma_ptr,
2487966df6deSSven Van Asbroeck used_length,
2488966df6deSSven Van Asbroeck DMA_FROM_DEVICE);
2489966df6deSSven Van Asbroeck dma_unmap_single_attrs(dev, buffer_info->dma_ptr,
2490966df6deSSven Van Asbroeck buffer_info->buffer_length,
2491966df6deSSven Van Asbroeck DMA_FROM_DEVICE,
2492966df6deSSven Van Asbroeck DMA_ATTR_SKIP_CPU_SYNC);
2493966df6deSSven Van Asbroeck }
249423f0703cSBryan Whitehead
2495a8db76d4SSven Van Asbroeck buffer_info->skb = skb;
2496a8db76d4SSven Van Asbroeck buffer_info->dma_ptr = dma_ptr;
2497966df6deSSven Van Asbroeck buffer_info->buffer_length = buffer_length;
249846251282SAlexey Denisov descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(buffer_info->dma_ptr));
249946251282SAlexey Denisov descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(buffer_info->dma_ptr));
250023f0703cSBryan Whitehead descriptor->data3 = 0;
250146251282SAlexey Denisov descriptor->data0 = cpu_to_le32((RX_DESC_DATA0_OWN_ |
2502966df6deSSven Van Asbroeck (buffer_length & RX_DESC_DATA0_BUF_LENGTH_MASK_)));
250357030a0bSSven Van Asbroeck lan743x_rx_update_tail(rx, index);
250423f0703cSBryan Whitehead
250523f0703cSBryan Whitehead return 0;
250623f0703cSBryan Whitehead }
250723f0703cSBryan Whitehead
lan743x_rx_reuse_ring_element(struct lan743x_rx * rx,int index)250823f0703cSBryan Whitehead static void lan743x_rx_reuse_ring_element(struct lan743x_rx *rx, int index)
250923f0703cSBryan Whitehead {
251023f0703cSBryan Whitehead struct lan743x_rx_buffer_info *buffer_info;
251123f0703cSBryan Whitehead struct lan743x_rx_descriptor *descriptor;
251223f0703cSBryan Whitehead
251323f0703cSBryan Whitehead descriptor = &rx->ring_cpu_ptr[index];
251423f0703cSBryan Whitehead buffer_info = &rx->buffer_info[index];
251523f0703cSBryan Whitehead
251646251282SAlexey Denisov descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(buffer_info->dma_ptr));
251746251282SAlexey Denisov descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(buffer_info->dma_ptr));
251823f0703cSBryan Whitehead descriptor->data3 = 0;
251946251282SAlexey Denisov descriptor->data0 = cpu_to_le32((RX_DESC_DATA0_OWN_ |
252023f0703cSBryan Whitehead ((buffer_info->buffer_length) &
252146251282SAlexey Denisov RX_DESC_DATA0_BUF_LENGTH_MASK_)));
252257030a0bSSven Van Asbroeck lan743x_rx_update_tail(rx, index);
252323f0703cSBryan Whitehead }
252423f0703cSBryan Whitehead
lan743x_rx_release_ring_element(struct lan743x_rx * rx,int index)252523f0703cSBryan Whitehead static void lan743x_rx_release_ring_element(struct lan743x_rx *rx, int index)
252623f0703cSBryan Whitehead {
252723f0703cSBryan Whitehead struct lan743x_rx_buffer_info *buffer_info;
252823f0703cSBryan Whitehead struct lan743x_rx_descriptor *descriptor;
252923f0703cSBryan Whitehead
253023f0703cSBryan Whitehead descriptor = &rx->ring_cpu_ptr[index];
253123f0703cSBryan Whitehead buffer_info = &rx->buffer_info[index];
253223f0703cSBryan Whitehead
253323f0703cSBryan Whitehead memset(descriptor, 0, sizeof(*descriptor));
253423f0703cSBryan Whitehead
253523f0703cSBryan Whitehead if (buffer_info->dma_ptr) {
253623f0703cSBryan Whitehead dma_unmap_single(&rx->adapter->pdev->dev,
253723f0703cSBryan Whitehead buffer_info->dma_ptr,
253823f0703cSBryan Whitehead buffer_info->buffer_length,
253923f0703cSBryan Whitehead DMA_FROM_DEVICE);
254023f0703cSBryan Whitehead buffer_info->dma_ptr = 0;
254123f0703cSBryan Whitehead }
254223f0703cSBryan Whitehead
254323f0703cSBryan Whitehead if (buffer_info->skb) {
254423f0703cSBryan Whitehead dev_kfree_skb(buffer_info->skb);
254523f0703cSBryan Whitehead buffer_info->skb = NULL;
254623f0703cSBryan Whitehead }
254723f0703cSBryan Whitehead
254823f0703cSBryan Whitehead memset(buffer_info, 0, sizeof(*buffer_info));
254923f0703cSBryan Whitehead }
255023f0703cSBryan Whitehead
2551a8db76d4SSven Van Asbroeck static struct sk_buff *
lan743x_rx_trim_skb(struct sk_buff * skb,int frame_length)2552a8db76d4SSven Van Asbroeck lan743x_rx_trim_skb(struct sk_buff *skb, int frame_length)
255323f0703cSBryan Whitehead {
2554a8db76d4SSven Van Asbroeck if (skb_linearize(skb)) {
2555a8db76d4SSven Van Asbroeck dev_kfree_skb_irq(skb);
2556a8db76d4SSven Van Asbroeck return NULL;
2557a8db76d4SSven Van Asbroeck }
25583bc41d6dSSven Van Asbroeck frame_length = max_t(int, 0, frame_length - ETH_FCS_LEN);
2559a8db76d4SSven Van Asbroeck if (skb->len > frame_length) {
2560a8db76d4SSven Van Asbroeck skb->tail -= skb->len - frame_length;
2561a8db76d4SSven Van Asbroeck skb->len = frame_length;
2562a8db76d4SSven Van Asbroeck }
2563a8db76d4SSven Van Asbroeck return skb;
2564a8db76d4SSven Van Asbroeck }
2565a8db76d4SSven Van Asbroeck
lan743x_rx_process_buffer(struct lan743x_rx * rx)2566a8db76d4SSven Van Asbroeck static int lan743x_rx_process_buffer(struct lan743x_rx *rx)
2567a8db76d4SSven Van Asbroeck {
256846251282SAlexey Denisov int current_head_index = le32_to_cpu(*rx->head_cpu_ptr);
2569a8db76d4SSven Van Asbroeck struct lan743x_rx_descriptor *descriptor, *desc_ext;
2570a8db76d4SSven Van Asbroeck struct net_device *netdev = rx->adapter->netdev;
2571a8db76d4SSven Van Asbroeck int result = RX_PROCESS_RESULT_NOTHING_TO_DO;
257223f0703cSBryan Whitehead struct lan743x_rx_buffer_info *buffer_info;
2573a8db76d4SSven Van Asbroeck int frame_length, buffer_length;
2574cd691050SRaju Lakkaraju bool is_ice, is_tce, is_icsm;
257523f0703cSBryan Whitehead int extension_index = -1;
2576a8db76d4SSven Van Asbroeck bool is_last, is_first;
2577a8db76d4SSven Van Asbroeck struct sk_buff *skb;
257823f0703cSBryan Whitehead
257923f0703cSBryan Whitehead if (current_head_index < 0 || current_head_index >= rx->ring_size)
258023f0703cSBryan Whitehead goto done;
258123f0703cSBryan Whitehead
258223f0703cSBryan Whitehead if (rx->last_head < 0 || rx->last_head >= rx->ring_size)
258323f0703cSBryan Whitehead goto done;
258423f0703cSBryan Whitehead
2585a8db76d4SSven Van Asbroeck if (rx->last_head == current_head_index)
2586a8db76d4SSven Van Asbroeck goto done;
2587a8db76d4SSven Van Asbroeck
258823f0703cSBryan Whitehead descriptor = &rx->ring_cpu_ptr[rx->last_head];
258946251282SAlexey Denisov if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_OWN_)
259023f0703cSBryan Whitehead goto done;
2591a8db76d4SSven Van Asbroeck buffer_info = &rx->buffer_info[rx->last_head];
259223f0703cSBryan Whitehead
2593a8db76d4SSven Van Asbroeck is_last = le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_LS_;
2594a8db76d4SSven Van Asbroeck is_first = le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_FS_;
259523f0703cSBryan Whitehead
2596a8db76d4SSven Van Asbroeck if (is_last && le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_EXT_) {
259723f0703cSBryan Whitehead /* extension is expected to follow */
2598a8db76d4SSven Van Asbroeck int index = lan743x_rx_next_index(rx, rx->last_head);
2599a8db76d4SSven Van Asbroeck
2600a8db76d4SSven Van Asbroeck if (index == current_head_index)
2601a8db76d4SSven Van Asbroeck /* extension not yet available */
260223f0703cSBryan Whitehead goto done;
2603a8db76d4SSven Van Asbroeck desc_ext = &rx->ring_cpu_ptr[index];
2604a8db76d4SSven Van Asbroeck if (le32_to_cpu(desc_ext->data0) & RX_DESC_DATA0_OWN_)
2605a8db76d4SSven Van Asbroeck /* extension not yet available */
2606a8db76d4SSven Van Asbroeck goto done;
2607a8db76d4SSven Van Asbroeck if (!(le32_to_cpu(desc_ext->data0) & RX_DESC_DATA0_EXT_))
2608a8db76d4SSven Van Asbroeck goto move_forward;
260923f0703cSBryan Whitehead extension_index = index;
261023f0703cSBryan Whitehead }
261123f0703cSBryan Whitehead
2612a8db76d4SSven Van Asbroeck /* Only the last buffer in a multi-buffer frame contains the total frame
2613a8db76d4SSven Van Asbroeck * length. The chip occasionally sends more buffers than strictly
2614a8db76d4SSven Van Asbroeck * required to reach the total frame length.
2615a8db76d4SSven Van Asbroeck * Handle this by adding all buffers to the skb in their entirety.
2616a8db76d4SSven Van Asbroeck * Once the real frame length is known, trim the skb.
2617a8db76d4SSven Van Asbroeck */
2618a8db76d4SSven Van Asbroeck frame_length =
2619a8db76d4SSven Van Asbroeck RX_DESC_DATA0_FRAME_LENGTH_GET_(le32_to_cpu(descriptor->data0));
2620a8db76d4SSven Van Asbroeck buffer_length = buffer_info->buffer_length;
2621cd691050SRaju Lakkaraju is_ice = le32_to_cpu(descriptor->data1) & RX_DESC_DATA1_STATUS_ICE_;
2622cd691050SRaju Lakkaraju is_tce = le32_to_cpu(descriptor->data1) & RX_DESC_DATA1_STATUS_TCE_;
2623cd691050SRaju Lakkaraju is_icsm = le32_to_cpu(descriptor->data1) & RX_DESC_DATA1_STATUS_ICSM_;
262423f0703cSBryan Whitehead
2625a8db76d4SSven Van Asbroeck netdev_dbg(netdev, "%s%schunk: %d/%d",
2626a8db76d4SSven Van Asbroeck is_first ? "first " : " ",
2627a8db76d4SSven Van Asbroeck is_last ? "last " : " ",
2628a8db76d4SSven Van Asbroeck frame_length, buffer_length);
2629a8db76d4SSven Van Asbroeck
2630a8db76d4SSven Van Asbroeck /* save existing skb, allocate new skb and map to dma */
2631a8db76d4SSven Van Asbroeck skb = buffer_info->skb;
2632e8684db1SYuiko Oshino if (lan743x_rx_init_ring_element(rx, rx->last_head,
2633e8684db1SYuiko Oshino GFP_ATOMIC | GFP_DMA)) {
2634dd9d9f59SBryan Whitehead /* failed to allocate next skb.
2635dd9d9f59SBryan Whitehead * Memory is very low.
2636dd9d9f59SBryan Whitehead * Drop this packet and reuse buffer.
2637dd9d9f59SBryan Whitehead */
2638a8db76d4SSven Van Asbroeck lan743x_rx_reuse_ring_element(rx, rx->last_head);
2639a8db76d4SSven Van Asbroeck /* drop packet that was being assembled */
2640a8db76d4SSven Van Asbroeck dev_kfree_skb_irq(rx->skb_head);
2641a8db76d4SSven Van Asbroeck rx->skb_head = NULL;
2642dd9d9f59SBryan Whitehead goto process_extension;
2643dd9d9f59SBryan Whitehead }
2644dd9d9f59SBryan Whitehead
2645a8db76d4SSven Van Asbroeck /* add buffers to skb via skb->frag_list */
2646a8db76d4SSven Van Asbroeck if (is_first) {
2647a8db76d4SSven Van Asbroeck skb_reserve(skb, RX_HEAD_PADDING);
2648a8db76d4SSven Van Asbroeck skb_put(skb, buffer_length - RX_HEAD_PADDING);
2649a8db76d4SSven Van Asbroeck if (rx->skb_head)
2650a8db76d4SSven Van Asbroeck dev_kfree_skb_irq(rx->skb_head);
2651a8db76d4SSven Van Asbroeck rx->skb_head = skb;
2652a8db76d4SSven Van Asbroeck } else if (rx->skb_head) {
2653a8db76d4SSven Van Asbroeck skb_put(skb, buffer_length);
2654a8db76d4SSven Van Asbroeck if (skb_shinfo(rx->skb_head)->frag_list)
2655a8db76d4SSven Van Asbroeck rx->skb_tail->next = skb;
2656a8db76d4SSven Van Asbroeck else
2657a8db76d4SSven Van Asbroeck skb_shinfo(rx->skb_head)->frag_list = skb;
2658a8db76d4SSven Van Asbroeck rx->skb_tail = skb;
2659a8db76d4SSven Van Asbroeck rx->skb_head->len += skb->len;
2660a8db76d4SSven Van Asbroeck rx->skb_head->data_len += skb->len;
2661a8db76d4SSven Van Asbroeck rx->skb_head->truesize += skb->truesize;
266223f0703cSBryan Whitehead } else {
2663a8db76d4SSven Van Asbroeck /* packet to assemble has already been dropped because one or
2664a8db76d4SSven Van Asbroeck * more of its buffers could not be allocated
266523f0703cSBryan Whitehead */
2666a8db76d4SSven Van Asbroeck netdev_dbg(netdev, "drop buffer intended for dropped packet");
2667a8db76d4SSven Van Asbroeck dev_kfree_skb_irq(skb);
266823f0703cSBryan Whitehead }
266923f0703cSBryan Whitehead
2670dd9d9f59SBryan Whitehead process_extension:
267123f0703cSBryan Whitehead if (extension_index >= 0) {
2672a8db76d4SSven Van Asbroeck u32 ts_sec;
2673a8db76d4SSven Van Asbroeck u32 ts_nsec;
267423f0703cSBryan Whitehead
2675a8db76d4SSven Van Asbroeck ts_sec = le32_to_cpu(desc_ext->data1);
2676a8db76d4SSven Van Asbroeck ts_nsec = (le32_to_cpu(desc_ext->data2) &
267723f0703cSBryan Whitehead RX_DESC_DATA2_TS_NS_MASK_);
2678a8db76d4SSven Van Asbroeck if (rx->skb_head)
2679a8db76d4SSven Van Asbroeck skb_hwtstamps(rx->skb_head)->hwtstamp =
2680a8db76d4SSven Van Asbroeck ktime_set(ts_sec, ts_nsec);
268123f0703cSBryan Whitehead lan743x_rx_reuse_ring_element(rx, extension_index);
2682a8db76d4SSven Van Asbroeck rx->last_head = extension_index;
2683a8db76d4SSven Van Asbroeck netdev_dbg(netdev, "process extension");
268423f0703cSBryan Whitehead }
268523f0703cSBryan Whitehead
2686a8db76d4SSven Van Asbroeck if (is_last && rx->skb_head)
2687a8db76d4SSven Van Asbroeck rx->skb_head = lan743x_rx_trim_skb(rx->skb_head, frame_length);
2688a8db76d4SSven Van Asbroeck
2689a8db76d4SSven Van Asbroeck if (is_last && rx->skb_head) {
2690a8db76d4SSven Van Asbroeck rx->skb_head->protocol = eth_type_trans(rx->skb_head,
2691a8db76d4SSven Van Asbroeck rx->adapter->netdev);
2692cd691050SRaju Lakkaraju if (rx->adapter->netdev->features & NETIF_F_RXCSUM) {
2693cd691050SRaju Lakkaraju if (!is_ice && !is_tce && !is_icsm)
2694cd691050SRaju Lakkaraju skb->ip_summed = CHECKSUM_UNNECESSARY;
2695cd691050SRaju Lakkaraju }
2696a8db76d4SSven Van Asbroeck netdev_dbg(netdev, "sending %d byte frame to OS",
2697a8db76d4SSven Van Asbroeck rx->skb_head->len);
2698a8db76d4SSven Van Asbroeck napi_gro_receive(&rx->napi, rx->skb_head);
2699a8db76d4SSven Van Asbroeck rx->skb_head = NULL;
270023f0703cSBryan Whitehead }
270123f0703cSBryan Whitehead
270223f0703cSBryan Whitehead move_forward:
270323f0703cSBryan Whitehead /* push tail and head forward */
2704a8db76d4SSven Van Asbroeck rx->last_tail = rx->last_head;
2705a8db76d4SSven Van Asbroeck rx->last_head = lan743x_rx_next_index(rx, rx->last_head);
2706a8db76d4SSven Van Asbroeck result = RX_PROCESS_RESULT_BUFFER_RECEIVED;
270723f0703cSBryan Whitehead done:
270823f0703cSBryan Whitehead return result;
270923f0703cSBryan Whitehead }
271023f0703cSBryan Whitehead
lan743x_rx_napi_poll(struct napi_struct * napi,int weight)271123f0703cSBryan Whitehead static int lan743x_rx_napi_poll(struct napi_struct *napi, int weight)
271223f0703cSBryan Whitehead {
271323f0703cSBryan Whitehead struct lan743x_rx *rx = container_of(napi, struct lan743x_rx, napi);
271423f0703cSBryan Whitehead struct lan743x_adapter *adapter = rx->adapter;
271557030a0bSSven Van Asbroeck int result = RX_PROCESS_RESULT_NOTHING_TO_DO;
271623f0703cSBryan Whitehead u32 rx_tail_flags = 0;
271723f0703cSBryan Whitehead int count;
271823f0703cSBryan Whitehead
271923f0703cSBryan Whitehead if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C) {
272023f0703cSBryan Whitehead /* clear int status bit before reading packet */
272123f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_INT_STS,
272223f0703cSBryan Whitehead DMAC_INT_BIT_RXFRM_(rx->channel_number));
272323f0703cSBryan Whitehead }
272457030a0bSSven Van Asbroeck for (count = 0; count < weight; count++) {
2725a8db76d4SSven Van Asbroeck result = lan743x_rx_process_buffer(rx);
272657030a0bSSven Van Asbroeck if (result == RX_PROCESS_RESULT_NOTHING_TO_DO)
272723f0703cSBryan Whitehead break;
272823f0703cSBryan Whitehead }
272923f0703cSBryan Whitehead rx->frame_count += count;
2730a8db76d4SSven Van Asbroeck if (count == weight || result == RX_PROCESS_RESULT_BUFFER_RECEIVED)
273157030a0bSSven Van Asbroeck return weight;
273223f0703cSBryan Whitehead
273323f0703cSBryan Whitehead if (!napi_complete_done(napi, count))
273457030a0bSSven Van Asbroeck return count;
273523f0703cSBryan Whitehead
273657030a0bSSven Van Asbroeck /* re-arm interrupts, must write to rx tail on some chip variants */
273723f0703cSBryan Whitehead if (rx->vector_flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET)
273823f0703cSBryan Whitehead rx_tail_flags |= RX_TAIL_SET_TOP_INT_VEC_EN_;
273923f0703cSBryan Whitehead if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET) {
274023f0703cSBryan Whitehead rx_tail_flags |= RX_TAIL_SET_TOP_INT_EN_;
274123f0703cSBryan Whitehead } else {
274223f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET,
274323f0703cSBryan Whitehead INT_BIT_DMA_RX_(rx->channel_number));
274423f0703cSBryan Whitehead }
274523f0703cSBryan Whitehead
274657030a0bSSven Van Asbroeck if (rx_tail_flags)
274723f0703cSBryan Whitehead lan743x_csr_write(adapter, RX_TAIL(rx->channel_number),
274823f0703cSBryan Whitehead rx_tail_flags | rx->last_tail);
274957030a0bSSven Van Asbroeck
275023f0703cSBryan Whitehead return count;
275123f0703cSBryan Whitehead }
275223f0703cSBryan Whitehead
lan743x_rx_ring_cleanup(struct lan743x_rx * rx)275323f0703cSBryan Whitehead static void lan743x_rx_ring_cleanup(struct lan743x_rx *rx)
275423f0703cSBryan Whitehead {
275523f0703cSBryan Whitehead if (rx->buffer_info && rx->ring_cpu_ptr) {
275623f0703cSBryan Whitehead int index;
275723f0703cSBryan Whitehead
275823f0703cSBryan Whitehead for (index = 0; index < rx->ring_size; index++)
275923f0703cSBryan Whitehead lan743x_rx_release_ring_element(rx, index);
276023f0703cSBryan Whitehead }
276123f0703cSBryan Whitehead
276223f0703cSBryan Whitehead if (rx->head_cpu_ptr) {
2763a3b7b493SChristophe JAILLET dma_free_coherent(&rx->adapter->pdev->dev,
2764a3b7b493SChristophe JAILLET sizeof(*rx->head_cpu_ptr), rx->head_cpu_ptr,
276523f0703cSBryan Whitehead rx->head_dma_ptr);
276623f0703cSBryan Whitehead rx->head_cpu_ptr = NULL;
276723f0703cSBryan Whitehead rx->head_dma_ptr = 0;
276823f0703cSBryan Whitehead }
276923f0703cSBryan Whitehead
277023f0703cSBryan Whitehead kfree(rx->buffer_info);
277123f0703cSBryan Whitehead rx->buffer_info = NULL;
277223f0703cSBryan Whitehead
277323f0703cSBryan Whitehead if (rx->ring_cpu_ptr) {
2774a3b7b493SChristophe JAILLET dma_free_coherent(&rx->adapter->pdev->dev,
2775a3b7b493SChristophe JAILLET rx->ring_allocation_size, rx->ring_cpu_ptr,
277623f0703cSBryan Whitehead rx->ring_dma_ptr);
277723f0703cSBryan Whitehead rx->ring_allocation_size = 0;
277823f0703cSBryan Whitehead rx->ring_cpu_ptr = NULL;
277923f0703cSBryan Whitehead rx->ring_dma_ptr = 0;
278023f0703cSBryan Whitehead }
278123f0703cSBryan Whitehead
278223f0703cSBryan Whitehead rx->ring_size = 0;
278323f0703cSBryan Whitehead rx->last_head = 0;
278423f0703cSBryan Whitehead }
278523f0703cSBryan Whitehead
lan743x_rx_ring_init(struct lan743x_rx * rx)278623f0703cSBryan Whitehead static int lan743x_rx_ring_init(struct lan743x_rx *rx)
278723f0703cSBryan Whitehead {
278823f0703cSBryan Whitehead size_t ring_allocation_size = 0;
278923f0703cSBryan Whitehead dma_addr_t dma_ptr = 0;
279023f0703cSBryan Whitehead void *cpu_ptr = NULL;
279123f0703cSBryan Whitehead int ret = -ENOMEM;
279223f0703cSBryan Whitehead int index = 0;
279323f0703cSBryan Whitehead
279423f0703cSBryan Whitehead rx->ring_size = LAN743X_RX_RING_SIZE;
279523f0703cSBryan Whitehead if (rx->ring_size <= 1) {
279623f0703cSBryan Whitehead ret = -EINVAL;
279723f0703cSBryan Whitehead goto cleanup;
279823f0703cSBryan Whitehead }
279923f0703cSBryan Whitehead if (rx->ring_size & ~RX_CFG_B_RX_RING_LEN_MASK_) {
280023f0703cSBryan Whitehead ret = -EINVAL;
280123f0703cSBryan Whitehead goto cleanup;
280223f0703cSBryan Whitehead }
280395a359c9SYuiko Oshino if (dma_set_mask_and_coherent(&rx->adapter->pdev->dev,
280495a359c9SYuiko Oshino DMA_BIT_MASK(64))) {
280595a359c9SYuiko Oshino dev_warn(&rx->adapter->pdev->dev,
280695a359c9SYuiko Oshino "lan743x_: No suitable DMA available\n");
280795a359c9SYuiko Oshino ret = -ENOMEM;
280895a359c9SYuiko Oshino goto cleanup;
280995a359c9SYuiko Oshino }
281023f0703cSBryan Whitehead ring_allocation_size = ALIGN(rx->ring_size *
281123f0703cSBryan Whitehead sizeof(struct lan743x_rx_descriptor),
281223f0703cSBryan Whitehead PAGE_SIZE);
281323f0703cSBryan Whitehead dma_ptr = 0;
2814a3b7b493SChristophe JAILLET cpu_ptr = dma_alloc_coherent(&rx->adapter->pdev->dev,
2815a3b7b493SChristophe JAILLET ring_allocation_size, &dma_ptr, GFP_KERNEL);
281623f0703cSBryan Whitehead if (!cpu_ptr) {
281723f0703cSBryan Whitehead ret = -ENOMEM;
281823f0703cSBryan Whitehead goto cleanup;
281923f0703cSBryan Whitehead }
282023f0703cSBryan Whitehead rx->ring_allocation_size = ring_allocation_size;
282123f0703cSBryan Whitehead rx->ring_cpu_ptr = (struct lan743x_rx_descriptor *)cpu_ptr;
282223f0703cSBryan Whitehead rx->ring_dma_ptr = dma_ptr;
282323f0703cSBryan Whitehead
282423f0703cSBryan Whitehead cpu_ptr = kcalloc(rx->ring_size, sizeof(*rx->buffer_info),
282523f0703cSBryan Whitehead GFP_KERNEL);
282623f0703cSBryan Whitehead if (!cpu_ptr) {
282723f0703cSBryan Whitehead ret = -ENOMEM;
282823f0703cSBryan Whitehead goto cleanup;
282923f0703cSBryan Whitehead }
283023f0703cSBryan Whitehead rx->buffer_info = (struct lan743x_rx_buffer_info *)cpu_ptr;
283123f0703cSBryan Whitehead dma_ptr = 0;
2832a3b7b493SChristophe JAILLET cpu_ptr = dma_alloc_coherent(&rx->adapter->pdev->dev,
2833a3b7b493SChristophe JAILLET sizeof(*rx->head_cpu_ptr), &dma_ptr,
2834a3b7b493SChristophe JAILLET GFP_KERNEL);
283523f0703cSBryan Whitehead if (!cpu_ptr) {
283623f0703cSBryan Whitehead ret = -ENOMEM;
283723f0703cSBryan Whitehead goto cleanup;
283823f0703cSBryan Whitehead }
283923f0703cSBryan Whitehead
284023f0703cSBryan Whitehead rx->head_cpu_ptr = cpu_ptr;
284123f0703cSBryan Whitehead rx->head_dma_ptr = dma_ptr;
284223f0703cSBryan Whitehead if (rx->head_dma_ptr & 0x3) {
284323f0703cSBryan Whitehead ret = -ENOMEM;
284423f0703cSBryan Whitehead goto cleanup;
284523f0703cSBryan Whitehead }
284623f0703cSBryan Whitehead
284723f0703cSBryan Whitehead rx->last_head = 0;
284823f0703cSBryan Whitehead for (index = 0; index < rx->ring_size; index++) {
2849e8684db1SYuiko Oshino ret = lan743x_rx_init_ring_element(rx, index, GFP_KERNEL);
285023f0703cSBryan Whitehead if (ret)
285123f0703cSBryan Whitehead goto cleanup;
285223f0703cSBryan Whitehead }
285323f0703cSBryan Whitehead return 0;
285423f0703cSBryan Whitehead
285523f0703cSBryan Whitehead cleanup:
2856e8684db1SYuiko Oshino netif_warn(rx->adapter, ifup, rx->adapter->netdev,
2857e8684db1SYuiko Oshino "Error allocating memory for LAN743x\n");
2858e8684db1SYuiko Oshino
285923f0703cSBryan Whitehead lan743x_rx_ring_cleanup(rx);
286023f0703cSBryan Whitehead return ret;
286123f0703cSBryan Whitehead }
286223f0703cSBryan Whitehead
lan743x_rx_close(struct lan743x_rx * rx)286323f0703cSBryan Whitehead static void lan743x_rx_close(struct lan743x_rx *rx)
286423f0703cSBryan Whitehead {
286523f0703cSBryan Whitehead struct lan743x_adapter *adapter = rx->adapter;
286623f0703cSBryan Whitehead
286723f0703cSBryan Whitehead lan743x_csr_write(adapter, FCT_RX_CTL,
286823f0703cSBryan Whitehead FCT_RX_CTL_DIS_(rx->channel_number));
286923f0703cSBryan Whitehead lan743x_csr_wait_for_bit(adapter, FCT_RX_CTL,
287023f0703cSBryan Whitehead FCT_RX_CTL_EN_(rx->channel_number),
287123f0703cSBryan Whitehead 0, 1000, 20000, 100);
287223f0703cSBryan Whitehead
287323f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_CMD,
287423f0703cSBryan Whitehead DMAC_CMD_STOP_R_(rx->channel_number));
287523f0703cSBryan Whitehead lan743x_dmac_rx_wait_till_stopped(adapter, rx->channel_number);
287623f0703cSBryan Whitehead
287723f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_INT_EN_CLR,
287823f0703cSBryan Whitehead DMAC_INT_BIT_RXFRM_(rx->channel_number));
287923f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR,
288023f0703cSBryan Whitehead INT_BIT_DMA_RX_(rx->channel_number));
288123f0703cSBryan Whitehead napi_disable(&rx->napi);
288223f0703cSBryan Whitehead
288323f0703cSBryan Whitehead netif_napi_del(&rx->napi);
288423f0703cSBryan Whitehead
288523f0703cSBryan Whitehead lan743x_rx_ring_cleanup(rx);
288623f0703cSBryan Whitehead }
288723f0703cSBryan Whitehead
lan743x_rx_open(struct lan743x_rx * rx)288823f0703cSBryan Whitehead static int lan743x_rx_open(struct lan743x_rx *rx)
288923f0703cSBryan Whitehead {
289023f0703cSBryan Whitehead struct lan743x_adapter *adapter = rx->adapter;
289123f0703cSBryan Whitehead u32 data = 0;
289223f0703cSBryan Whitehead int ret;
289323f0703cSBryan Whitehead
289423f0703cSBryan Whitehead rx->frame_count = 0;
289523f0703cSBryan Whitehead ret = lan743x_rx_ring_init(rx);
289623f0703cSBryan Whitehead if (ret)
289723f0703cSBryan Whitehead goto return_error;
289823f0703cSBryan Whitehead
2899b48b89f9SJakub Kicinski netif_napi_add(adapter->netdev, &rx->napi, lan743x_rx_napi_poll);
290023f0703cSBryan Whitehead
290123f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_CMD,
290223f0703cSBryan Whitehead DMAC_CMD_RX_SWR_(rx->channel_number));
290323f0703cSBryan Whitehead lan743x_csr_wait_for_bit(adapter, DMAC_CMD,
290423f0703cSBryan Whitehead DMAC_CMD_RX_SWR_(rx->channel_number),
290523f0703cSBryan Whitehead 0, 1000, 20000, 100);
290623f0703cSBryan Whitehead
290723f0703cSBryan Whitehead /* set ring base address */
290823f0703cSBryan Whitehead lan743x_csr_write(adapter,
290923f0703cSBryan Whitehead RX_BASE_ADDRH(rx->channel_number),
291023f0703cSBryan Whitehead DMA_ADDR_HIGH32(rx->ring_dma_ptr));
291123f0703cSBryan Whitehead lan743x_csr_write(adapter,
291223f0703cSBryan Whitehead RX_BASE_ADDRL(rx->channel_number),
291323f0703cSBryan Whitehead DMA_ADDR_LOW32(rx->ring_dma_ptr));
291423f0703cSBryan Whitehead
291523f0703cSBryan Whitehead /* set rx write back address */
291623f0703cSBryan Whitehead lan743x_csr_write(adapter,
291723f0703cSBryan Whitehead RX_HEAD_WRITEBACK_ADDRH(rx->channel_number),
291823f0703cSBryan Whitehead DMA_ADDR_HIGH32(rx->head_dma_ptr));
291923f0703cSBryan Whitehead lan743x_csr_write(adapter,
292023f0703cSBryan Whitehead RX_HEAD_WRITEBACK_ADDRL(rx->channel_number),
292123f0703cSBryan Whitehead DMA_ADDR_LOW32(rx->head_dma_ptr));
292223f0703cSBryan Whitehead data = RX_CFG_A_RX_HP_WB_EN_;
292323f0703cSBryan Whitehead if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) {
292423f0703cSBryan Whitehead data |= (RX_CFG_A_RX_WB_ON_INT_TMR_ |
292523f0703cSBryan Whitehead RX_CFG_A_RX_WB_THRES_SET_(0x7) |
292623f0703cSBryan Whitehead RX_CFG_A_RX_PF_THRES_SET_(16) |
292723f0703cSBryan Whitehead RX_CFG_A_RX_PF_PRI_THRES_SET_(4));
292823f0703cSBryan Whitehead }
292923f0703cSBryan Whitehead
293023f0703cSBryan Whitehead /* set RX_CFG_A */
293123f0703cSBryan Whitehead lan743x_csr_write(adapter,
293223f0703cSBryan Whitehead RX_CFG_A(rx->channel_number), data);
293323f0703cSBryan Whitehead
293423f0703cSBryan Whitehead /* set RX_CFG_B */
293523f0703cSBryan Whitehead data = lan743x_csr_read(adapter, RX_CFG_B(rx->channel_number));
293623f0703cSBryan Whitehead data &= ~RX_CFG_B_RX_PAD_MASK_;
293723f0703cSBryan Whitehead if (!RX_HEAD_PADDING)
293823f0703cSBryan Whitehead data |= RX_CFG_B_RX_PAD_0_;
293923f0703cSBryan Whitehead else
294023f0703cSBryan Whitehead data |= RX_CFG_B_RX_PAD_2_;
294123f0703cSBryan Whitehead data &= ~RX_CFG_B_RX_RING_LEN_MASK_;
294223f0703cSBryan Whitehead data |= ((rx->ring_size) & RX_CFG_B_RX_RING_LEN_MASK_);
294323f0703cSBryan Whitehead data |= RX_CFG_B_TS_ALL_RX_;
294423f0703cSBryan Whitehead if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0))
294523f0703cSBryan Whitehead data |= RX_CFG_B_RDMABL_512_;
294623f0703cSBryan Whitehead
294723f0703cSBryan Whitehead lan743x_csr_write(adapter, RX_CFG_B(rx->channel_number), data);
294823f0703cSBryan Whitehead rx->vector_flags = lan743x_intr_get_vector_flags(adapter,
294923f0703cSBryan Whitehead INT_BIT_DMA_RX_
295023f0703cSBryan Whitehead (rx->channel_number));
295123f0703cSBryan Whitehead
295223f0703cSBryan Whitehead /* set RX_CFG_C */
295323f0703cSBryan Whitehead data = 0;
295423f0703cSBryan Whitehead if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR)
295523f0703cSBryan Whitehead data |= RX_CFG_C_RX_TOP_INT_EN_AUTO_CLR_;
295623f0703cSBryan Whitehead if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR)
295723f0703cSBryan Whitehead data |= RX_CFG_C_RX_DMA_INT_STS_AUTO_CLR_;
295823f0703cSBryan Whitehead if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C)
295923f0703cSBryan Whitehead data |= RX_CFG_C_RX_INT_STS_R2C_MODE_MASK_;
296023f0703cSBryan Whitehead if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C)
296123f0703cSBryan Whitehead data |= RX_CFG_C_RX_INT_EN_R2C_;
296223f0703cSBryan Whitehead lan743x_csr_write(adapter, RX_CFG_C(rx->channel_number), data);
296323f0703cSBryan Whitehead
296423f0703cSBryan Whitehead rx->last_tail = ((u32)(rx->ring_size - 1));
296523f0703cSBryan Whitehead lan743x_csr_write(adapter, RX_TAIL(rx->channel_number),
296623f0703cSBryan Whitehead rx->last_tail);
296723f0703cSBryan Whitehead rx->last_head = lan743x_csr_read(adapter, RX_HEAD(rx->channel_number));
296823f0703cSBryan Whitehead if (rx->last_head) {
296923f0703cSBryan Whitehead ret = -EIO;
297023f0703cSBryan Whitehead goto napi_delete;
297123f0703cSBryan Whitehead }
297223f0703cSBryan Whitehead
297323f0703cSBryan Whitehead napi_enable(&rx->napi);
297423f0703cSBryan Whitehead
297523f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET,
297623f0703cSBryan Whitehead INT_BIT_DMA_RX_(rx->channel_number));
297723f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_INT_STS,
297823f0703cSBryan Whitehead DMAC_INT_BIT_RXFRM_(rx->channel_number));
297923f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_INT_EN_SET,
298023f0703cSBryan Whitehead DMAC_INT_BIT_RXFRM_(rx->channel_number));
298123f0703cSBryan Whitehead lan743x_csr_write(adapter, DMAC_CMD,
298223f0703cSBryan Whitehead DMAC_CMD_START_R_(rx->channel_number));
298323f0703cSBryan Whitehead
298423f0703cSBryan Whitehead /* initialize fifo */
298523f0703cSBryan Whitehead lan743x_csr_write(adapter, FCT_RX_CTL,
298623f0703cSBryan Whitehead FCT_RX_CTL_RESET_(rx->channel_number));
298723f0703cSBryan Whitehead lan743x_csr_wait_for_bit(adapter, FCT_RX_CTL,
298823f0703cSBryan Whitehead FCT_RX_CTL_RESET_(rx->channel_number),
298923f0703cSBryan Whitehead 0, 1000, 20000, 100);
299023f0703cSBryan Whitehead lan743x_csr_write(adapter, FCT_FLOW(rx->channel_number),
299123f0703cSBryan Whitehead FCT_FLOW_CTL_REQ_EN_ |
299223f0703cSBryan Whitehead FCT_FLOW_CTL_ON_THRESHOLD_SET_(0x2A) |
299323f0703cSBryan Whitehead FCT_FLOW_CTL_OFF_THRESHOLD_SET_(0xA));
299423f0703cSBryan Whitehead
299523f0703cSBryan Whitehead /* enable fifo */
299623f0703cSBryan Whitehead lan743x_csr_write(adapter, FCT_RX_CTL,
299723f0703cSBryan Whitehead FCT_RX_CTL_EN_(rx->channel_number));
299823f0703cSBryan Whitehead return 0;
299923f0703cSBryan Whitehead
300023f0703cSBryan Whitehead napi_delete:
300123f0703cSBryan Whitehead netif_napi_del(&rx->napi);
300223f0703cSBryan Whitehead lan743x_rx_ring_cleanup(rx);
300323f0703cSBryan Whitehead
300423f0703cSBryan Whitehead return_error:
300523f0703cSBryan Whitehead return ret;
300623f0703cSBryan Whitehead }
300723f0703cSBryan Whitehead
lan743x_netdev_close(struct net_device * netdev)300823f0703cSBryan Whitehead static int lan743x_netdev_close(struct net_device *netdev)
300923f0703cSBryan Whitehead {
301023f0703cSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
301123f0703cSBryan Whitehead int index;
301223f0703cSBryan Whitehead
3013cf9aaea8SRaju Lakkaraju for (index = 0; index < adapter->used_tx_channels; index++)
3014cf9aaea8SRaju Lakkaraju lan743x_tx_close(&adapter->tx[index]);
301523f0703cSBryan Whitehead
301623f0703cSBryan Whitehead for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++)
301723f0703cSBryan Whitehead lan743x_rx_close(&adapter->rx[index]);
301823f0703cSBryan Whitehead
301907624df1SBryan Whitehead lan743x_ptp_close(adapter);
302007624df1SBryan Whitehead
302123f0703cSBryan Whitehead lan743x_phy_close(adapter);
302223f0703cSBryan Whitehead
302323f0703cSBryan Whitehead lan743x_mac_close(adapter);
302423f0703cSBryan Whitehead
302523f0703cSBryan Whitehead lan743x_intr_close(adapter);
302623f0703cSBryan Whitehead
302723f0703cSBryan Whitehead return 0;
302823f0703cSBryan Whitehead }
302923f0703cSBryan Whitehead
lan743x_netdev_open(struct net_device * netdev)303023f0703cSBryan Whitehead static int lan743x_netdev_open(struct net_device *netdev)
303123f0703cSBryan Whitehead {
303223f0703cSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
303323f0703cSBryan Whitehead int index;
303423f0703cSBryan Whitehead int ret;
303523f0703cSBryan Whitehead
303623f0703cSBryan Whitehead ret = lan743x_intr_open(adapter);
303723f0703cSBryan Whitehead if (ret)
303823f0703cSBryan Whitehead goto return_error;
303923f0703cSBryan Whitehead
304023f0703cSBryan Whitehead ret = lan743x_mac_open(adapter);
304123f0703cSBryan Whitehead if (ret)
304223f0703cSBryan Whitehead goto close_intr;
304323f0703cSBryan Whitehead
304423f0703cSBryan Whitehead ret = lan743x_phy_open(adapter);
304523f0703cSBryan Whitehead if (ret)
304623f0703cSBryan Whitehead goto close_mac;
304723f0703cSBryan Whitehead
304807624df1SBryan Whitehead ret = lan743x_ptp_open(adapter);
304907624df1SBryan Whitehead if (ret)
305007624df1SBryan Whitehead goto close_phy;
305107624df1SBryan Whitehead
305243e8fe9bSBryan Whitehead lan743x_rfe_open(adapter);
305343e8fe9bSBryan Whitehead
305423f0703cSBryan Whitehead for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) {
305523f0703cSBryan Whitehead ret = lan743x_rx_open(&adapter->rx[index]);
305623f0703cSBryan Whitehead if (ret)
305723f0703cSBryan Whitehead goto close_rx;
305823f0703cSBryan Whitehead }
305923f0703cSBryan Whitehead
3060cf9aaea8SRaju Lakkaraju for (index = 0; index < adapter->used_tx_channels; index++) {
3061cf9aaea8SRaju Lakkaraju ret = lan743x_tx_open(&adapter->tx[index]);
306223f0703cSBryan Whitehead if (ret)
3063cf9aaea8SRaju Lakkaraju goto close_tx;
3064cf9aaea8SRaju Lakkaraju }
3065*de4fc109SRaju Lakkaraju
3066*de4fc109SRaju Lakkaraju #ifdef CONFIG_PM
3067*de4fc109SRaju Lakkaraju if (adapter->netdev->phydev) {
3068*de4fc109SRaju Lakkaraju struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
3069*de4fc109SRaju Lakkaraju
3070*de4fc109SRaju Lakkaraju phy_ethtool_get_wol(netdev->phydev, &wol);
3071*de4fc109SRaju Lakkaraju adapter->phy_wol_supported = wol.supported;
3072*de4fc109SRaju Lakkaraju adapter->phy_wolopts = wol.wolopts;
3073*de4fc109SRaju Lakkaraju }
3074*de4fc109SRaju Lakkaraju #endif
3075*de4fc109SRaju Lakkaraju
307623f0703cSBryan Whitehead return 0;
307723f0703cSBryan Whitehead
3078cf9aaea8SRaju Lakkaraju close_tx:
3079cf9aaea8SRaju Lakkaraju for (index = 0; index < adapter->used_tx_channels; index++) {
3080cf9aaea8SRaju Lakkaraju if (adapter->tx[index].ring_cpu_ptr)
3081cf9aaea8SRaju Lakkaraju lan743x_tx_close(&adapter->tx[index]);
3082cf9aaea8SRaju Lakkaraju }
3083cf9aaea8SRaju Lakkaraju
308423f0703cSBryan Whitehead close_rx:
308523f0703cSBryan Whitehead for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) {
308623f0703cSBryan Whitehead if (adapter->rx[index].ring_cpu_ptr)
308723f0703cSBryan Whitehead lan743x_rx_close(&adapter->rx[index]);
308823f0703cSBryan Whitehead }
308907624df1SBryan Whitehead lan743x_ptp_close(adapter);
309007624df1SBryan Whitehead
309107624df1SBryan Whitehead close_phy:
309223f0703cSBryan Whitehead lan743x_phy_close(adapter);
309323f0703cSBryan Whitehead
309423f0703cSBryan Whitehead close_mac:
309523f0703cSBryan Whitehead lan743x_mac_close(adapter);
309623f0703cSBryan Whitehead
309723f0703cSBryan Whitehead close_intr:
309823f0703cSBryan Whitehead lan743x_intr_close(adapter);
309923f0703cSBryan Whitehead
310023f0703cSBryan Whitehead return_error:
310123f0703cSBryan Whitehead netif_warn(adapter, ifup, adapter->netdev,
310223f0703cSBryan Whitehead "Error opening LAN743x\n");
310323f0703cSBryan Whitehead return ret;
310423f0703cSBryan Whitehead }
310523f0703cSBryan Whitehead
lan743x_netdev_xmit_frame(struct sk_buff * skb,struct net_device * netdev)310623f0703cSBryan Whitehead static netdev_tx_t lan743x_netdev_xmit_frame(struct sk_buff *skb,
310723f0703cSBryan Whitehead struct net_device *netdev)
310823f0703cSBryan Whitehead {
310923f0703cSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
3110cf9aaea8SRaju Lakkaraju u8 ch = 0;
311123f0703cSBryan Whitehead
3112cf9aaea8SRaju Lakkaraju if (adapter->is_pci11x1x)
3113cf9aaea8SRaju Lakkaraju ch = skb->queue_mapping % PCI11X1X_USED_TX_CHANNELS;
3114cf9aaea8SRaju Lakkaraju
3115cf9aaea8SRaju Lakkaraju return lan743x_tx_xmit_frame(&adapter->tx[ch], skb);
311623f0703cSBryan Whitehead }
311723f0703cSBryan Whitehead
lan743x_netdev_ioctl(struct net_device * netdev,struct ifreq * ifr,int cmd)311823f0703cSBryan Whitehead static int lan743x_netdev_ioctl(struct net_device *netdev,
311923f0703cSBryan Whitehead struct ifreq *ifr, int cmd)
312023f0703cSBryan Whitehead {
312123f0703cSBryan Whitehead if (!netif_running(netdev))
312223f0703cSBryan Whitehead return -EINVAL;
312307624df1SBryan Whitehead if (cmd == SIOCSHWTSTAMP)
312407624df1SBryan Whitehead return lan743x_ptp_ioctl(netdev, ifr, cmd);
312523f0703cSBryan Whitehead return phy_mii_ioctl(netdev->phydev, ifr, cmd);
312623f0703cSBryan Whitehead }
312723f0703cSBryan Whitehead
lan743x_netdev_set_multicast(struct net_device * netdev)312823f0703cSBryan Whitehead static void lan743x_netdev_set_multicast(struct net_device *netdev)
312923f0703cSBryan Whitehead {
313023f0703cSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
313123f0703cSBryan Whitehead
313223f0703cSBryan Whitehead lan743x_rfe_set_multicast(adapter);
313323f0703cSBryan Whitehead }
313423f0703cSBryan Whitehead
lan743x_netdev_change_mtu(struct net_device * netdev,int new_mtu)313523f0703cSBryan Whitehead static int lan743x_netdev_change_mtu(struct net_device *netdev, int new_mtu)
313623f0703cSBryan Whitehead {
313723f0703cSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
313823f0703cSBryan Whitehead int ret = 0;
313923f0703cSBryan Whitehead
314023f0703cSBryan Whitehead ret = lan743x_mac_set_mtu(adapter, new_mtu);
314123f0703cSBryan Whitehead if (!ret)
314223f0703cSBryan Whitehead netdev->mtu = new_mtu;
314323f0703cSBryan Whitehead return ret;
314423f0703cSBryan Whitehead }
314523f0703cSBryan Whitehead
lan743x_netdev_get_stats64(struct net_device * netdev,struct rtnl_link_stats64 * stats)314623f0703cSBryan Whitehead static void lan743x_netdev_get_stats64(struct net_device *netdev,
314723f0703cSBryan Whitehead struct rtnl_link_stats64 *stats)
314823f0703cSBryan Whitehead {
314923f0703cSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
315023f0703cSBryan Whitehead
315123f0703cSBryan Whitehead stats->rx_packets = lan743x_csr_read(adapter, STAT_RX_TOTAL_FRAMES);
315223f0703cSBryan Whitehead stats->tx_packets = lan743x_csr_read(adapter, STAT_TX_TOTAL_FRAMES);
315323f0703cSBryan Whitehead stats->rx_bytes = lan743x_csr_read(adapter,
315423f0703cSBryan Whitehead STAT_RX_UNICAST_BYTE_COUNT) +
315523f0703cSBryan Whitehead lan743x_csr_read(adapter,
315623f0703cSBryan Whitehead STAT_RX_BROADCAST_BYTE_COUNT) +
315723f0703cSBryan Whitehead lan743x_csr_read(adapter,
315823f0703cSBryan Whitehead STAT_RX_MULTICAST_BYTE_COUNT);
315923f0703cSBryan Whitehead stats->tx_bytes = lan743x_csr_read(adapter,
316023f0703cSBryan Whitehead STAT_TX_UNICAST_BYTE_COUNT) +
316123f0703cSBryan Whitehead lan743x_csr_read(adapter,
316223f0703cSBryan Whitehead STAT_TX_BROADCAST_BYTE_COUNT) +
316323f0703cSBryan Whitehead lan743x_csr_read(adapter,
316423f0703cSBryan Whitehead STAT_TX_MULTICAST_BYTE_COUNT);
316523f0703cSBryan Whitehead stats->rx_errors = lan743x_csr_read(adapter, STAT_RX_FCS_ERRORS) +
316623f0703cSBryan Whitehead lan743x_csr_read(adapter,
316723f0703cSBryan Whitehead STAT_RX_ALIGNMENT_ERRORS) +
316823f0703cSBryan Whitehead lan743x_csr_read(adapter, STAT_RX_JABBER_ERRORS) +
316923f0703cSBryan Whitehead lan743x_csr_read(adapter,
317023f0703cSBryan Whitehead STAT_RX_UNDERSIZE_FRAME_ERRORS) +
317123f0703cSBryan Whitehead lan743x_csr_read(adapter,
317223f0703cSBryan Whitehead STAT_RX_OVERSIZE_FRAME_ERRORS);
317323f0703cSBryan Whitehead stats->tx_errors = lan743x_csr_read(adapter, STAT_TX_FCS_ERRORS) +
317423f0703cSBryan Whitehead lan743x_csr_read(adapter,
317523f0703cSBryan Whitehead STAT_TX_EXCESS_DEFERRAL_ERRORS) +
317623f0703cSBryan Whitehead lan743x_csr_read(adapter, STAT_TX_CARRIER_ERRORS);
317723f0703cSBryan Whitehead stats->rx_dropped = lan743x_csr_read(adapter,
317823f0703cSBryan Whitehead STAT_RX_DROPPED_FRAMES);
317923f0703cSBryan Whitehead stats->tx_dropped = lan743x_csr_read(adapter,
318023f0703cSBryan Whitehead STAT_TX_EXCESSIVE_COLLISION);
318123f0703cSBryan Whitehead stats->multicast = lan743x_csr_read(adapter,
318223f0703cSBryan Whitehead STAT_RX_MULTICAST_FRAMES) +
318323f0703cSBryan Whitehead lan743x_csr_read(adapter,
318423f0703cSBryan Whitehead STAT_TX_MULTICAST_FRAMES);
318523f0703cSBryan Whitehead stats->collisions = lan743x_csr_read(adapter,
318623f0703cSBryan Whitehead STAT_TX_SINGLE_COLLISIONS) +
318723f0703cSBryan Whitehead lan743x_csr_read(adapter,
318823f0703cSBryan Whitehead STAT_TX_MULTIPLE_COLLISIONS) +
318923f0703cSBryan Whitehead lan743x_csr_read(adapter,
319023f0703cSBryan Whitehead STAT_TX_LATE_COLLISIONS);
319123f0703cSBryan Whitehead }
319223f0703cSBryan Whitehead
lan743x_netdev_set_mac_address(struct net_device * netdev,void * addr)319323f0703cSBryan Whitehead static int lan743x_netdev_set_mac_address(struct net_device *netdev,
319423f0703cSBryan Whitehead void *addr)
319523f0703cSBryan Whitehead {
319623f0703cSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
319723f0703cSBryan Whitehead struct sockaddr *sock_addr = addr;
319823f0703cSBryan Whitehead int ret;
319923f0703cSBryan Whitehead
320023f0703cSBryan Whitehead ret = eth_prepare_mac_addr_change(netdev, sock_addr);
320123f0703cSBryan Whitehead if (ret)
320223f0703cSBryan Whitehead return ret;
3203f3956ebbSJakub Kicinski eth_hw_addr_set(netdev, sock_addr->sa_data);
320423f0703cSBryan Whitehead lan743x_mac_set_address(adapter, sock_addr->sa_data);
320523f0703cSBryan Whitehead lan743x_rfe_update_mac_address(adapter);
320623f0703cSBryan Whitehead return 0;
320723f0703cSBryan Whitehead }
320823f0703cSBryan Whitehead
320923f0703cSBryan Whitehead static const struct net_device_ops lan743x_netdev_ops = {
321023f0703cSBryan Whitehead .ndo_open = lan743x_netdev_open,
321123f0703cSBryan Whitehead .ndo_stop = lan743x_netdev_close,
321223f0703cSBryan Whitehead .ndo_start_xmit = lan743x_netdev_xmit_frame,
3213a7605370SArnd Bergmann .ndo_eth_ioctl = lan743x_netdev_ioctl,
321423f0703cSBryan Whitehead .ndo_set_rx_mode = lan743x_netdev_set_multicast,
321523f0703cSBryan Whitehead .ndo_change_mtu = lan743x_netdev_change_mtu,
321623f0703cSBryan Whitehead .ndo_get_stats64 = lan743x_netdev_get_stats64,
321723f0703cSBryan Whitehead .ndo_set_mac_address = lan743x_netdev_set_mac_address,
321823f0703cSBryan Whitehead };
321923f0703cSBryan Whitehead
lan743x_hardware_cleanup(struct lan743x_adapter * adapter)322023f0703cSBryan Whitehead static void lan743x_hardware_cleanup(struct lan743x_adapter *adapter)
322123f0703cSBryan Whitehead {
322223f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR, 0xFFFFFFFF);
322323f0703cSBryan Whitehead }
322423f0703cSBryan Whitehead
lan743x_mdiobus_cleanup(struct lan743x_adapter * adapter)322523f0703cSBryan Whitehead static void lan743x_mdiobus_cleanup(struct lan743x_adapter *adapter)
322623f0703cSBryan Whitehead {
322723f0703cSBryan Whitehead mdiobus_unregister(adapter->mdiobus);
322823f0703cSBryan Whitehead }
322923f0703cSBryan Whitehead
lan743x_full_cleanup(struct lan743x_adapter * adapter)323023f0703cSBryan Whitehead static void lan743x_full_cleanup(struct lan743x_adapter *adapter)
323123f0703cSBryan Whitehead {
323223f0703cSBryan Whitehead unregister_netdev(adapter->netdev);
323323f0703cSBryan Whitehead
323423f0703cSBryan Whitehead lan743x_mdiobus_cleanup(adapter);
323523f0703cSBryan Whitehead lan743x_hardware_cleanup(adapter);
323623f0703cSBryan Whitehead lan743x_pci_cleanup(adapter);
323723f0703cSBryan Whitehead }
323823f0703cSBryan Whitehead
pci11x1x_set_rfe_rd_fifo_threshold(struct lan743x_adapter * adapter)323974a78a00SRaju Lakkaraju static void pci11x1x_set_rfe_rd_fifo_threshold(struct lan743x_adapter *adapter)
324074a78a00SRaju Lakkaraju {
324174a78a00SRaju Lakkaraju u16 rev = adapter->csr.id_rev & ID_REV_CHIP_REV_MASK_;
324274a78a00SRaju Lakkaraju
324374a78a00SRaju Lakkaraju if (rev == ID_REV_CHIP_REV_PCI11X1X_B0_) {
324474a78a00SRaju Lakkaraju u32 misc_ctl;
324574a78a00SRaju Lakkaraju
324674a78a00SRaju Lakkaraju misc_ctl = lan743x_csr_read(adapter, MISC_CTL_0);
324774a78a00SRaju Lakkaraju misc_ctl &= ~MISC_CTL_0_RFE_READ_FIFO_MASK_;
324874a78a00SRaju Lakkaraju misc_ctl |= FIELD_PREP(MISC_CTL_0_RFE_READ_FIFO_MASK_,
324974a78a00SRaju Lakkaraju RFE_RD_FIFO_TH_3_DWORDS);
325074a78a00SRaju Lakkaraju lan743x_csr_write(adapter, MISC_CTL_0, misc_ctl);
325174a78a00SRaju Lakkaraju }
325274a78a00SRaju Lakkaraju }
325374a78a00SRaju Lakkaraju
lan743x_hardware_init(struct lan743x_adapter * adapter,struct pci_dev * pdev)325423f0703cSBryan Whitehead static int lan743x_hardware_init(struct lan743x_adapter *adapter,
325523f0703cSBryan Whitehead struct pci_dev *pdev)
325623f0703cSBryan Whitehead {
325723f0703cSBryan Whitehead struct lan743x_tx *tx;
325823f0703cSBryan Whitehead int index;
325923f0703cSBryan Whitehead int ret;
326023f0703cSBryan Whitehead
3261cf9aaea8SRaju Lakkaraju adapter->is_pci11x1x = is_pci11x1x_chip(adapter);
3262cf9aaea8SRaju Lakkaraju if (adapter->is_pci11x1x) {
3263cf9aaea8SRaju Lakkaraju adapter->max_tx_channels = PCI11X1X_MAX_TX_CHANNELS;
3264cf9aaea8SRaju Lakkaraju adapter->used_tx_channels = PCI11X1X_USED_TX_CHANNELS;
3265ac16b6ebSRaju Lakkaraju adapter->max_vector_count = PCI11X1X_MAX_VECTOR_COUNT;
3266a46d9d37SRaju Lakkaraju pci11x1x_strap_get_status(adapter);
3267cdea83ccSRaju Lakkaraju spin_lock_init(&adapter->eth_syslock_spinlock);
326846b777adSRaju Lakkaraju mutex_init(&adapter->sgmii_rw_lock);
326974a78a00SRaju Lakkaraju pci11x1x_set_rfe_rd_fifo_threshold(adapter);
3270cf9aaea8SRaju Lakkaraju } else {
3271cf9aaea8SRaju Lakkaraju adapter->max_tx_channels = LAN743X_MAX_TX_CHANNELS;
3272cf9aaea8SRaju Lakkaraju adapter->used_tx_channels = LAN743X_USED_TX_CHANNELS;
3273ac16b6ebSRaju Lakkaraju adapter->max_vector_count = LAN743X_MAX_VECTOR_COUNT;
3274cf9aaea8SRaju Lakkaraju }
3275cf9aaea8SRaju Lakkaraju
327623f0703cSBryan Whitehead adapter->intr.irq = adapter->pdev->irq;
327723f0703cSBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR, 0xFFFFFFFF);
327807624df1SBryan Whitehead
327907624df1SBryan Whitehead ret = lan743x_gpio_init(adapter);
328007624df1SBryan Whitehead if (ret)
328107624df1SBryan Whitehead return ret;
328207624df1SBryan Whitehead
328323f0703cSBryan Whitehead ret = lan743x_mac_init(adapter);
328423f0703cSBryan Whitehead if (ret)
328523f0703cSBryan Whitehead return ret;
328623f0703cSBryan Whitehead
328723f0703cSBryan Whitehead ret = lan743x_phy_init(adapter);
328823f0703cSBryan Whitehead if (ret)
328923f0703cSBryan Whitehead return ret;
329023f0703cSBryan Whitehead
329107624df1SBryan Whitehead ret = lan743x_ptp_init(adapter);
329207624df1SBryan Whitehead if (ret)
329307624df1SBryan Whitehead return ret;
329407624df1SBryan Whitehead
329523f0703cSBryan Whitehead lan743x_rfe_update_mac_address(adapter);
329623f0703cSBryan Whitehead
329723f0703cSBryan Whitehead ret = lan743x_dmac_init(adapter);
329823f0703cSBryan Whitehead if (ret)
329923f0703cSBryan Whitehead return ret;
330023f0703cSBryan Whitehead
330123f0703cSBryan Whitehead for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) {
330223f0703cSBryan Whitehead adapter->rx[index].adapter = adapter;
330323f0703cSBryan Whitehead adapter->rx[index].channel_number = index;
330423f0703cSBryan Whitehead }
330523f0703cSBryan Whitehead
3306cf9aaea8SRaju Lakkaraju for (index = 0; index < adapter->used_tx_channels; index++) {
3307cf9aaea8SRaju Lakkaraju tx = &adapter->tx[index];
330823f0703cSBryan Whitehead tx->adapter = adapter;
3309cf9aaea8SRaju Lakkaraju tx->channel_number = index;
331023f0703cSBryan Whitehead spin_lock_init(&tx->ring_lock);
3311cf9aaea8SRaju Lakkaraju }
3312cf9aaea8SRaju Lakkaraju
331323f0703cSBryan Whitehead return 0;
331423f0703cSBryan Whitehead }
331523f0703cSBryan Whitehead
lan743x_mdiobus_init(struct lan743x_adapter * adapter)331623f0703cSBryan Whitehead static int lan743x_mdiobus_init(struct lan743x_adapter *adapter)
331723f0703cSBryan Whitehead {
3318a46d9d37SRaju Lakkaraju u32 sgmii_ctl;
331923f0703cSBryan Whitehead int ret;
332023f0703cSBryan Whitehead
332123f0703cSBryan Whitehead adapter->mdiobus = devm_mdiobus_alloc(&adapter->pdev->dev);
332223f0703cSBryan Whitehead if (!(adapter->mdiobus)) {
332323f0703cSBryan Whitehead ret = -ENOMEM;
332423f0703cSBryan Whitehead goto return_error;
332523f0703cSBryan Whitehead }
332623f0703cSBryan Whitehead
332723f0703cSBryan Whitehead adapter->mdiobus->priv = (void *)adapter;
3328a46d9d37SRaju Lakkaraju if (adapter->is_pci11x1x) {
3329a46d9d37SRaju Lakkaraju if (adapter->is_sgmii_en) {
3330a46d9d37SRaju Lakkaraju sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
3331a46d9d37SRaju Lakkaraju sgmii_ctl |= SGMII_CTL_SGMII_ENABLE_;
3332a46d9d37SRaju Lakkaraju sgmii_ctl &= ~SGMII_CTL_SGMII_POWER_DN_;
3333a46d9d37SRaju Lakkaraju lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl);
3334a46d9d37SRaju Lakkaraju netif_dbg(adapter, drv, adapter->netdev,
3335a46d9d37SRaju Lakkaraju "SGMII operation\n");
33363d90c03cSAndrew Lunn adapter->mdiobus->read = lan743x_mdiobus_read_c22;
33373d90c03cSAndrew Lunn adapter->mdiobus->write = lan743x_mdiobus_write_c22;
33383d90c03cSAndrew Lunn adapter->mdiobus->read_c45 = lan743x_mdiobus_read_c45;
33393d90c03cSAndrew Lunn adapter->mdiobus->write_c45 = lan743x_mdiobus_write_c45;
334079dfeb29SRaju Lakkaraju adapter->mdiobus->name = "lan743x-mdiobus-c45";
334179dfeb29SRaju Lakkaraju netif_dbg(adapter, drv, adapter->netdev,
334279dfeb29SRaju Lakkaraju "lan743x-mdiobus-c45\n");
3343a46d9d37SRaju Lakkaraju } else {
3344a46d9d37SRaju Lakkaraju sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
3345a46d9d37SRaju Lakkaraju sgmii_ctl &= ~SGMII_CTL_SGMII_ENABLE_;
3346a46d9d37SRaju Lakkaraju sgmii_ctl |= SGMII_CTL_SGMII_POWER_DN_;
3347a46d9d37SRaju Lakkaraju lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl);
3348a46d9d37SRaju Lakkaraju netif_dbg(adapter, drv, adapter->netdev,
334979dfeb29SRaju Lakkaraju "RGMII operation\n");
335079dfeb29SRaju Lakkaraju // Only C22 support when RGMII I/F
33513d90c03cSAndrew Lunn adapter->mdiobus->read = lan743x_mdiobus_read_c22;
33523d90c03cSAndrew Lunn adapter->mdiobus->write = lan743x_mdiobus_write_c22;
335379dfeb29SRaju Lakkaraju adapter->mdiobus->name = "lan743x-mdiobus";
335479dfeb29SRaju Lakkaraju netif_dbg(adapter, drv, adapter->netdev,
335579dfeb29SRaju Lakkaraju "lan743x-mdiobus\n");
3356a46d9d37SRaju Lakkaraju }
3357a2ab95a3SRaju Lakkaraju } else {
33583d90c03cSAndrew Lunn adapter->mdiobus->read = lan743x_mdiobus_read_c22;
33593d90c03cSAndrew Lunn adapter->mdiobus->write = lan743x_mdiobus_write_c22;
336023f0703cSBryan Whitehead adapter->mdiobus->name = "lan743x-mdiobus";
3361a2ab95a3SRaju Lakkaraju netif_dbg(adapter, drv, adapter->netdev, "lan743x-mdiobus\n");
3362a2ab95a3SRaju Lakkaraju }
3363a2ab95a3SRaju Lakkaraju
336423f0703cSBryan Whitehead snprintf(adapter->mdiobus->id, MII_BUS_ID_SIZE,
336523f0703cSBryan Whitehead "pci-%s", pci_name(adapter->pdev));
336623f0703cSBryan Whitehead
33670db7d253SBryan Whitehead if ((adapter->csr.id_rev & ID_REV_ID_MASK_) == ID_REV_ID_LAN7430_)
33680db7d253SBryan Whitehead /* LAN7430 uses internal phy at address 1 */
336923f0703cSBryan Whitehead adapter->mdiobus->phy_mask = ~(u32)BIT(1);
337023f0703cSBryan Whitehead
337123f0703cSBryan Whitehead /* register mdiobus */
337223f0703cSBryan Whitehead ret = mdiobus_register(adapter->mdiobus);
337323f0703cSBryan Whitehead if (ret < 0)
337423f0703cSBryan Whitehead goto return_error;
337523f0703cSBryan Whitehead return 0;
337623f0703cSBryan Whitehead
337723f0703cSBryan Whitehead return_error:
337823f0703cSBryan Whitehead return ret;
337923f0703cSBryan Whitehead }
338023f0703cSBryan Whitehead
338123f0703cSBryan Whitehead /* lan743x_pcidev_probe - Device Initialization Routine
338223f0703cSBryan Whitehead * @pdev: PCI device information struct
338323f0703cSBryan Whitehead * @id: entry in lan743x_pci_tbl
338423f0703cSBryan Whitehead *
338523f0703cSBryan Whitehead * Returns 0 on success, negative on failure
338623f0703cSBryan Whitehead *
338723f0703cSBryan Whitehead * initializes an adapter identified by a pci_dev structure.
338823f0703cSBryan Whitehead * The OS initialization, configuring of the adapter private structure,
338923f0703cSBryan Whitehead * and a hardware reset occur.
339023f0703cSBryan Whitehead **/
lan743x_pcidev_probe(struct pci_dev * pdev,const struct pci_device_id * id)339123f0703cSBryan Whitehead static int lan743x_pcidev_probe(struct pci_dev *pdev,
339223f0703cSBryan Whitehead const struct pci_device_id *id)
339323f0703cSBryan Whitehead {
339423f0703cSBryan Whitehead struct lan743x_adapter *adapter = NULL;
339523f0703cSBryan Whitehead struct net_device *netdev = NULL;
339623f0703cSBryan Whitehead int ret = -ENODEV;
339723f0703cSBryan Whitehead
3398cf9aaea8SRaju Lakkaraju if (id->device == PCI_DEVICE_ID_SMSC_A011 ||
3399cf9aaea8SRaju Lakkaraju id->device == PCI_DEVICE_ID_SMSC_A041) {
3400cf9aaea8SRaju Lakkaraju netdev = devm_alloc_etherdev_mqs(&pdev->dev,
3401cf9aaea8SRaju Lakkaraju sizeof(struct lan743x_adapter),
3402cf9aaea8SRaju Lakkaraju PCI11X1X_USED_TX_CHANNELS,
3403cf9aaea8SRaju Lakkaraju LAN743X_USED_RX_CHANNELS);
3404cf9aaea8SRaju Lakkaraju } else {
3405721f80c4SRaju Lakkaraju netdev = devm_alloc_etherdev_mqs(&pdev->dev,
3406721f80c4SRaju Lakkaraju sizeof(struct lan743x_adapter),
3407721f80c4SRaju Lakkaraju LAN743X_USED_TX_CHANNELS,
3408721f80c4SRaju Lakkaraju LAN743X_USED_RX_CHANNELS);
3409cf9aaea8SRaju Lakkaraju }
3410cf9aaea8SRaju Lakkaraju
341123f0703cSBryan Whitehead if (!netdev)
341223f0703cSBryan Whitehead goto return_error;
341323f0703cSBryan Whitehead
341423f0703cSBryan Whitehead SET_NETDEV_DEV(netdev, &pdev->dev);
341523f0703cSBryan Whitehead pci_set_drvdata(pdev, netdev);
341623f0703cSBryan Whitehead adapter = netdev_priv(netdev);
341723f0703cSBryan Whitehead adapter->netdev = netdev;
341823f0703cSBryan Whitehead adapter->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE |
341923f0703cSBryan Whitehead NETIF_MSG_LINK | NETIF_MSG_IFUP |
342023f0703cSBryan Whitehead NETIF_MSG_IFDOWN | NETIF_MSG_TX_QUEUED;
342123f0703cSBryan Whitehead netdev->max_mtu = LAN743X_MAX_FRAME_SIZE;
342223f0703cSBryan Whitehead
342383216e39SMichael Walle of_get_mac_address(pdev->dev.of_node, adapter->mac_address);
3424c90834cdSTim Harvey
342523f0703cSBryan Whitehead ret = lan743x_pci_init(adapter, pdev);
342623f0703cSBryan Whitehead if (ret)
342723f0703cSBryan Whitehead goto return_error;
342823f0703cSBryan Whitehead
342923f0703cSBryan Whitehead ret = lan743x_csr_init(adapter);
343023f0703cSBryan Whitehead if (ret)
343123f0703cSBryan Whitehead goto cleanup_pci;
343223f0703cSBryan Whitehead
343323f0703cSBryan Whitehead ret = lan743x_hardware_init(adapter, pdev);
343423f0703cSBryan Whitehead if (ret)
343523f0703cSBryan Whitehead goto cleanup_pci;
343623f0703cSBryan Whitehead
343723f0703cSBryan Whitehead ret = lan743x_mdiobus_init(adapter);
343823f0703cSBryan Whitehead if (ret)
343923f0703cSBryan Whitehead goto cleanup_hardware;
344023f0703cSBryan Whitehead
344123f0703cSBryan Whitehead adapter->netdev->netdev_ops = &lan743x_netdev_ops;
34420cf63226SBryan Whitehead adapter->netdev->ethtool_ops = &lan743x_ethtool_ops;
3443cd691050SRaju Lakkaraju adapter->netdev->features = NETIF_F_SG | NETIF_F_TSO |
3444cd691050SRaju Lakkaraju NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
344523f0703cSBryan Whitehead adapter->netdev->hw_features = adapter->netdev->features;
344623f0703cSBryan Whitehead
344723f0703cSBryan Whitehead /* carrier off reporting is important to ethtool even BEFORE open */
344823f0703cSBryan Whitehead netif_carrier_off(netdev);
344923f0703cSBryan Whitehead
345023f0703cSBryan Whitehead ret = register_netdev(adapter->netdev);
345123f0703cSBryan Whitehead if (ret < 0)
345223f0703cSBryan Whitehead goto cleanup_mdiobus;
345323f0703cSBryan Whitehead return 0;
345423f0703cSBryan Whitehead
345523f0703cSBryan Whitehead cleanup_mdiobus:
345623f0703cSBryan Whitehead lan743x_mdiobus_cleanup(adapter);
345723f0703cSBryan Whitehead
345823f0703cSBryan Whitehead cleanup_hardware:
345923f0703cSBryan Whitehead lan743x_hardware_cleanup(adapter);
346023f0703cSBryan Whitehead
346123f0703cSBryan Whitehead cleanup_pci:
346223f0703cSBryan Whitehead lan743x_pci_cleanup(adapter);
346323f0703cSBryan Whitehead
346423f0703cSBryan Whitehead return_error:
346523f0703cSBryan Whitehead pr_warn("Initialization failed\n");
346623f0703cSBryan Whitehead return ret;
346723f0703cSBryan Whitehead }
346823f0703cSBryan Whitehead
346923f0703cSBryan Whitehead /**
347023f0703cSBryan Whitehead * lan743x_pcidev_remove - Device Removal Routine
347123f0703cSBryan Whitehead * @pdev: PCI device information struct
347223f0703cSBryan Whitehead *
347323f0703cSBryan Whitehead * this is called by the PCI subsystem to alert the driver
347423f0703cSBryan Whitehead * that it should release a PCI device. This could be caused by a
347523f0703cSBryan Whitehead * Hot-Plug event, or because the driver is going to be removed from
347623f0703cSBryan Whitehead * memory.
347723f0703cSBryan Whitehead **/
lan743x_pcidev_remove(struct pci_dev * pdev)347823f0703cSBryan Whitehead static void lan743x_pcidev_remove(struct pci_dev *pdev)
347923f0703cSBryan Whitehead {
348023f0703cSBryan Whitehead struct net_device *netdev = pci_get_drvdata(pdev);
348123f0703cSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
348223f0703cSBryan Whitehead
348323f0703cSBryan Whitehead lan743x_full_cleanup(adapter);
348423f0703cSBryan Whitehead }
348523f0703cSBryan Whitehead
lan743x_pcidev_shutdown(struct pci_dev * pdev)348623f0703cSBryan Whitehead static void lan743x_pcidev_shutdown(struct pci_dev *pdev)
348723f0703cSBryan Whitehead {
348823f0703cSBryan Whitehead struct net_device *netdev = pci_get_drvdata(pdev);
348923f0703cSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
349023f0703cSBryan Whitehead
349123f0703cSBryan Whitehead rtnl_lock();
349223f0703cSBryan Whitehead netif_device_detach(netdev);
349323f0703cSBryan Whitehead
349423f0703cSBryan Whitehead /* close netdev when netdev is at running state.
349523f0703cSBryan Whitehead * For instance, it is true when system goes to sleep by pm-suspend
349623f0703cSBryan Whitehead * However, it is false when system goes to sleep by suspend GUI menu
349723f0703cSBryan Whitehead */
349823f0703cSBryan Whitehead if (netif_running(netdev))
349923f0703cSBryan Whitehead lan743x_netdev_close(netdev);
350023f0703cSBryan Whitehead rtnl_unlock();
350123f0703cSBryan Whitehead
35024d94282aSBryan Whitehead #ifdef CONFIG_PM
35034d94282aSBryan Whitehead pci_save_state(pdev);
35044d94282aSBryan Whitehead #endif
35054d94282aSBryan Whitehead
350623f0703cSBryan Whitehead /* clean up lan743x portion */
350723f0703cSBryan Whitehead lan743x_hardware_cleanup(adapter);
350823f0703cSBryan Whitehead }
350923f0703cSBryan Whitehead
3510c7348091Szhong jiang #ifdef CONFIG_PM_SLEEP
lan743x_pm_wakeframe_crc16(const u8 * buf,int len)35114d94282aSBryan Whitehead static u16 lan743x_pm_wakeframe_crc16(const u8 *buf, int len)
35124d94282aSBryan Whitehead {
35134d94282aSBryan Whitehead return bitrev16(crc16(0xFFFF, buf, len));
35144d94282aSBryan Whitehead }
35154d94282aSBryan Whitehead
lan743x_pm_set_wol(struct lan743x_adapter * adapter)35164d94282aSBryan Whitehead static void lan743x_pm_set_wol(struct lan743x_adapter *adapter)
35174d94282aSBryan Whitehead {
35184d94282aSBryan Whitehead const u8 ipv4_multicast[3] = { 0x01, 0x00, 0x5E };
35194d94282aSBryan Whitehead const u8 ipv6_multicast[3] = { 0x33, 0x33 };
35204d94282aSBryan Whitehead const u8 arp_type[2] = { 0x08, 0x06 };
35214d94282aSBryan Whitehead int mask_index;
35226b3768acSRaju Lakkaraju u32 sopass;
35234d94282aSBryan Whitehead u32 pmtctl;
35244d94282aSBryan Whitehead u32 wucsr;
35254d94282aSBryan Whitehead u32 macrx;
35264d94282aSBryan Whitehead u16 crc;
35274d94282aSBryan Whitehead
35284d94282aSBryan Whitehead for (mask_index = 0; mask_index < MAC_NUM_OF_WUF_CFG; mask_index++)
35294d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index), 0);
35304d94282aSBryan Whitehead
35314d94282aSBryan Whitehead /* clear wake settings */
35324d94282aSBryan Whitehead pmtctl = lan743x_csr_read(adapter, PMT_CTL);
353341805c46SRaju Lakkaraju pmtctl |= PMT_CTL_WUPS_MASK_ | PMT_CTL_RES_CLR_WKP_MASK_;
35344d94282aSBryan Whitehead pmtctl &= ~(PMT_CTL_GPIO_WAKEUP_EN_ | PMT_CTL_EEE_WAKEUP_EN_ |
35354d94282aSBryan Whitehead PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_ |
35364d94282aSBryan Whitehead PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_ | PMT_CTL_ETH_PHY_WAKE_EN_);
35374d94282aSBryan Whitehead
35384d94282aSBryan Whitehead macrx = lan743x_csr_read(adapter, MAC_RX);
35394d94282aSBryan Whitehead
35404d94282aSBryan Whitehead wucsr = 0;
35414d94282aSBryan Whitehead mask_index = 0;
35424d94282aSBryan Whitehead
35434d94282aSBryan Whitehead pmtctl |= PMT_CTL_ETH_PHY_D3_COLD_OVR_ | PMT_CTL_ETH_PHY_D3_OVR_;
35444d94282aSBryan Whitehead
3545*de4fc109SRaju Lakkaraju if (adapter->phy_wolopts)
35464d94282aSBryan Whitehead pmtctl |= PMT_CTL_ETH_PHY_WAKE_EN_;
3547*de4fc109SRaju Lakkaraju
35484d94282aSBryan Whitehead if (adapter->wolopts & WAKE_MAGIC) {
35494d94282aSBryan Whitehead wucsr |= MAC_WUCSR_MPEN_;
35504d94282aSBryan Whitehead macrx |= MAC_RX_RXEN_;
35514d94282aSBryan Whitehead pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
35524d94282aSBryan Whitehead }
35534d94282aSBryan Whitehead if (adapter->wolopts & WAKE_UCAST) {
35544d94282aSBryan Whitehead wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_PFDA_EN_;
35554d94282aSBryan Whitehead macrx |= MAC_RX_RXEN_;
35564d94282aSBryan Whitehead pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
35574d94282aSBryan Whitehead pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_;
35584d94282aSBryan Whitehead }
35594d94282aSBryan Whitehead if (adapter->wolopts & WAKE_BCAST) {
35604d94282aSBryan Whitehead wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_BCST_EN_;
35614d94282aSBryan Whitehead macrx |= MAC_RX_RXEN_;
35624d94282aSBryan Whitehead pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
35634d94282aSBryan Whitehead pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_;
35644d94282aSBryan Whitehead }
35654d94282aSBryan Whitehead if (adapter->wolopts & WAKE_MCAST) {
35664d94282aSBryan Whitehead /* IPv4 multicast */
35674d94282aSBryan Whitehead crc = lan743x_pm_wakeframe_crc16(ipv4_multicast, 3);
35684d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index),
35694d94282aSBryan Whitehead MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_MCAST_ |
35704d94282aSBryan Whitehead (0 << MAC_WUF_CFG_OFFSET_SHIFT_) |
35714d94282aSBryan Whitehead (crc & MAC_WUF_CFG_CRC16_MASK_));
35724d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 7);
35734d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0);
35744d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0);
35754d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0);
35764d94282aSBryan Whitehead mask_index++;
35774d94282aSBryan Whitehead
35784d94282aSBryan Whitehead /* IPv6 multicast */
35794d94282aSBryan Whitehead crc = lan743x_pm_wakeframe_crc16(ipv6_multicast, 2);
35804d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index),
35814d94282aSBryan Whitehead MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_MCAST_ |
35824d94282aSBryan Whitehead (0 << MAC_WUF_CFG_OFFSET_SHIFT_) |
35834d94282aSBryan Whitehead (crc & MAC_WUF_CFG_CRC16_MASK_));
35844d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 3);
35854d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0);
35864d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0);
35874d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0);
35884d94282aSBryan Whitehead mask_index++;
35894d94282aSBryan Whitehead
35904d94282aSBryan Whitehead wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_WAKE_EN_;
35914d94282aSBryan Whitehead macrx |= MAC_RX_RXEN_;
35924d94282aSBryan Whitehead pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
35934d94282aSBryan Whitehead pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_;
35944d94282aSBryan Whitehead }
35954d94282aSBryan Whitehead if (adapter->wolopts & WAKE_ARP) {
35964d94282aSBryan Whitehead /* set MAC_WUF_CFG & WUF_MASK
35974d94282aSBryan Whitehead * for packettype (offset 12,13) = ARP (0x0806)
35984d94282aSBryan Whitehead */
35994d94282aSBryan Whitehead crc = lan743x_pm_wakeframe_crc16(arp_type, 2);
36004d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index),
36014d94282aSBryan Whitehead MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_ALL_ |
36024d94282aSBryan Whitehead (0 << MAC_WUF_CFG_OFFSET_SHIFT_) |
36034d94282aSBryan Whitehead (crc & MAC_WUF_CFG_CRC16_MASK_));
36044d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 0x3000);
36054d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0);
36064d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0);
36074d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0);
36084d94282aSBryan Whitehead mask_index++;
36094d94282aSBryan Whitehead
36104d94282aSBryan Whitehead wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_WAKE_EN_;
36114d94282aSBryan Whitehead macrx |= MAC_RX_RXEN_;
36124d94282aSBryan Whitehead pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
36134d94282aSBryan Whitehead pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_;
36144d94282aSBryan Whitehead }
36154d94282aSBryan Whitehead
36166b3768acSRaju Lakkaraju if (adapter->wolopts & WAKE_MAGICSECURE) {
36176b3768acSRaju Lakkaraju sopass = *(u32 *)adapter->sopass;
36186b3768acSRaju Lakkaraju lan743x_csr_write(adapter, MAC_MP_SO_LO, sopass);
36196b3768acSRaju Lakkaraju sopass = *(u16 *)&adapter->sopass[4];
36206b3768acSRaju Lakkaraju lan743x_csr_write(adapter, MAC_MP_SO_HI, sopass);
36216b3768acSRaju Lakkaraju wucsr |= MAC_MP_SO_EN_;
36226b3768acSRaju Lakkaraju }
36236b3768acSRaju Lakkaraju
36244d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUCSR, wucsr);
36254d94282aSBryan Whitehead lan743x_csr_write(adapter, PMT_CTL, pmtctl);
36264d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_RX, macrx);
36274d94282aSBryan Whitehead }
36284d94282aSBryan Whitehead
lan743x_pm_suspend(struct device * dev)36294d94282aSBryan Whitehead static int lan743x_pm_suspend(struct device *dev)
36304d94282aSBryan Whitehead {
36314d94282aSBryan Whitehead struct pci_dev *pdev = to_pci_dev(dev);
36324d94282aSBryan Whitehead struct net_device *netdev = pci_get_drvdata(pdev);
36334d94282aSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
36346b3768acSRaju Lakkaraju u32 data;
36354d94282aSBryan Whitehead
36364d94282aSBryan Whitehead lan743x_pcidev_shutdown(pdev);
36374d94282aSBryan Whitehead
36384d94282aSBryan Whitehead /* clear all wakes */
36394d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUCSR, 0);
36404d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WUCSR2, 0);
36414d94282aSBryan Whitehead lan743x_csr_write(adapter, MAC_WK_SRC, 0xFFFFFFFF);
36424d94282aSBryan Whitehead
3643*de4fc109SRaju Lakkaraju if (adapter->wolopts || adapter->phy_wolopts)
36444d94282aSBryan Whitehead lan743x_pm_set_wol(adapter);
36454d94282aSBryan Whitehead
36466b3768acSRaju Lakkaraju if (adapter->is_pci11x1x) {
36476b3768acSRaju Lakkaraju /* Save HW_CFG to config again in PM resume */
36486b3768acSRaju Lakkaraju data = lan743x_csr_read(adapter, HW_CFG);
36496b3768acSRaju Lakkaraju adapter->hw_cfg = data;
36506b3768acSRaju Lakkaraju data |= (HW_CFG_RST_PROTECT_PCIE_ |
36516b3768acSRaju Lakkaraju HW_CFG_D3_RESET_DIS_ |
36526b3768acSRaju Lakkaraju HW_CFG_D3_VAUX_OVR_ |
36536b3768acSRaju Lakkaraju HW_CFG_HOT_RESET_DIS_ |
36546b3768acSRaju Lakkaraju HW_CFG_RST_PROTECT_);
36556b3768acSRaju Lakkaraju lan743x_csr_write(adapter, HW_CFG, data);
36566b3768acSRaju Lakkaraju }
36576b3768acSRaju Lakkaraju
36584d94282aSBryan Whitehead /* Host sets PME_En, put D3hot */
3659e228c0deSYang Yingliang return pci_prepare_to_sleep(pdev);
36604d94282aSBryan Whitehead }
36614d94282aSBryan Whitehead
lan743x_pm_resume(struct device * dev)36624d94282aSBryan Whitehead static int lan743x_pm_resume(struct device *dev)
36634d94282aSBryan Whitehead {
36644d94282aSBryan Whitehead struct pci_dev *pdev = to_pci_dev(dev);
36654d94282aSBryan Whitehead struct net_device *netdev = pci_get_drvdata(pdev);
36664d94282aSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
366741805c46SRaju Lakkaraju u32 data;
36684d94282aSBryan Whitehead int ret;
36694d94282aSBryan Whitehead
36704d94282aSBryan Whitehead pci_set_power_state(pdev, PCI_D0);
36714d94282aSBryan Whitehead pci_restore_state(pdev);
36724d94282aSBryan Whitehead pci_save_state(pdev);
36734d94282aSBryan Whitehead
36746b3768acSRaju Lakkaraju /* Restore HW_CFG that was saved during pm suspend */
36756b3768acSRaju Lakkaraju if (adapter->is_pci11x1x)
36766b3768acSRaju Lakkaraju lan743x_csr_write(adapter, HW_CFG, adapter->hw_cfg);
36776b3768acSRaju Lakkaraju
36784d94282aSBryan Whitehead ret = lan743x_hardware_init(adapter, pdev);
36794d94282aSBryan Whitehead if (ret) {
36804d94282aSBryan Whitehead netif_err(adapter, probe, adapter->netdev,
36814d94282aSBryan Whitehead "lan743x_hardware_init returned %d\n", ret);
3682d6423d2eSYuiko Oshino lan743x_pci_cleanup(adapter);
3683d6423d2eSYuiko Oshino return ret;
36844d94282aSBryan Whitehead }
36854d94282aSBryan Whitehead
368641805c46SRaju Lakkaraju ret = lan743x_csr_read(adapter, MAC_WK_SRC);
368741805c46SRaju Lakkaraju netif_dbg(adapter, drv, adapter->netdev,
368841805c46SRaju Lakkaraju "Wakeup source : 0x%08X\n", ret);
368941805c46SRaju Lakkaraju
369041805c46SRaju Lakkaraju /* Clear the wol configuration and status bits. Note that
369141805c46SRaju Lakkaraju * the status bits are "Write One to Clear (W1C)"
369241805c46SRaju Lakkaraju */
369341805c46SRaju Lakkaraju data = MAC_WUCSR_EEE_TX_WAKE_ | MAC_WUCSR_EEE_RX_WAKE_ |
369441805c46SRaju Lakkaraju MAC_WUCSR_RFE_WAKE_FR_ | MAC_WUCSR_PFDA_FR_ | MAC_WUCSR_WUFR_ |
369541805c46SRaju Lakkaraju MAC_WUCSR_MPR_ | MAC_WUCSR_BCAST_FR_;
369641805c46SRaju Lakkaraju lan743x_csr_write(adapter, MAC_WUCSR, data);
369741805c46SRaju Lakkaraju
369841805c46SRaju Lakkaraju data = MAC_WUCSR2_NS_RCD_ | MAC_WUCSR2_ARP_RCD_ |
369941805c46SRaju Lakkaraju MAC_WUCSR2_IPV6_TCPSYN_RCD_ | MAC_WUCSR2_IPV4_TCPSYN_RCD_;
370041805c46SRaju Lakkaraju lan743x_csr_write(adapter, MAC_WUCSR2, data);
370141805c46SRaju Lakkaraju
370241805c46SRaju Lakkaraju data = MAC_WK_SRC_ETH_PHY_WK_ | MAC_WK_SRC_IPV6_TCPSYN_RCD_WK_ |
370341805c46SRaju Lakkaraju MAC_WK_SRC_IPV4_TCPSYN_RCD_WK_ | MAC_WK_SRC_EEE_TX_WK_ |
370441805c46SRaju Lakkaraju MAC_WK_SRC_EEE_RX_WK_ | MAC_WK_SRC_RFE_FR_WK_ |
370541805c46SRaju Lakkaraju MAC_WK_SRC_PFDA_FR_WK_ | MAC_WK_SRC_MP_FR_WK_ |
370641805c46SRaju Lakkaraju MAC_WK_SRC_BCAST_FR_WK_ | MAC_WK_SRC_WU_FR_WK_ |
370741805c46SRaju Lakkaraju MAC_WK_SRC_WK_FR_SAVED_;
370841805c46SRaju Lakkaraju lan743x_csr_write(adapter, MAC_WK_SRC, data);
370941805c46SRaju Lakkaraju
37104d94282aSBryan Whitehead /* open netdev when netdev is at running state while resume.
37114d94282aSBryan Whitehead * For instance, it is true when system wakesup after pm-suspend
37124d94282aSBryan Whitehead * However, it is false when system wakes up after suspend GUI menu
37134d94282aSBryan Whitehead */
37144d94282aSBryan Whitehead if (netif_running(netdev))
37154d94282aSBryan Whitehead lan743x_netdev_open(netdev);
37164d94282aSBryan Whitehead
37174d94282aSBryan Whitehead netif_device_attach(netdev);
37184d94282aSBryan Whitehead
37194d94282aSBryan Whitehead return 0;
37204d94282aSBryan Whitehead }
37214d94282aSBryan Whitehead
372241147bb1SWei Yongjun static const struct dev_pm_ops lan743x_pm_ops = {
37234d94282aSBryan Whitehead SET_SYSTEM_SLEEP_PM_OPS(lan743x_pm_suspend, lan743x_pm_resume)
37244d94282aSBryan Whitehead };
3725c7348091Szhong jiang #endif /* CONFIG_PM_SLEEP */
37264d94282aSBryan Whitehead
372723f0703cSBryan Whitehead static const struct pci_device_id lan743x_pcidev_tbl[] = {
372823f0703cSBryan Whitehead { PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_LAN7430) },
37294df5ce9bSBryan Whitehead { PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_LAN7431) },
3730bb4f6bffSRaju Lakkaraju { PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_A011) },
3731bb4f6bffSRaju Lakkaraju { PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_A041) },
373223f0703cSBryan Whitehead { 0, }
373323f0703cSBryan Whitehead };
373423f0703cSBryan Whitehead
3735ea12fe9dSTim Harvey MODULE_DEVICE_TABLE(pci, lan743x_pcidev_tbl);
3736ea12fe9dSTim Harvey
373723f0703cSBryan Whitehead static struct pci_driver lan743x_pcidev_driver = {
373823f0703cSBryan Whitehead .name = DRIVER_NAME,
373923f0703cSBryan Whitehead .id_table = lan743x_pcidev_tbl,
374023f0703cSBryan Whitehead .probe = lan743x_pcidev_probe,
374123f0703cSBryan Whitehead .remove = lan743x_pcidev_remove,
3742c7348091Szhong jiang #ifdef CONFIG_PM_SLEEP
37434d94282aSBryan Whitehead .driver.pm = &lan743x_pm_ops,
37444d94282aSBryan Whitehead #endif
374523f0703cSBryan Whitehead .shutdown = lan743x_pcidev_shutdown,
374623f0703cSBryan Whitehead };
374723f0703cSBryan Whitehead
374823f0703cSBryan Whitehead module_pci_driver(lan743x_pcidev_driver);
374923f0703cSBryan Whitehead
375023f0703cSBryan Whitehead MODULE_AUTHOR(DRIVER_AUTHOR);
375123f0703cSBryan Whitehead MODULE_DESCRIPTION(DRIVER_DESC);
375223f0703cSBryan Whitehead MODULE_LICENSE("GPL");
3753