18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright(c) 2007 Atheros Corporation. All rights reserved.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Derived from Intel e1000 driver
68c2ecf20Sopenharmony_ci * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "atl1e.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cichar atl1e_driver_name[] = "ATL1E";
128c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_ATTANSIC_L1E      0x1026
138c2ecf20Sopenharmony_ci/*
148c2ecf20Sopenharmony_ci * atl1e_pci_tbl - PCI Device ID Table
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Wildcard entries (PCI_ANY_ID) should come last
178c2ecf20Sopenharmony_ci * Last entry must be all 0s
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
208c2ecf20Sopenharmony_ci *   Class, Class Mask, private data (not used) }
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_cistatic const struct pci_device_id atl1e_pci_tbl[] = {
238c2ecf20Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1E)},
248c2ecf20Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1066)},
258c2ecf20Sopenharmony_ci	/* required last entry */
268c2ecf20Sopenharmony_ci	{ 0 }
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, atl1e_pci_tbl);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ciMODULE_AUTHOR("Atheros Corporation, <xiong.huang@atheros.com>, Jie Yang <jie.yang@atheros.com>");
318c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Atheros 1000M Ethernet Network Driver");
328c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic const u16
378c2ecf20Sopenharmony_ciatl1e_rx_page_vld_regs[AT_MAX_RECEIVE_QUEUE][AT_PAGE_NUM_PER_QUEUE] =
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	{REG_HOST_RXF0_PAGE0_VLD, REG_HOST_RXF0_PAGE1_VLD},
408c2ecf20Sopenharmony_ci	{REG_HOST_RXF1_PAGE0_VLD, REG_HOST_RXF1_PAGE1_VLD},
418c2ecf20Sopenharmony_ci	{REG_HOST_RXF2_PAGE0_VLD, REG_HOST_RXF2_PAGE1_VLD},
428c2ecf20Sopenharmony_ci	{REG_HOST_RXF3_PAGE0_VLD, REG_HOST_RXF3_PAGE1_VLD}
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic const u16 atl1e_rx_page_hi_addr_regs[AT_MAX_RECEIVE_QUEUE] =
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	REG_RXF0_BASE_ADDR_HI,
488c2ecf20Sopenharmony_ci	REG_RXF1_BASE_ADDR_HI,
498c2ecf20Sopenharmony_ci	REG_RXF2_BASE_ADDR_HI,
508c2ecf20Sopenharmony_ci	REG_RXF3_BASE_ADDR_HI
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic const u16
548c2ecf20Sopenharmony_ciatl1e_rx_page_lo_addr_regs[AT_MAX_RECEIVE_QUEUE][AT_PAGE_NUM_PER_QUEUE] =
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	{REG_HOST_RXF0_PAGE0_LO, REG_HOST_RXF0_PAGE1_LO},
578c2ecf20Sopenharmony_ci	{REG_HOST_RXF1_PAGE0_LO, REG_HOST_RXF1_PAGE1_LO},
588c2ecf20Sopenharmony_ci	{REG_HOST_RXF2_PAGE0_LO, REG_HOST_RXF2_PAGE1_LO},
598c2ecf20Sopenharmony_ci	{REG_HOST_RXF3_PAGE0_LO, REG_HOST_RXF3_PAGE1_LO}
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic const u16
638c2ecf20Sopenharmony_ciatl1e_rx_page_write_offset_regs[AT_MAX_RECEIVE_QUEUE][AT_PAGE_NUM_PER_QUEUE] =
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	{REG_HOST_RXF0_MB0_LO,  REG_HOST_RXF0_MB1_LO},
668c2ecf20Sopenharmony_ci	{REG_HOST_RXF1_MB0_LO,  REG_HOST_RXF1_MB1_LO},
678c2ecf20Sopenharmony_ci	{REG_HOST_RXF2_MB0_LO,  REG_HOST_RXF2_MB1_LO},
688c2ecf20Sopenharmony_ci	{REG_HOST_RXF3_MB0_LO,  REG_HOST_RXF3_MB1_LO}
698c2ecf20Sopenharmony_ci};
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic const u16 atl1e_pay_load_size[] = {
728c2ecf20Sopenharmony_ci	128, 256, 512, 1024, 2048, 4096,
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/**
768c2ecf20Sopenharmony_ci * atl1e_irq_enable - Enable default interrupt generation settings
778c2ecf20Sopenharmony_ci * @adapter: board private structure
788c2ecf20Sopenharmony_ci */
798c2ecf20Sopenharmony_cistatic inline void atl1e_irq_enable(struct atl1e_adapter *adapter)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	if (likely(atomic_dec_and_test(&adapter->irq_sem))) {
828c2ecf20Sopenharmony_ci		AT_WRITE_REG(&adapter->hw, REG_ISR, 0);
838c2ecf20Sopenharmony_ci		AT_WRITE_REG(&adapter->hw, REG_IMR, IMR_NORMAL_MASK);
848c2ecf20Sopenharmony_ci		AT_WRITE_FLUSH(&adapter->hw);
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/**
898c2ecf20Sopenharmony_ci * atl1e_irq_disable - Mask off interrupt generation on the NIC
908c2ecf20Sopenharmony_ci * @adapter: board private structure
918c2ecf20Sopenharmony_ci */
928c2ecf20Sopenharmony_cistatic inline void atl1e_irq_disable(struct atl1e_adapter *adapter)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	atomic_inc(&adapter->irq_sem);
958c2ecf20Sopenharmony_ci	AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
968c2ecf20Sopenharmony_ci	AT_WRITE_FLUSH(&adapter->hw);
978c2ecf20Sopenharmony_ci	synchronize_irq(adapter->pdev->irq);
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/**
1018c2ecf20Sopenharmony_ci * atl1e_irq_reset - reset interrupt confiure on the NIC
1028c2ecf20Sopenharmony_ci * @adapter: board private structure
1038c2ecf20Sopenharmony_ci */
1048c2ecf20Sopenharmony_cistatic inline void atl1e_irq_reset(struct atl1e_adapter *adapter)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	atomic_set(&adapter->irq_sem, 0);
1078c2ecf20Sopenharmony_ci	AT_WRITE_REG(&adapter->hw, REG_ISR, 0);
1088c2ecf20Sopenharmony_ci	AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
1098c2ecf20Sopenharmony_ci	AT_WRITE_FLUSH(&adapter->hw);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/**
1138c2ecf20Sopenharmony_ci * atl1e_phy_config - Timer Call-back
1148c2ecf20Sopenharmony_ci * @t: timer list containing pointer to netdev cast into an unsigned long
1158c2ecf20Sopenharmony_ci */
1168c2ecf20Sopenharmony_cistatic void atl1e_phy_config(struct timer_list *t)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = from_timer(adapter, t,
1198c2ecf20Sopenharmony_ci						   phy_config_timer);
1208c2ecf20Sopenharmony_ci	struct atl1e_hw *hw = &adapter->hw;
1218c2ecf20Sopenharmony_ci	unsigned long flags;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	spin_lock_irqsave(&adapter->mdio_lock, flags);
1248c2ecf20Sopenharmony_ci	atl1e_restart_autoneg(hw);
1258c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&adapter->mdio_lock, flags);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_civoid atl1e_reinit_locked(struct atl1e_adapter *adapter)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	while (test_and_set_bit(__AT_RESETTING, &adapter->flags))
1318c2ecf20Sopenharmony_ci		msleep(1);
1328c2ecf20Sopenharmony_ci	atl1e_down(adapter);
1338c2ecf20Sopenharmony_ci	atl1e_up(adapter);
1348c2ecf20Sopenharmony_ci	clear_bit(__AT_RESETTING, &adapter->flags);
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic void atl1e_reset_task(struct work_struct *work)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter;
1408c2ecf20Sopenharmony_ci	adapter = container_of(work, struct atl1e_adapter, reset_task);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	atl1e_reinit_locked(adapter);
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic int atl1e_check_link(struct atl1e_adapter *adapter)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct atl1e_hw *hw = &adapter->hw;
1488c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
1498c2ecf20Sopenharmony_ci	int err = 0;
1508c2ecf20Sopenharmony_ci	u16 speed, duplex, phy_data;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	/* MII_BMSR must read twice */
1538c2ecf20Sopenharmony_ci	atl1e_read_phy_reg(hw, MII_BMSR, &phy_data);
1548c2ecf20Sopenharmony_ci	atl1e_read_phy_reg(hw, MII_BMSR, &phy_data);
1558c2ecf20Sopenharmony_ci	if ((phy_data & BMSR_LSTATUS) == 0) {
1568c2ecf20Sopenharmony_ci		/* link down */
1578c2ecf20Sopenharmony_ci		if (netif_carrier_ok(netdev)) { /* old link state: Up */
1588c2ecf20Sopenharmony_ci			u32 value;
1598c2ecf20Sopenharmony_ci			/* disable rx */
1608c2ecf20Sopenharmony_ci			value = AT_READ_REG(hw, REG_MAC_CTRL);
1618c2ecf20Sopenharmony_ci			value &= ~MAC_CTRL_RX_EN;
1628c2ecf20Sopenharmony_ci			AT_WRITE_REG(hw, REG_MAC_CTRL, value);
1638c2ecf20Sopenharmony_ci			adapter->link_speed = SPEED_0;
1648c2ecf20Sopenharmony_ci			netif_carrier_off(netdev);
1658c2ecf20Sopenharmony_ci			netif_stop_queue(netdev);
1668c2ecf20Sopenharmony_ci		}
1678c2ecf20Sopenharmony_ci	} else {
1688c2ecf20Sopenharmony_ci		/* Link Up */
1698c2ecf20Sopenharmony_ci		err = atl1e_get_speed_and_duplex(hw, &speed, &duplex);
1708c2ecf20Sopenharmony_ci		if (unlikely(err))
1718c2ecf20Sopenharmony_ci			return err;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci		/* link result is our setting */
1748c2ecf20Sopenharmony_ci		if (adapter->link_speed != speed ||
1758c2ecf20Sopenharmony_ci		    adapter->link_duplex != duplex) {
1768c2ecf20Sopenharmony_ci			adapter->link_speed  = speed;
1778c2ecf20Sopenharmony_ci			adapter->link_duplex = duplex;
1788c2ecf20Sopenharmony_ci			atl1e_setup_mac_ctrl(adapter);
1798c2ecf20Sopenharmony_ci			netdev_info(netdev,
1808c2ecf20Sopenharmony_ci				    "NIC Link is Up <%d Mbps %s Duplex>\n",
1818c2ecf20Sopenharmony_ci				    adapter->link_speed,
1828c2ecf20Sopenharmony_ci				    adapter->link_duplex == FULL_DUPLEX ?
1838c2ecf20Sopenharmony_ci				    "Full" : "Half");
1848c2ecf20Sopenharmony_ci		}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		if (!netif_carrier_ok(netdev)) {
1878c2ecf20Sopenharmony_ci			/* Link down -> Up */
1888c2ecf20Sopenharmony_ci			netif_carrier_on(netdev);
1898c2ecf20Sopenharmony_ci			netif_wake_queue(netdev);
1908c2ecf20Sopenharmony_ci		}
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci	return 0;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci/**
1968c2ecf20Sopenharmony_ci * atl1e_link_chg_task - deal with link change event Out of interrupt context
1978c2ecf20Sopenharmony_ci * @work: work struct with driver info
1988c2ecf20Sopenharmony_ci */
1998c2ecf20Sopenharmony_cistatic void atl1e_link_chg_task(struct work_struct *work)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter;
2028c2ecf20Sopenharmony_ci	unsigned long flags;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	adapter = container_of(work, struct atl1e_adapter, link_chg_task);
2058c2ecf20Sopenharmony_ci	spin_lock_irqsave(&adapter->mdio_lock, flags);
2068c2ecf20Sopenharmony_ci	atl1e_check_link(adapter);
2078c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&adapter->mdio_lock, flags);
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic void atl1e_link_chg_event(struct atl1e_adapter *adapter)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
2138c2ecf20Sopenharmony_ci	u16 phy_data = 0;
2148c2ecf20Sopenharmony_ci	u16 link_up = 0;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	spin_lock(&adapter->mdio_lock);
2178c2ecf20Sopenharmony_ci	atl1e_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
2188c2ecf20Sopenharmony_ci	atl1e_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
2198c2ecf20Sopenharmony_ci	spin_unlock(&adapter->mdio_lock);
2208c2ecf20Sopenharmony_ci	link_up = phy_data & BMSR_LSTATUS;
2218c2ecf20Sopenharmony_ci	/* notify upper layer link down ASAP */
2228c2ecf20Sopenharmony_ci	if (!link_up) {
2238c2ecf20Sopenharmony_ci		if (netif_carrier_ok(netdev)) {
2248c2ecf20Sopenharmony_ci			/* old link state: Up */
2258c2ecf20Sopenharmony_ci			netdev_info(netdev, "NIC Link is Down\n");
2268c2ecf20Sopenharmony_ci			adapter->link_speed = SPEED_0;
2278c2ecf20Sopenharmony_ci			netif_stop_queue(netdev);
2288c2ecf20Sopenharmony_ci		}
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci	schedule_work(&adapter->link_chg_task);
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic void atl1e_del_timer(struct atl1e_adapter *adapter)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	del_timer_sync(&adapter->phy_config_timer);
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic void atl1e_cancel_work(struct atl1e_adapter *adapter)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	cancel_work_sync(&adapter->reset_task);
2418c2ecf20Sopenharmony_ci	cancel_work_sync(&adapter->link_chg_task);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci/**
2458c2ecf20Sopenharmony_ci * atl1e_tx_timeout - Respond to a Tx Hang
2468c2ecf20Sopenharmony_ci * @netdev: network interface device structure
2478c2ecf20Sopenharmony_ci * @txqueue: the index of the hanging queue
2488c2ecf20Sopenharmony_ci */
2498c2ecf20Sopenharmony_cistatic void atl1e_tx_timeout(struct net_device *netdev, unsigned int txqueue)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* Do the reset outside of interrupt context */
2548c2ecf20Sopenharmony_ci	schedule_work(&adapter->reset_task);
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci/**
2588c2ecf20Sopenharmony_ci * atl1e_set_multi - Multicast and Promiscuous mode set
2598c2ecf20Sopenharmony_ci * @netdev: network interface device structure
2608c2ecf20Sopenharmony_ci *
2618c2ecf20Sopenharmony_ci * The set_multi entry point is called whenever the multicast address
2628c2ecf20Sopenharmony_ci * list or the network interface flags are updated.  This routine is
2638c2ecf20Sopenharmony_ci * responsible for configuring the hardware for proper multicast,
2648c2ecf20Sopenharmony_ci * promiscuous mode, and all-multi behavior.
2658c2ecf20Sopenharmony_ci */
2668c2ecf20Sopenharmony_cistatic void atl1e_set_multi(struct net_device *netdev)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
2698c2ecf20Sopenharmony_ci	struct atl1e_hw *hw = &adapter->hw;
2708c2ecf20Sopenharmony_ci	struct netdev_hw_addr *ha;
2718c2ecf20Sopenharmony_ci	u32 mac_ctrl_data = 0;
2728c2ecf20Sopenharmony_ci	u32 hash_value;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	/* Check for Promiscuous and All Multicast modes */
2758c2ecf20Sopenharmony_ci	mac_ctrl_data = AT_READ_REG(hw, REG_MAC_CTRL);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if (netdev->flags & IFF_PROMISC) {
2788c2ecf20Sopenharmony_ci		mac_ctrl_data |= MAC_CTRL_PROMIS_EN;
2798c2ecf20Sopenharmony_ci	} else if (netdev->flags & IFF_ALLMULTI) {
2808c2ecf20Sopenharmony_ci		mac_ctrl_data |= MAC_CTRL_MC_ALL_EN;
2818c2ecf20Sopenharmony_ci		mac_ctrl_data &= ~MAC_CTRL_PROMIS_EN;
2828c2ecf20Sopenharmony_ci	} else {
2838c2ecf20Sopenharmony_ci		mac_ctrl_data &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN);
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	/* clear the old settings from the multicast hash table */
2898c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_RX_HASH_TABLE, 0);
2908c2ecf20Sopenharmony_ci	AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* comoute mc addresses' hash value ,and put it into hash table */
2938c2ecf20Sopenharmony_ci	netdev_for_each_mc_addr(ha, netdev) {
2948c2ecf20Sopenharmony_ci		hash_value = atl1e_hash_mc_addr(hw, ha->addr);
2958c2ecf20Sopenharmony_ci		atl1e_hash_set(hw, hash_value);
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic void __atl1e_rx_mode(netdev_features_t features, u32 *mac_ctrl_data)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (features & NETIF_F_RXALL) {
3038c2ecf20Sopenharmony_ci		/* enable RX of ALL frames */
3048c2ecf20Sopenharmony_ci		*mac_ctrl_data |= MAC_CTRL_DBG;
3058c2ecf20Sopenharmony_ci	} else {
3068c2ecf20Sopenharmony_ci		/* disable RX of ALL frames */
3078c2ecf20Sopenharmony_ci		*mac_ctrl_data &= ~MAC_CTRL_DBG;
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic void atl1e_rx_mode(struct net_device *netdev,
3128c2ecf20Sopenharmony_ci	netdev_features_t features)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
3158c2ecf20Sopenharmony_ci	u32 mac_ctrl_data = 0;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	netdev_dbg(adapter->netdev, "%s\n", __func__);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	atl1e_irq_disable(adapter);
3208c2ecf20Sopenharmony_ci	mac_ctrl_data = AT_READ_REG(&adapter->hw, REG_MAC_CTRL);
3218c2ecf20Sopenharmony_ci	__atl1e_rx_mode(features, &mac_ctrl_data);
3228c2ecf20Sopenharmony_ci	AT_WRITE_REG(&adapter->hw, REG_MAC_CTRL, mac_ctrl_data);
3238c2ecf20Sopenharmony_ci	atl1e_irq_enable(adapter);
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic void __atl1e_vlan_mode(netdev_features_t features, u32 *mac_ctrl_data)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	if (features & NETIF_F_HW_VLAN_CTAG_RX) {
3308c2ecf20Sopenharmony_ci		/* enable VLAN tag insert/strip */
3318c2ecf20Sopenharmony_ci		*mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
3328c2ecf20Sopenharmony_ci	} else {
3338c2ecf20Sopenharmony_ci		/* disable VLAN tag insert/strip */
3348c2ecf20Sopenharmony_ci		*mac_ctrl_data &= ~MAC_CTRL_RMV_VLAN;
3358c2ecf20Sopenharmony_ci	}
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic void atl1e_vlan_mode(struct net_device *netdev,
3398c2ecf20Sopenharmony_ci	netdev_features_t features)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
3428c2ecf20Sopenharmony_ci	u32 mac_ctrl_data = 0;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	netdev_dbg(adapter->netdev, "%s\n", __func__);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	atl1e_irq_disable(adapter);
3478c2ecf20Sopenharmony_ci	mac_ctrl_data = AT_READ_REG(&adapter->hw, REG_MAC_CTRL);
3488c2ecf20Sopenharmony_ci	__atl1e_vlan_mode(features, &mac_ctrl_data);
3498c2ecf20Sopenharmony_ci	AT_WRITE_REG(&adapter->hw, REG_MAC_CTRL, mac_ctrl_data);
3508c2ecf20Sopenharmony_ci	atl1e_irq_enable(adapter);
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic void atl1e_restore_vlan(struct atl1e_adapter *adapter)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	netdev_dbg(adapter->netdev, "%s\n", __func__);
3568c2ecf20Sopenharmony_ci	atl1e_vlan_mode(adapter->netdev, adapter->netdev->features);
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci/**
3608c2ecf20Sopenharmony_ci * atl1e_set_mac - Change the Ethernet Address of the NIC
3618c2ecf20Sopenharmony_ci * @netdev: network interface device structure
3628c2ecf20Sopenharmony_ci * @p: pointer to an address structure
3638c2ecf20Sopenharmony_ci *
3648c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure
3658c2ecf20Sopenharmony_ci */
3668c2ecf20Sopenharmony_cistatic int atl1e_set_mac_addr(struct net_device *netdev, void *p)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
3698c2ecf20Sopenharmony_ci	struct sockaddr *addr = p;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	if (!is_valid_ether_addr(addr->sa_data))
3728c2ecf20Sopenharmony_ci		return -EADDRNOTAVAIL;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	if (netif_running(netdev))
3758c2ecf20Sopenharmony_ci		return -EBUSY;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
3788c2ecf20Sopenharmony_ci	memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	atl1e_hw_set_mac_addr(&adapter->hw);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	return 0;
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic netdev_features_t atl1e_fix_features(struct net_device *netdev,
3868c2ecf20Sopenharmony_ci	netdev_features_t features)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	/*
3898c2ecf20Sopenharmony_ci	 * Since there is no support for separate rx/tx vlan accel
3908c2ecf20Sopenharmony_ci	 * enable/disable make sure tx flag is always in same state as rx.
3918c2ecf20Sopenharmony_ci	 */
3928c2ecf20Sopenharmony_ci	if (features & NETIF_F_HW_VLAN_CTAG_RX)
3938c2ecf20Sopenharmony_ci		features |= NETIF_F_HW_VLAN_CTAG_TX;
3948c2ecf20Sopenharmony_ci	else
3958c2ecf20Sopenharmony_ci		features &= ~NETIF_F_HW_VLAN_CTAG_TX;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	return features;
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic int atl1e_set_features(struct net_device *netdev,
4018c2ecf20Sopenharmony_ci	netdev_features_t features)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	netdev_features_t changed = netdev->features ^ features;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	if (changed & NETIF_F_HW_VLAN_CTAG_RX)
4068c2ecf20Sopenharmony_ci		atl1e_vlan_mode(netdev, features);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	if (changed & NETIF_F_RXALL)
4098c2ecf20Sopenharmony_ci		atl1e_rx_mode(netdev, features);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	return 0;
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci/**
4168c2ecf20Sopenharmony_ci * atl1e_change_mtu - Change the Maximum Transfer Unit
4178c2ecf20Sopenharmony_ci * @netdev: network interface device structure
4188c2ecf20Sopenharmony_ci * @new_mtu: new value for maximum frame size
4198c2ecf20Sopenharmony_ci *
4208c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure
4218c2ecf20Sopenharmony_ci */
4228c2ecf20Sopenharmony_cistatic int atl1e_change_mtu(struct net_device *netdev, int new_mtu)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
4258c2ecf20Sopenharmony_ci	int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	/* set MTU */
4288c2ecf20Sopenharmony_ci	if (netif_running(netdev)) {
4298c2ecf20Sopenharmony_ci		while (test_and_set_bit(__AT_RESETTING, &adapter->flags))
4308c2ecf20Sopenharmony_ci			msleep(1);
4318c2ecf20Sopenharmony_ci		netdev->mtu = new_mtu;
4328c2ecf20Sopenharmony_ci		adapter->hw.max_frame_size = new_mtu;
4338c2ecf20Sopenharmony_ci		adapter->hw.rx_jumbo_th = (max_frame + 7) >> 3;
4348c2ecf20Sopenharmony_ci		atl1e_down(adapter);
4358c2ecf20Sopenharmony_ci		atl1e_up(adapter);
4368c2ecf20Sopenharmony_ci		clear_bit(__AT_RESETTING, &adapter->flags);
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci	return 0;
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci/*
4428c2ecf20Sopenharmony_ci *  caller should hold mdio_lock
4438c2ecf20Sopenharmony_ci */
4448c2ecf20Sopenharmony_cistatic int atl1e_mdio_read(struct net_device *netdev, int phy_id, int reg_num)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
4478c2ecf20Sopenharmony_ci	u16 result;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	atl1e_read_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, &result);
4508c2ecf20Sopenharmony_ci	return result;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic void atl1e_mdio_write(struct net_device *netdev, int phy_id,
4548c2ecf20Sopenharmony_ci			     int reg_num, int val)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	if (atl1e_write_phy_reg(&adapter->hw,
4598c2ecf20Sopenharmony_ci				reg_num & MDIO_REG_ADDR_MASK, val))
4608c2ecf20Sopenharmony_ci		netdev_err(netdev, "write phy register failed\n");
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic int atl1e_mii_ioctl(struct net_device *netdev,
4648c2ecf20Sopenharmony_ci			   struct ifreq *ifr, int cmd)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
4678c2ecf20Sopenharmony_ci	struct mii_ioctl_data *data = if_mii(ifr);
4688c2ecf20Sopenharmony_ci	unsigned long flags;
4698c2ecf20Sopenharmony_ci	int retval = 0;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	if (!netif_running(netdev))
4728c2ecf20Sopenharmony_ci		return -EINVAL;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	spin_lock_irqsave(&adapter->mdio_lock, flags);
4758c2ecf20Sopenharmony_ci	switch (cmd) {
4768c2ecf20Sopenharmony_ci	case SIOCGMIIPHY:
4778c2ecf20Sopenharmony_ci		data->phy_id = 0;
4788c2ecf20Sopenharmony_ci		break;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	case SIOCGMIIREG:
4818c2ecf20Sopenharmony_ci		if (atl1e_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
4828c2ecf20Sopenharmony_ci				    &data->val_out)) {
4838c2ecf20Sopenharmony_ci			retval = -EIO;
4848c2ecf20Sopenharmony_ci			goto out;
4858c2ecf20Sopenharmony_ci		}
4868c2ecf20Sopenharmony_ci		break;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	case SIOCSMIIREG:
4898c2ecf20Sopenharmony_ci		if (data->reg_num & ~(0x1F)) {
4908c2ecf20Sopenharmony_ci			retval = -EFAULT;
4918c2ecf20Sopenharmony_ci			goto out;
4928c2ecf20Sopenharmony_ci		}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci		netdev_dbg(adapter->netdev, "<atl1e_mii_ioctl> write %x %x\n",
4958c2ecf20Sopenharmony_ci			   data->reg_num, data->val_in);
4968c2ecf20Sopenharmony_ci		if (atl1e_write_phy_reg(&adapter->hw,
4978c2ecf20Sopenharmony_ci				     data->reg_num, data->val_in)) {
4988c2ecf20Sopenharmony_ci			retval = -EIO;
4998c2ecf20Sopenharmony_ci			goto out;
5008c2ecf20Sopenharmony_ci		}
5018c2ecf20Sopenharmony_ci		break;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	default:
5048c2ecf20Sopenharmony_ci		retval = -EOPNOTSUPP;
5058c2ecf20Sopenharmony_ci		break;
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ciout:
5088c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&adapter->mdio_lock, flags);
5098c2ecf20Sopenharmony_ci	return retval;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cistatic int atl1e_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	switch (cmd) {
5168c2ecf20Sopenharmony_ci	case SIOCGMIIPHY:
5178c2ecf20Sopenharmony_ci	case SIOCGMIIREG:
5188c2ecf20Sopenharmony_ci	case SIOCSMIIREG:
5198c2ecf20Sopenharmony_ci		return atl1e_mii_ioctl(netdev, ifr, cmd);
5208c2ecf20Sopenharmony_ci	default:
5218c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_cistatic void atl1e_setup_pcicmd(struct pci_dev *pdev)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	u16 cmd;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
5308c2ecf20Sopenharmony_ci	cmd &= ~(PCI_COMMAND_INTX_DISABLE | PCI_COMMAND_IO);
5318c2ecf20Sopenharmony_ci	cmd |=  (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
5328c2ecf20Sopenharmony_ci	pci_write_config_word(pdev, PCI_COMMAND, cmd);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	/*
5358c2ecf20Sopenharmony_ci	 * some motherboards BIOS(PXE/EFI) driver may set PME
5368c2ecf20Sopenharmony_ci	 * while they transfer control to OS (Windows/Linux)
5378c2ecf20Sopenharmony_ci	 * so we should clear this bit before NIC work normally
5388c2ecf20Sopenharmony_ci	 */
5398c2ecf20Sopenharmony_ci	pci_write_config_dword(pdev, REG_PM_CTRLSTAT, 0);
5408c2ecf20Sopenharmony_ci	msleep(1);
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci/**
5448c2ecf20Sopenharmony_ci * atl1e_alloc_queues - Allocate memory for all rings
5458c2ecf20Sopenharmony_ci * @adapter: board private structure to initialize
5468c2ecf20Sopenharmony_ci *
5478c2ecf20Sopenharmony_ci */
5488c2ecf20Sopenharmony_cistatic int atl1e_alloc_queues(struct atl1e_adapter *adapter)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci	return 0;
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci/**
5548c2ecf20Sopenharmony_ci * atl1e_sw_init - Initialize general software structures (struct atl1e_adapter)
5558c2ecf20Sopenharmony_ci * @adapter: board private structure to initialize
5568c2ecf20Sopenharmony_ci *
5578c2ecf20Sopenharmony_ci * atl1e_sw_init initializes the Adapter private data structure.
5588c2ecf20Sopenharmony_ci * Fields are initialized based on PCI device information and
5598c2ecf20Sopenharmony_ci * OS network device settings (MTU size).
5608c2ecf20Sopenharmony_ci */
5618c2ecf20Sopenharmony_cistatic int atl1e_sw_init(struct atl1e_adapter *adapter)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	struct atl1e_hw *hw   = &adapter->hw;
5648c2ecf20Sopenharmony_ci	struct pci_dev	*pdev = adapter->pdev;
5658c2ecf20Sopenharmony_ci	u32 phy_status_data = 0;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	adapter->wol = 0;
5688c2ecf20Sopenharmony_ci	adapter->link_speed = SPEED_0;   /* hardware init */
5698c2ecf20Sopenharmony_ci	adapter->link_duplex = FULL_DUPLEX;
5708c2ecf20Sopenharmony_ci	adapter->num_rx_queues = 1;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	/* PCI config space info */
5738c2ecf20Sopenharmony_ci	hw->vendor_id = pdev->vendor;
5748c2ecf20Sopenharmony_ci	hw->device_id = pdev->device;
5758c2ecf20Sopenharmony_ci	hw->subsystem_vendor_id = pdev->subsystem_vendor;
5768c2ecf20Sopenharmony_ci	hw->subsystem_id = pdev->subsystem_device;
5778c2ecf20Sopenharmony_ci	hw->revision_id  = pdev->revision;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	phy_status_data = AT_READ_REG(hw, REG_PHY_STATUS);
5828c2ecf20Sopenharmony_ci	/* nic type */
5838c2ecf20Sopenharmony_ci	if (hw->revision_id >= 0xF0) {
5848c2ecf20Sopenharmony_ci		hw->nic_type = athr_l2e_revB;
5858c2ecf20Sopenharmony_ci	} else {
5868c2ecf20Sopenharmony_ci		if (phy_status_data & PHY_STATUS_100M)
5878c2ecf20Sopenharmony_ci			hw->nic_type = athr_l1e;
5888c2ecf20Sopenharmony_ci		else
5898c2ecf20Sopenharmony_ci			hw->nic_type = athr_l2e_revA;
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	phy_status_data = AT_READ_REG(hw, REG_PHY_STATUS);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	if (phy_status_data & PHY_STATUS_EMI_CA)
5958c2ecf20Sopenharmony_ci		hw->emi_ca = true;
5968c2ecf20Sopenharmony_ci	else
5978c2ecf20Sopenharmony_ci		hw->emi_ca = false;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	hw->phy_configured = false;
6008c2ecf20Sopenharmony_ci	hw->preamble_len = 7;
6018c2ecf20Sopenharmony_ci	hw->max_frame_size = adapter->netdev->mtu;
6028c2ecf20Sopenharmony_ci	hw->rx_jumbo_th = (hw->max_frame_size + ETH_HLEN +
6038c2ecf20Sopenharmony_ci				VLAN_HLEN + ETH_FCS_LEN + 7) >> 3;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	hw->rrs_type = atl1e_rrs_disable;
6068c2ecf20Sopenharmony_ci	hw->indirect_tab = 0;
6078c2ecf20Sopenharmony_ci	hw->base_cpu = 0;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	/* need confirm */
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	hw->ict = 50000;                 /* 100ms */
6128c2ecf20Sopenharmony_ci	hw->smb_timer = 200000;          /* 200ms  */
6138c2ecf20Sopenharmony_ci	hw->tpd_burst = 5;
6148c2ecf20Sopenharmony_ci	hw->rrd_thresh = 1;
6158c2ecf20Sopenharmony_ci	hw->tpd_thresh = adapter->tx_ring.count / 2;
6168c2ecf20Sopenharmony_ci	hw->rx_count_down = 4;  /* 2us resolution */
6178c2ecf20Sopenharmony_ci	hw->tx_count_down = hw->imt * 4 / 3;
6188c2ecf20Sopenharmony_ci	hw->dmar_block = atl1e_dma_req_1024;
6198c2ecf20Sopenharmony_ci	hw->dmaw_block = atl1e_dma_req_1024;
6208c2ecf20Sopenharmony_ci	hw->dmar_dly_cnt = 15;
6218c2ecf20Sopenharmony_ci	hw->dmaw_dly_cnt = 4;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (atl1e_alloc_queues(adapter)) {
6248c2ecf20Sopenharmony_ci		netdev_err(adapter->netdev, "Unable to allocate memory for queues\n");
6258c2ecf20Sopenharmony_ci		return -ENOMEM;
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	atomic_set(&adapter->irq_sem, 1);
6298c2ecf20Sopenharmony_ci	spin_lock_init(&adapter->mdio_lock);
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	set_bit(__AT_DOWN, &adapter->flags);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	return 0;
6348c2ecf20Sopenharmony_ci}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci/**
6378c2ecf20Sopenharmony_ci * atl1e_clean_tx_ring - Free Tx-skb
6388c2ecf20Sopenharmony_ci * @adapter: board private structure
6398c2ecf20Sopenharmony_ci */
6408c2ecf20Sopenharmony_cistatic void atl1e_clean_tx_ring(struct atl1e_adapter *adapter)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
6438c2ecf20Sopenharmony_ci	struct atl1e_tx_buffer *tx_buffer = NULL;
6448c2ecf20Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
6458c2ecf20Sopenharmony_ci	u16 index, ring_count;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	if (tx_ring->desc == NULL || tx_ring->tx_buffer == NULL)
6488c2ecf20Sopenharmony_ci		return;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	ring_count = tx_ring->count;
6518c2ecf20Sopenharmony_ci	/* first unmmap dma */
6528c2ecf20Sopenharmony_ci	for (index = 0; index < ring_count; index++) {
6538c2ecf20Sopenharmony_ci		tx_buffer = &tx_ring->tx_buffer[index];
6548c2ecf20Sopenharmony_ci		if (tx_buffer->dma) {
6558c2ecf20Sopenharmony_ci			if (tx_buffer->flags & ATL1E_TX_PCIMAP_SINGLE)
6568c2ecf20Sopenharmony_ci				dma_unmap_single(&pdev->dev, tx_buffer->dma,
6578c2ecf20Sopenharmony_ci						 tx_buffer->length,
6588c2ecf20Sopenharmony_ci						 DMA_TO_DEVICE);
6598c2ecf20Sopenharmony_ci			else if (tx_buffer->flags & ATL1E_TX_PCIMAP_PAGE)
6608c2ecf20Sopenharmony_ci				dma_unmap_page(&pdev->dev, tx_buffer->dma,
6618c2ecf20Sopenharmony_ci					       tx_buffer->length,
6628c2ecf20Sopenharmony_ci					       DMA_TO_DEVICE);
6638c2ecf20Sopenharmony_ci			tx_buffer->dma = 0;
6648c2ecf20Sopenharmony_ci		}
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci	/* second free skb */
6678c2ecf20Sopenharmony_ci	for (index = 0; index < ring_count; index++) {
6688c2ecf20Sopenharmony_ci		tx_buffer = &tx_ring->tx_buffer[index];
6698c2ecf20Sopenharmony_ci		if (tx_buffer->skb) {
6708c2ecf20Sopenharmony_ci			dev_kfree_skb_any(tx_buffer->skb);
6718c2ecf20Sopenharmony_ci			tx_buffer->skb = NULL;
6728c2ecf20Sopenharmony_ci		}
6738c2ecf20Sopenharmony_ci	}
6748c2ecf20Sopenharmony_ci	/* Zero out Tx-buffers */
6758c2ecf20Sopenharmony_ci	memset(tx_ring->desc, 0, sizeof(struct atl1e_tpd_desc) *
6768c2ecf20Sopenharmony_ci				ring_count);
6778c2ecf20Sopenharmony_ci	memset(tx_ring->tx_buffer, 0, sizeof(struct atl1e_tx_buffer) *
6788c2ecf20Sopenharmony_ci				ring_count);
6798c2ecf20Sopenharmony_ci}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci/**
6828c2ecf20Sopenharmony_ci * atl1e_clean_rx_ring - Free rx-reservation skbs
6838c2ecf20Sopenharmony_ci * @adapter: board private structure
6848c2ecf20Sopenharmony_ci */
6858c2ecf20Sopenharmony_cistatic void atl1e_clean_rx_ring(struct atl1e_adapter *adapter)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	struct atl1e_rx_ring *rx_ring =
6888c2ecf20Sopenharmony_ci		&adapter->rx_ring;
6898c2ecf20Sopenharmony_ci	struct atl1e_rx_page_desc *rx_page_desc = rx_ring->rx_page_desc;
6908c2ecf20Sopenharmony_ci	u16 i, j;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	if (adapter->ring_vir_addr == NULL)
6948c2ecf20Sopenharmony_ci		return;
6958c2ecf20Sopenharmony_ci	/* Zero out the descriptor ring */
6968c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->num_rx_queues; i++) {
6978c2ecf20Sopenharmony_ci		for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) {
6988c2ecf20Sopenharmony_ci			if (rx_page_desc[i].rx_page[j].addr != NULL) {
6998c2ecf20Sopenharmony_ci				memset(rx_page_desc[i].rx_page[j].addr, 0,
7008c2ecf20Sopenharmony_ci						rx_ring->real_page_size);
7018c2ecf20Sopenharmony_ci			}
7028c2ecf20Sopenharmony_ci		}
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_cistatic void atl1e_cal_ring_size(struct atl1e_adapter *adapter, u32 *ring_size)
7078c2ecf20Sopenharmony_ci{
7088c2ecf20Sopenharmony_ci	*ring_size = ((u32)(adapter->tx_ring.count *
7098c2ecf20Sopenharmony_ci		     sizeof(struct atl1e_tpd_desc) + 7
7108c2ecf20Sopenharmony_ci			/* tx ring, qword align */
7118c2ecf20Sopenharmony_ci		     + adapter->rx_ring.real_page_size * AT_PAGE_NUM_PER_QUEUE *
7128c2ecf20Sopenharmony_ci			adapter->num_rx_queues + 31
7138c2ecf20Sopenharmony_ci			/* rx ring,  32 bytes align */
7148c2ecf20Sopenharmony_ci		     + (1 + AT_PAGE_NUM_PER_QUEUE * adapter->num_rx_queues) *
7158c2ecf20Sopenharmony_ci			sizeof(u32) + 3));
7168c2ecf20Sopenharmony_ci			/* tx, rx cmd, dword align   */
7178c2ecf20Sopenharmony_ci}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_cistatic void atl1e_init_ring_resources(struct atl1e_adapter *adapter)
7208c2ecf20Sopenharmony_ci{
7218c2ecf20Sopenharmony_ci	struct atl1e_rx_ring *rx_ring = NULL;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	rx_ring = &adapter->rx_ring;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	rx_ring->real_page_size = adapter->rx_ring.page_size
7268c2ecf20Sopenharmony_ci				 + adapter->hw.max_frame_size
7278c2ecf20Sopenharmony_ci				 + ETH_HLEN + VLAN_HLEN
7288c2ecf20Sopenharmony_ci				 + ETH_FCS_LEN;
7298c2ecf20Sopenharmony_ci	rx_ring->real_page_size = roundup(rx_ring->real_page_size, 32);
7308c2ecf20Sopenharmony_ci	atl1e_cal_ring_size(adapter, &adapter->ring_size);
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	adapter->ring_vir_addr = NULL;
7338c2ecf20Sopenharmony_ci	adapter->rx_ring.desc = NULL;
7348c2ecf20Sopenharmony_ci	rwlock_init(&adapter->tx_ring.tx_lock);
7358c2ecf20Sopenharmony_ci}
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci/*
7388c2ecf20Sopenharmony_ci * Read / Write Ptr Initialize:
7398c2ecf20Sopenharmony_ci */
7408c2ecf20Sopenharmony_cistatic void atl1e_init_ring_ptrs(struct atl1e_adapter *adapter)
7418c2ecf20Sopenharmony_ci{
7428c2ecf20Sopenharmony_ci	struct atl1e_tx_ring *tx_ring = NULL;
7438c2ecf20Sopenharmony_ci	struct atl1e_rx_ring *rx_ring = NULL;
7448c2ecf20Sopenharmony_ci	struct atl1e_rx_page_desc *rx_page_desc = NULL;
7458c2ecf20Sopenharmony_ci	int i, j;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	tx_ring = &adapter->tx_ring;
7488c2ecf20Sopenharmony_ci	rx_ring = &adapter->rx_ring;
7498c2ecf20Sopenharmony_ci	rx_page_desc = rx_ring->rx_page_desc;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	tx_ring->next_to_use = 0;
7528c2ecf20Sopenharmony_ci	atomic_set(&tx_ring->next_to_clean, 0);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->num_rx_queues; i++) {
7558c2ecf20Sopenharmony_ci		rx_page_desc[i].rx_using  = 0;
7568c2ecf20Sopenharmony_ci		rx_page_desc[i].rx_nxseq = 0;
7578c2ecf20Sopenharmony_ci		for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) {
7588c2ecf20Sopenharmony_ci			*rx_page_desc[i].rx_page[j].write_offset_addr = 0;
7598c2ecf20Sopenharmony_ci			rx_page_desc[i].rx_page[j].read_offset = 0;
7608c2ecf20Sopenharmony_ci		}
7618c2ecf20Sopenharmony_ci	}
7628c2ecf20Sopenharmony_ci}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci/**
7658c2ecf20Sopenharmony_ci * atl1e_free_ring_resources - Free Tx / RX descriptor Resources
7668c2ecf20Sopenharmony_ci * @adapter: board private structure
7678c2ecf20Sopenharmony_ci *
7688c2ecf20Sopenharmony_ci * Free all transmit software resources
7698c2ecf20Sopenharmony_ci */
7708c2ecf20Sopenharmony_cistatic void atl1e_free_ring_resources(struct atl1e_adapter *adapter)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	atl1e_clean_tx_ring(adapter);
7758c2ecf20Sopenharmony_ci	atl1e_clean_rx_ring(adapter);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	if (adapter->ring_vir_addr) {
7788c2ecf20Sopenharmony_ci		dma_free_coherent(&pdev->dev, adapter->ring_size,
7798c2ecf20Sopenharmony_ci				  adapter->ring_vir_addr, adapter->ring_dma);
7808c2ecf20Sopenharmony_ci		adapter->ring_vir_addr = NULL;
7818c2ecf20Sopenharmony_ci	}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	if (adapter->tx_ring.tx_buffer) {
7848c2ecf20Sopenharmony_ci		kfree(adapter->tx_ring.tx_buffer);
7858c2ecf20Sopenharmony_ci		adapter->tx_ring.tx_buffer = NULL;
7868c2ecf20Sopenharmony_ci	}
7878c2ecf20Sopenharmony_ci}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci/**
7908c2ecf20Sopenharmony_ci * atl1e_setup_mem_resources - allocate Tx / RX descriptor resources
7918c2ecf20Sopenharmony_ci * @adapter: board private structure
7928c2ecf20Sopenharmony_ci *
7938c2ecf20Sopenharmony_ci * Return 0 on success, negative on failure
7948c2ecf20Sopenharmony_ci */
7958c2ecf20Sopenharmony_cistatic int atl1e_setup_ring_resources(struct atl1e_adapter *adapter)
7968c2ecf20Sopenharmony_ci{
7978c2ecf20Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
7988c2ecf20Sopenharmony_ci	struct atl1e_tx_ring *tx_ring;
7998c2ecf20Sopenharmony_ci	struct atl1e_rx_ring *rx_ring;
8008c2ecf20Sopenharmony_ci	struct atl1e_rx_page_desc  *rx_page_desc;
8018c2ecf20Sopenharmony_ci	int size, i, j;
8028c2ecf20Sopenharmony_ci	u32 offset = 0;
8038c2ecf20Sopenharmony_ci	int err = 0;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	if (adapter->ring_vir_addr != NULL)
8068c2ecf20Sopenharmony_ci		return 0; /* alloced already */
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	tx_ring = &adapter->tx_ring;
8098c2ecf20Sopenharmony_ci	rx_ring = &adapter->rx_ring;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	/* real ring DMA buffer */
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	size = adapter->ring_size;
8148c2ecf20Sopenharmony_ci	adapter->ring_vir_addr = dma_alloc_coherent(&pdev->dev,
8158c2ecf20Sopenharmony_ci						    adapter->ring_size,
8168c2ecf20Sopenharmony_ci						    &adapter->ring_dma, GFP_KERNEL);
8178c2ecf20Sopenharmony_ci	if (adapter->ring_vir_addr == NULL) {
8188c2ecf20Sopenharmony_ci		netdev_err(adapter->netdev,
8198c2ecf20Sopenharmony_ci			   "dma_alloc_coherent failed, size = D%d\n", size);
8208c2ecf20Sopenharmony_ci		return -ENOMEM;
8218c2ecf20Sopenharmony_ci	}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	rx_page_desc = rx_ring->rx_page_desc;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	/* Init TPD Ring */
8268c2ecf20Sopenharmony_ci	tx_ring->dma = roundup(adapter->ring_dma, 8);
8278c2ecf20Sopenharmony_ci	offset = tx_ring->dma - adapter->ring_dma;
8288c2ecf20Sopenharmony_ci	tx_ring->desc = adapter->ring_vir_addr + offset;
8298c2ecf20Sopenharmony_ci	size = sizeof(struct atl1e_tx_buffer) * (tx_ring->count);
8308c2ecf20Sopenharmony_ci	tx_ring->tx_buffer = kzalloc(size, GFP_KERNEL);
8318c2ecf20Sopenharmony_ci	if (tx_ring->tx_buffer == NULL) {
8328c2ecf20Sopenharmony_ci		err = -ENOMEM;
8338c2ecf20Sopenharmony_ci		goto failed;
8348c2ecf20Sopenharmony_ci	}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	/* Init RXF-Pages */
8378c2ecf20Sopenharmony_ci	offset += (sizeof(struct atl1e_tpd_desc) * tx_ring->count);
8388c2ecf20Sopenharmony_ci	offset = roundup(offset, 32);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->num_rx_queues; i++) {
8418c2ecf20Sopenharmony_ci		for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) {
8428c2ecf20Sopenharmony_ci			rx_page_desc[i].rx_page[j].dma =
8438c2ecf20Sopenharmony_ci				adapter->ring_dma + offset;
8448c2ecf20Sopenharmony_ci			rx_page_desc[i].rx_page[j].addr =
8458c2ecf20Sopenharmony_ci				adapter->ring_vir_addr + offset;
8468c2ecf20Sopenharmony_ci			offset += rx_ring->real_page_size;
8478c2ecf20Sopenharmony_ci		}
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	/* Init CMB dma address */
8518c2ecf20Sopenharmony_ci	tx_ring->cmb_dma = adapter->ring_dma + offset;
8528c2ecf20Sopenharmony_ci	tx_ring->cmb = adapter->ring_vir_addr + offset;
8538c2ecf20Sopenharmony_ci	offset += sizeof(u32);
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->num_rx_queues; i++) {
8568c2ecf20Sopenharmony_ci		for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) {
8578c2ecf20Sopenharmony_ci			rx_page_desc[i].rx_page[j].write_offset_dma =
8588c2ecf20Sopenharmony_ci				adapter->ring_dma + offset;
8598c2ecf20Sopenharmony_ci			rx_page_desc[i].rx_page[j].write_offset_addr =
8608c2ecf20Sopenharmony_ci				adapter->ring_vir_addr + offset;
8618c2ecf20Sopenharmony_ci			offset += sizeof(u32);
8628c2ecf20Sopenharmony_ci		}
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	if (unlikely(offset > adapter->ring_size)) {
8668c2ecf20Sopenharmony_ci		netdev_err(adapter->netdev, "offset(%d) > ring size(%d) !!\n",
8678c2ecf20Sopenharmony_ci			   offset, adapter->ring_size);
8688c2ecf20Sopenharmony_ci		err = -1;
8698c2ecf20Sopenharmony_ci		goto free_buffer;
8708c2ecf20Sopenharmony_ci	}
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	return 0;
8738c2ecf20Sopenharmony_cifree_buffer:
8748c2ecf20Sopenharmony_ci	kfree(tx_ring->tx_buffer);
8758c2ecf20Sopenharmony_ci	tx_ring->tx_buffer = NULL;
8768c2ecf20Sopenharmony_cifailed:
8778c2ecf20Sopenharmony_ci	if (adapter->ring_vir_addr != NULL) {
8788c2ecf20Sopenharmony_ci		dma_free_coherent(&pdev->dev, adapter->ring_size,
8798c2ecf20Sopenharmony_ci				  adapter->ring_vir_addr, adapter->ring_dma);
8808c2ecf20Sopenharmony_ci		adapter->ring_vir_addr = NULL;
8818c2ecf20Sopenharmony_ci	}
8828c2ecf20Sopenharmony_ci	return err;
8838c2ecf20Sopenharmony_ci}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_cistatic inline void atl1e_configure_des_ring(struct atl1e_adapter *adapter)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	struct atl1e_hw *hw = &adapter->hw;
8898c2ecf20Sopenharmony_ci	struct atl1e_rx_ring *rx_ring = &adapter->rx_ring;
8908c2ecf20Sopenharmony_ci	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
8918c2ecf20Sopenharmony_ci	struct atl1e_rx_page_desc *rx_page_desc = NULL;
8928c2ecf20Sopenharmony_ci	int i, j;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_DESC_BASE_ADDR_HI,
8958c2ecf20Sopenharmony_ci			(u32)((adapter->ring_dma & AT_DMA_HI_ADDR_MASK) >> 32));
8968c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_TPD_BASE_ADDR_LO,
8978c2ecf20Sopenharmony_ci			(u32)((tx_ring->dma) & AT_DMA_LO_ADDR_MASK));
8988c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_TPD_RING_SIZE, (u16)(tx_ring->count));
8998c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_HOST_TX_CMB_LO,
9008c2ecf20Sopenharmony_ci			(u32)((tx_ring->cmb_dma) & AT_DMA_LO_ADDR_MASK));
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	rx_page_desc = rx_ring->rx_page_desc;
9038c2ecf20Sopenharmony_ci	/* RXF Page Physical address / Page Length */
9048c2ecf20Sopenharmony_ci	for (i = 0; i < AT_MAX_RECEIVE_QUEUE; i++) {
9058c2ecf20Sopenharmony_ci		AT_WRITE_REG(hw, atl1e_rx_page_hi_addr_regs[i],
9068c2ecf20Sopenharmony_ci				 (u32)((adapter->ring_dma &
9078c2ecf20Sopenharmony_ci				 AT_DMA_HI_ADDR_MASK) >> 32));
9088c2ecf20Sopenharmony_ci		for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) {
9098c2ecf20Sopenharmony_ci			u32 page_phy_addr;
9108c2ecf20Sopenharmony_ci			u32 offset_phy_addr;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci			page_phy_addr = rx_page_desc[i].rx_page[j].dma;
9138c2ecf20Sopenharmony_ci			offset_phy_addr =
9148c2ecf20Sopenharmony_ci				   rx_page_desc[i].rx_page[j].write_offset_dma;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci			AT_WRITE_REG(hw, atl1e_rx_page_lo_addr_regs[i][j],
9178c2ecf20Sopenharmony_ci					page_phy_addr & AT_DMA_LO_ADDR_MASK);
9188c2ecf20Sopenharmony_ci			AT_WRITE_REG(hw, atl1e_rx_page_write_offset_regs[i][j],
9198c2ecf20Sopenharmony_ci					offset_phy_addr & AT_DMA_LO_ADDR_MASK);
9208c2ecf20Sopenharmony_ci			AT_WRITE_REGB(hw, atl1e_rx_page_vld_regs[i][j], 1);
9218c2ecf20Sopenharmony_ci		}
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci	/* Page Length */
9248c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_HOST_RXFPAGE_SIZE, rx_ring->page_size);
9258c2ecf20Sopenharmony_ci	/* Load all of base address above */
9268c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_LOAD_PTR, 1);
9278c2ecf20Sopenharmony_ci}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_cistatic inline void atl1e_configure_tx(struct atl1e_adapter *adapter)
9308c2ecf20Sopenharmony_ci{
9318c2ecf20Sopenharmony_ci	struct atl1e_hw *hw = &adapter->hw;
9328c2ecf20Sopenharmony_ci	u32 dev_ctrl_data = 0;
9338c2ecf20Sopenharmony_ci	u32 max_pay_load = 0;
9348c2ecf20Sopenharmony_ci	u32 jumbo_thresh = 0;
9358c2ecf20Sopenharmony_ci	u32 extra_size = 0;     /* Jumbo frame threshold in QWORD unit */
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	/* configure TXQ param */
9388c2ecf20Sopenharmony_ci	if (hw->nic_type != athr_l2e_revB) {
9398c2ecf20Sopenharmony_ci		extra_size = ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
9408c2ecf20Sopenharmony_ci		if (hw->max_frame_size <= 1500) {
9418c2ecf20Sopenharmony_ci			jumbo_thresh = hw->max_frame_size + extra_size;
9428c2ecf20Sopenharmony_ci		} else if (hw->max_frame_size < 6*1024) {
9438c2ecf20Sopenharmony_ci			jumbo_thresh =
9448c2ecf20Sopenharmony_ci				(hw->max_frame_size + extra_size) * 2 / 3;
9458c2ecf20Sopenharmony_ci		} else {
9468c2ecf20Sopenharmony_ci			jumbo_thresh = (hw->max_frame_size + extra_size) / 2;
9478c2ecf20Sopenharmony_ci		}
9488c2ecf20Sopenharmony_ci		AT_WRITE_REG(hw, REG_TX_EARLY_TH, (jumbo_thresh + 7) >> 3);
9498c2ecf20Sopenharmony_ci	}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	dev_ctrl_data = AT_READ_REG(hw, REG_DEVICE_CTRL);
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	max_pay_load  = ((dev_ctrl_data >> DEVICE_CTRL_MAX_PAYLOAD_SHIFT)) &
9548c2ecf20Sopenharmony_ci			DEVICE_CTRL_MAX_PAYLOAD_MASK;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	hw->dmaw_block = min_t(u32, max_pay_load, hw->dmaw_block);
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	max_pay_load  = ((dev_ctrl_data >> DEVICE_CTRL_MAX_RREQ_SZ_SHIFT)) &
9598c2ecf20Sopenharmony_ci			DEVICE_CTRL_MAX_RREQ_SZ_MASK;
9608c2ecf20Sopenharmony_ci	hw->dmar_block = min_t(u32, max_pay_load, hw->dmar_block);
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	if (hw->nic_type != athr_l2e_revB)
9638c2ecf20Sopenharmony_ci		AT_WRITE_REGW(hw, REG_TXQ_CTRL + 2,
9648c2ecf20Sopenharmony_ci			      atl1e_pay_load_size[hw->dmar_block]);
9658c2ecf20Sopenharmony_ci	/* enable TXQ */
9668c2ecf20Sopenharmony_ci	AT_WRITE_REGW(hw, REG_TXQ_CTRL,
9678c2ecf20Sopenharmony_ci			(((u16)hw->tpd_burst & TXQ_CTRL_NUM_TPD_BURST_MASK)
9688c2ecf20Sopenharmony_ci			 << TXQ_CTRL_NUM_TPD_BURST_SHIFT)
9698c2ecf20Sopenharmony_ci			| TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN);
9708c2ecf20Sopenharmony_ci}
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_cistatic inline void atl1e_configure_rx(struct atl1e_adapter *adapter)
9738c2ecf20Sopenharmony_ci{
9748c2ecf20Sopenharmony_ci	struct atl1e_hw *hw = &adapter->hw;
9758c2ecf20Sopenharmony_ci	u32 rxf_len  = 0;
9768c2ecf20Sopenharmony_ci	u32 rxf_low  = 0;
9778c2ecf20Sopenharmony_ci	u32 rxf_high = 0;
9788c2ecf20Sopenharmony_ci	u32 rxf_thresh_data = 0;
9798c2ecf20Sopenharmony_ci	u32 rxq_ctrl_data = 0;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	if (hw->nic_type != athr_l2e_revB) {
9828c2ecf20Sopenharmony_ci		AT_WRITE_REGW(hw, REG_RXQ_JMBOSZ_RRDTIM,
9838c2ecf20Sopenharmony_ci			      (u16)((hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK) <<
9848c2ecf20Sopenharmony_ci			      RXQ_JMBOSZ_TH_SHIFT |
9858c2ecf20Sopenharmony_ci			      (1 & RXQ_JMBO_LKAH_MASK) <<
9868c2ecf20Sopenharmony_ci			      RXQ_JMBO_LKAH_SHIFT));
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci		rxf_len  = AT_READ_REG(hw, REG_SRAM_RXF_LEN);
9898c2ecf20Sopenharmony_ci		rxf_high = rxf_len * 4 / 5;
9908c2ecf20Sopenharmony_ci		rxf_low  = rxf_len / 5;
9918c2ecf20Sopenharmony_ci		rxf_thresh_data = ((rxf_high  & RXQ_RXF_PAUSE_TH_HI_MASK)
9928c2ecf20Sopenharmony_ci				  << RXQ_RXF_PAUSE_TH_HI_SHIFT) |
9938c2ecf20Sopenharmony_ci				  ((rxf_low & RXQ_RXF_PAUSE_TH_LO_MASK)
9948c2ecf20Sopenharmony_ci				  << RXQ_RXF_PAUSE_TH_LO_SHIFT);
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci		AT_WRITE_REG(hw, REG_RXQ_RXF_PAUSE_THRESH, rxf_thresh_data);
9978c2ecf20Sopenharmony_ci	}
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	/* RRS */
10008c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_IDT_TABLE, hw->indirect_tab);
10018c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_BASE_CPU_NUMBER, hw->base_cpu);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	if (hw->rrs_type & atl1e_rrs_ipv4)
10048c2ecf20Sopenharmony_ci		rxq_ctrl_data |= RXQ_CTRL_HASH_TYPE_IPV4;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	if (hw->rrs_type & atl1e_rrs_ipv4_tcp)
10078c2ecf20Sopenharmony_ci		rxq_ctrl_data |= RXQ_CTRL_HASH_TYPE_IPV4_TCP;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	if (hw->rrs_type & atl1e_rrs_ipv6)
10108c2ecf20Sopenharmony_ci		rxq_ctrl_data |= RXQ_CTRL_HASH_TYPE_IPV6;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	if (hw->rrs_type & atl1e_rrs_ipv6_tcp)
10138c2ecf20Sopenharmony_ci		rxq_ctrl_data |= RXQ_CTRL_HASH_TYPE_IPV6_TCP;
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	if (hw->rrs_type != atl1e_rrs_disable)
10168c2ecf20Sopenharmony_ci		rxq_ctrl_data |=
10178c2ecf20Sopenharmony_ci			(RXQ_CTRL_HASH_ENABLE | RXQ_CTRL_RSS_MODE_MQUESINT);
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	rxq_ctrl_data |= RXQ_CTRL_IPV6_XSUM_VERIFY_EN | RXQ_CTRL_PBA_ALIGN_32 |
10208c2ecf20Sopenharmony_ci			 RXQ_CTRL_CUT_THRU_EN | RXQ_CTRL_EN;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data);
10238c2ecf20Sopenharmony_ci}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_cistatic inline void atl1e_configure_dma(struct atl1e_adapter *adapter)
10268c2ecf20Sopenharmony_ci{
10278c2ecf20Sopenharmony_ci	struct atl1e_hw *hw = &adapter->hw;
10288c2ecf20Sopenharmony_ci	u32 dma_ctrl_data = 0;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	dma_ctrl_data = DMA_CTRL_RXCMB_EN;
10318c2ecf20Sopenharmony_ci	dma_ctrl_data |= (((u32)hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
10328c2ecf20Sopenharmony_ci		<< DMA_CTRL_DMAR_BURST_LEN_SHIFT;
10338c2ecf20Sopenharmony_ci	dma_ctrl_data |= (((u32)hw->dmaw_block) & DMA_CTRL_DMAW_BURST_LEN_MASK)
10348c2ecf20Sopenharmony_ci		<< DMA_CTRL_DMAW_BURST_LEN_SHIFT;
10358c2ecf20Sopenharmony_ci	dma_ctrl_data |= DMA_CTRL_DMAR_REQ_PRI | DMA_CTRL_DMAR_OUT_ORDER;
10368c2ecf20Sopenharmony_ci	dma_ctrl_data |= (((u32)hw->dmar_dly_cnt) & DMA_CTRL_DMAR_DLY_CNT_MASK)
10378c2ecf20Sopenharmony_ci		<< DMA_CTRL_DMAR_DLY_CNT_SHIFT;
10388c2ecf20Sopenharmony_ci	dma_ctrl_data |= (((u32)hw->dmaw_dly_cnt) & DMA_CTRL_DMAW_DLY_CNT_MASK)
10398c2ecf20Sopenharmony_ci		<< DMA_CTRL_DMAW_DLY_CNT_SHIFT;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_DMA_CTRL, dma_ctrl_data);
10428c2ecf20Sopenharmony_ci}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_cistatic void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter)
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	u32 value;
10478c2ecf20Sopenharmony_ci	struct atl1e_hw *hw = &adapter->hw;
10488c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	/* Config MAC CTRL Register */
10518c2ecf20Sopenharmony_ci	value = MAC_CTRL_TX_EN |
10528c2ecf20Sopenharmony_ci		MAC_CTRL_RX_EN ;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	if (FULL_DUPLEX == adapter->link_duplex)
10558c2ecf20Sopenharmony_ci		value |= MAC_CTRL_DUPLX;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	value |= ((u32)((SPEED_1000 == adapter->link_speed) ?
10588c2ecf20Sopenharmony_ci			  MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100) <<
10598c2ecf20Sopenharmony_ci			  MAC_CTRL_SPEED_SHIFT);
10608c2ecf20Sopenharmony_ci	value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW);
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD);
10638c2ecf20Sopenharmony_ci	value |= (((u32)adapter->hw.preamble_len &
10648c2ecf20Sopenharmony_ci		  MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT);
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	__atl1e_vlan_mode(netdev->features, &value);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	value |= MAC_CTRL_BC_EN;
10698c2ecf20Sopenharmony_ci	if (netdev->flags & IFF_PROMISC)
10708c2ecf20Sopenharmony_ci		value |= MAC_CTRL_PROMIS_EN;
10718c2ecf20Sopenharmony_ci	if (netdev->flags & IFF_ALLMULTI)
10728c2ecf20Sopenharmony_ci		value |= MAC_CTRL_MC_ALL_EN;
10738c2ecf20Sopenharmony_ci	if (netdev->features & NETIF_F_RXALL)
10748c2ecf20Sopenharmony_ci		value |= MAC_CTRL_DBG;
10758c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_MAC_CTRL, value);
10768c2ecf20Sopenharmony_ci}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci/**
10798c2ecf20Sopenharmony_ci * atl1e_configure - Configure Transmit&Receive Unit after Reset
10808c2ecf20Sopenharmony_ci * @adapter: board private structure
10818c2ecf20Sopenharmony_ci *
10828c2ecf20Sopenharmony_ci * Configure the Tx /Rx unit of the MAC after a reset.
10838c2ecf20Sopenharmony_ci */
10848c2ecf20Sopenharmony_cistatic int atl1e_configure(struct atl1e_adapter *adapter)
10858c2ecf20Sopenharmony_ci{
10868c2ecf20Sopenharmony_ci	struct atl1e_hw *hw = &adapter->hw;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	u32 intr_status_data = 0;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	/* clear interrupt status */
10918c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_ISR, ~0);
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	/* 1. set MAC Address */
10948c2ecf20Sopenharmony_ci	atl1e_hw_set_mac_addr(hw);
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	/* 2. Init the Multicast HASH table done by set_muti */
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	/* 3. Clear any WOL status */
10998c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	/* 4. Descripter Ring BaseMem/Length/Read ptr/Write ptr
11028c2ecf20Sopenharmony_ci	 *    TPD Ring/SMB/RXF0 Page CMBs, they use the same
11038c2ecf20Sopenharmony_ci	 *    High 32bits memory */
11048c2ecf20Sopenharmony_ci	atl1e_configure_des_ring(adapter);
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	/* 5. set Interrupt Moderator Timer */
11078c2ecf20Sopenharmony_ci	AT_WRITE_REGW(hw, REG_IRQ_MODU_TIMER_INIT, hw->imt);
11088c2ecf20Sopenharmony_ci	AT_WRITE_REGW(hw, REG_IRQ_MODU_TIMER2_INIT, hw->imt);
11098c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_LED_MODE |
11108c2ecf20Sopenharmony_ci			MASTER_CTRL_ITIMER_EN | MASTER_CTRL_ITIMER2_EN);
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	/* 6. rx/tx threshold to trig interrupt */
11138c2ecf20Sopenharmony_ci	AT_WRITE_REGW(hw, REG_TRIG_RRD_THRESH, hw->rrd_thresh);
11148c2ecf20Sopenharmony_ci	AT_WRITE_REGW(hw, REG_TRIG_TPD_THRESH, hw->tpd_thresh);
11158c2ecf20Sopenharmony_ci	AT_WRITE_REGW(hw, REG_TRIG_RXTIMER, hw->rx_count_down);
11168c2ecf20Sopenharmony_ci	AT_WRITE_REGW(hw, REG_TRIG_TXTIMER, hw->tx_count_down);
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	/* 7. set Interrupt Clear Timer */
11198c2ecf20Sopenharmony_ci	AT_WRITE_REGW(hw, REG_CMBDISDMA_TIMER, hw->ict);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	/* 8. set MTU */
11228c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_MTU, hw->max_frame_size + ETH_HLEN +
11238c2ecf20Sopenharmony_ci			VLAN_HLEN + ETH_FCS_LEN);
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	/* 9. config TXQ early tx threshold */
11268c2ecf20Sopenharmony_ci	atl1e_configure_tx(adapter);
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	/* 10. config RXQ */
11298c2ecf20Sopenharmony_ci	atl1e_configure_rx(adapter);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	/* 11. config  DMA Engine */
11328c2ecf20Sopenharmony_ci	atl1e_configure_dma(adapter);
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	/* 12. smb timer to trig interrupt */
11358c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_SMB_STAT_TIMER, hw->smb_timer);
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	intr_status_data = AT_READ_REG(hw, REG_ISR);
11388c2ecf20Sopenharmony_ci	if (unlikely((intr_status_data & ISR_PHY_LINKDOWN) != 0)) {
11398c2ecf20Sopenharmony_ci		netdev_err(adapter->netdev,
11408c2ecf20Sopenharmony_ci			   "atl1e_configure failed, PCIE phy link down\n");
11418c2ecf20Sopenharmony_ci		return -1;
11428c2ecf20Sopenharmony_ci	}
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_ISR, 0x7fffffff);
11458c2ecf20Sopenharmony_ci	return 0;
11468c2ecf20Sopenharmony_ci}
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci/**
11498c2ecf20Sopenharmony_ci * atl1e_get_stats - Get System Network Statistics
11508c2ecf20Sopenharmony_ci * @netdev: network interface device structure
11518c2ecf20Sopenharmony_ci *
11528c2ecf20Sopenharmony_ci * Returns the address of the device statistics structure.
11538c2ecf20Sopenharmony_ci * The statistics are actually updated from the timer callback.
11548c2ecf20Sopenharmony_ci */
11558c2ecf20Sopenharmony_cistatic struct net_device_stats *atl1e_get_stats(struct net_device *netdev)
11568c2ecf20Sopenharmony_ci{
11578c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
11588c2ecf20Sopenharmony_ci	struct atl1e_hw_stats  *hw_stats = &adapter->hw_stats;
11598c2ecf20Sopenharmony_ci	struct net_device_stats *net_stats = &netdev->stats;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	net_stats->rx_bytes   = hw_stats->rx_byte_cnt;
11628c2ecf20Sopenharmony_ci	net_stats->tx_bytes   = hw_stats->tx_byte_cnt;
11638c2ecf20Sopenharmony_ci	net_stats->multicast  = hw_stats->rx_mcast;
11648c2ecf20Sopenharmony_ci	net_stats->collisions = hw_stats->tx_1_col +
11658c2ecf20Sopenharmony_ci				hw_stats->tx_2_col +
11668c2ecf20Sopenharmony_ci				hw_stats->tx_late_col +
11678c2ecf20Sopenharmony_ci				hw_stats->tx_abort_col;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	net_stats->rx_errors  = hw_stats->rx_frag +
11708c2ecf20Sopenharmony_ci				hw_stats->rx_fcs_err +
11718c2ecf20Sopenharmony_ci				hw_stats->rx_len_err +
11728c2ecf20Sopenharmony_ci				hw_stats->rx_sz_ov +
11738c2ecf20Sopenharmony_ci				hw_stats->rx_rrd_ov +
11748c2ecf20Sopenharmony_ci				hw_stats->rx_align_err +
11758c2ecf20Sopenharmony_ci				hw_stats->rx_rxf_ov;
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	net_stats->rx_fifo_errors   = hw_stats->rx_rxf_ov;
11788c2ecf20Sopenharmony_ci	net_stats->rx_length_errors = hw_stats->rx_len_err;
11798c2ecf20Sopenharmony_ci	net_stats->rx_crc_errors    = hw_stats->rx_fcs_err;
11808c2ecf20Sopenharmony_ci	net_stats->rx_frame_errors  = hw_stats->rx_align_err;
11818c2ecf20Sopenharmony_ci	net_stats->rx_dropped       = hw_stats->rx_rrd_ov;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	net_stats->tx_errors = hw_stats->tx_late_col +
11848c2ecf20Sopenharmony_ci			       hw_stats->tx_abort_col +
11858c2ecf20Sopenharmony_ci			       hw_stats->tx_underrun +
11868c2ecf20Sopenharmony_ci			       hw_stats->tx_trunc;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	net_stats->tx_fifo_errors    = hw_stats->tx_underrun;
11898c2ecf20Sopenharmony_ci	net_stats->tx_aborted_errors = hw_stats->tx_abort_col;
11908c2ecf20Sopenharmony_ci	net_stats->tx_window_errors  = hw_stats->tx_late_col;
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors;
11938c2ecf20Sopenharmony_ci	net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	return net_stats;
11968c2ecf20Sopenharmony_ci}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_cistatic void atl1e_update_hw_stats(struct atl1e_adapter *adapter)
11998c2ecf20Sopenharmony_ci{
12008c2ecf20Sopenharmony_ci	u16 hw_reg_addr = 0;
12018c2ecf20Sopenharmony_ci	unsigned long *stats_item = NULL;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	/* update rx status */
12048c2ecf20Sopenharmony_ci	hw_reg_addr = REG_MAC_RX_STATUS_BIN;
12058c2ecf20Sopenharmony_ci	stats_item  = &adapter->hw_stats.rx_ok;
12068c2ecf20Sopenharmony_ci	while (hw_reg_addr <= REG_MAC_RX_STATUS_END) {
12078c2ecf20Sopenharmony_ci		*stats_item += AT_READ_REG(&adapter->hw, hw_reg_addr);
12088c2ecf20Sopenharmony_ci		stats_item++;
12098c2ecf20Sopenharmony_ci		hw_reg_addr += 4;
12108c2ecf20Sopenharmony_ci	}
12118c2ecf20Sopenharmony_ci	/* update tx status */
12128c2ecf20Sopenharmony_ci	hw_reg_addr = REG_MAC_TX_STATUS_BIN;
12138c2ecf20Sopenharmony_ci	stats_item  = &adapter->hw_stats.tx_ok;
12148c2ecf20Sopenharmony_ci	while (hw_reg_addr <= REG_MAC_TX_STATUS_END) {
12158c2ecf20Sopenharmony_ci		*stats_item += AT_READ_REG(&adapter->hw, hw_reg_addr);
12168c2ecf20Sopenharmony_ci		stats_item++;
12178c2ecf20Sopenharmony_ci		hw_reg_addr += 4;
12188c2ecf20Sopenharmony_ci	}
12198c2ecf20Sopenharmony_ci}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_cistatic inline void atl1e_clear_phy_int(struct atl1e_adapter *adapter)
12228c2ecf20Sopenharmony_ci{
12238c2ecf20Sopenharmony_ci	u16 phy_data;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	spin_lock(&adapter->mdio_lock);
12268c2ecf20Sopenharmony_ci	atl1e_read_phy_reg(&adapter->hw, MII_INT_STATUS, &phy_data);
12278c2ecf20Sopenharmony_ci	spin_unlock(&adapter->mdio_lock);
12288c2ecf20Sopenharmony_ci}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_cistatic bool atl1e_clean_tx_irq(struct atl1e_adapter *adapter)
12318c2ecf20Sopenharmony_ci{
12328c2ecf20Sopenharmony_ci	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
12338c2ecf20Sopenharmony_ci	struct atl1e_tx_buffer *tx_buffer = NULL;
12348c2ecf20Sopenharmony_ci	u16 hw_next_to_clean = AT_READ_REGW(&adapter->hw, REG_TPD_CONS_IDX);
12358c2ecf20Sopenharmony_ci	u16 next_to_clean = atomic_read(&tx_ring->next_to_clean);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	while (next_to_clean != hw_next_to_clean) {
12388c2ecf20Sopenharmony_ci		tx_buffer = &tx_ring->tx_buffer[next_to_clean];
12398c2ecf20Sopenharmony_ci		if (tx_buffer->dma) {
12408c2ecf20Sopenharmony_ci			if (tx_buffer->flags & ATL1E_TX_PCIMAP_SINGLE)
12418c2ecf20Sopenharmony_ci				dma_unmap_single(&adapter->pdev->dev,
12428c2ecf20Sopenharmony_ci						 tx_buffer->dma,
12438c2ecf20Sopenharmony_ci						 tx_buffer->length,
12448c2ecf20Sopenharmony_ci						 DMA_TO_DEVICE);
12458c2ecf20Sopenharmony_ci			else if (tx_buffer->flags & ATL1E_TX_PCIMAP_PAGE)
12468c2ecf20Sopenharmony_ci				dma_unmap_page(&adapter->pdev->dev,
12478c2ecf20Sopenharmony_ci					       tx_buffer->dma,
12488c2ecf20Sopenharmony_ci					       tx_buffer->length,
12498c2ecf20Sopenharmony_ci					       DMA_TO_DEVICE);
12508c2ecf20Sopenharmony_ci			tx_buffer->dma = 0;
12518c2ecf20Sopenharmony_ci		}
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci		if (tx_buffer->skb) {
12548c2ecf20Sopenharmony_ci			dev_consume_skb_irq(tx_buffer->skb);
12558c2ecf20Sopenharmony_ci			tx_buffer->skb = NULL;
12568c2ecf20Sopenharmony_ci		}
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci		if (++next_to_clean == tx_ring->count)
12598c2ecf20Sopenharmony_ci			next_to_clean = 0;
12608c2ecf20Sopenharmony_ci	}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	atomic_set(&tx_ring->next_to_clean, next_to_clean);
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	if (netif_queue_stopped(adapter->netdev) &&
12658c2ecf20Sopenharmony_ci			netif_carrier_ok(adapter->netdev)) {
12668c2ecf20Sopenharmony_ci		netif_wake_queue(adapter->netdev);
12678c2ecf20Sopenharmony_ci	}
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci	return true;
12708c2ecf20Sopenharmony_ci}
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci/**
12738c2ecf20Sopenharmony_ci * atl1e_intr - Interrupt Handler
12748c2ecf20Sopenharmony_ci * @irq: interrupt number
12758c2ecf20Sopenharmony_ci * @data: pointer to a network interface device structure
12768c2ecf20Sopenharmony_ci */
12778c2ecf20Sopenharmony_cistatic irqreturn_t atl1e_intr(int irq, void *data)
12788c2ecf20Sopenharmony_ci{
12798c2ecf20Sopenharmony_ci	struct net_device *netdev  = data;
12808c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
12818c2ecf20Sopenharmony_ci	struct atl1e_hw *hw = &adapter->hw;
12828c2ecf20Sopenharmony_ci	int max_ints = AT_MAX_INT_WORK;
12838c2ecf20Sopenharmony_ci	int handled = IRQ_NONE;
12848c2ecf20Sopenharmony_ci	u32 status;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	do {
12878c2ecf20Sopenharmony_ci		status = AT_READ_REG(hw, REG_ISR);
12888c2ecf20Sopenharmony_ci		if ((status & IMR_NORMAL_MASK) == 0 ||
12898c2ecf20Sopenharmony_ci				(status & ISR_DIS_INT) != 0) {
12908c2ecf20Sopenharmony_ci			if (max_ints != AT_MAX_INT_WORK)
12918c2ecf20Sopenharmony_ci				handled = IRQ_HANDLED;
12928c2ecf20Sopenharmony_ci			break;
12938c2ecf20Sopenharmony_ci		}
12948c2ecf20Sopenharmony_ci		/* link event */
12958c2ecf20Sopenharmony_ci		if (status & ISR_GPHY)
12968c2ecf20Sopenharmony_ci			atl1e_clear_phy_int(adapter);
12978c2ecf20Sopenharmony_ci		/* Ack ISR */
12988c2ecf20Sopenharmony_ci		AT_WRITE_REG(hw, REG_ISR, status | ISR_DIS_INT);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci		handled = IRQ_HANDLED;
13018c2ecf20Sopenharmony_ci		/* check if PCIE PHY Link down */
13028c2ecf20Sopenharmony_ci		if (status & ISR_PHY_LINKDOWN) {
13038c2ecf20Sopenharmony_ci			netdev_err(adapter->netdev,
13048c2ecf20Sopenharmony_ci				   "pcie phy linkdown %x\n", status);
13058c2ecf20Sopenharmony_ci			if (netif_running(adapter->netdev)) {
13068c2ecf20Sopenharmony_ci				/* reset MAC */
13078c2ecf20Sopenharmony_ci				atl1e_irq_reset(adapter);
13088c2ecf20Sopenharmony_ci				schedule_work(&adapter->reset_task);
13098c2ecf20Sopenharmony_ci				break;
13108c2ecf20Sopenharmony_ci			}
13118c2ecf20Sopenharmony_ci		}
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci		/* check if DMA read/write error */
13148c2ecf20Sopenharmony_ci		if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
13158c2ecf20Sopenharmony_ci			netdev_err(adapter->netdev,
13168c2ecf20Sopenharmony_ci				   "PCIE DMA RW error (status = 0x%x)\n",
13178c2ecf20Sopenharmony_ci				   status);
13188c2ecf20Sopenharmony_ci			atl1e_irq_reset(adapter);
13198c2ecf20Sopenharmony_ci			schedule_work(&adapter->reset_task);
13208c2ecf20Sopenharmony_ci			break;
13218c2ecf20Sopenharmony_ci		}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci		if (status & ISR_SMB)
13248c2ecf20Sopenharmony_ci			atl1e_update_hw_stats(adapter);
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci		/* link event */
13278c2ecf20Sopenharmony_ci		if (status & (ISR_GPHY | ISR_MANUAL)) {
13288c2ecf20Sopenharmony_ci			netdev->stats.tx_carrier_errors++;
13298c2ecf20Sopenharmony_ci			atl1e_link_chg_event(adapter);
13308c2ecf20Sopenharmony_ci			break;
13318c2ecf20Sopenharmony_ci		}
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci		/* transmit event */
13348c2ecf20Sopenharmony_ci		if (status & ISR_TX_EVENT)
13358c2ecf20Sopenharmony_ci			atl1e_clean_tx_irq(adapter);
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci		if (status & ISR_RX_EVENT) {
13388c2ecf20Sopenharmony_ci			/*
13398c2ecf20Sopenharmony_ci			 * disable rx interrupts, without
13408c2ecf20Sopenharmony_ci			 * the synchronize_irq bit
13418c2ecf20Sopenharmony_ci			 */
13428c2ecf20Sopenharmony_ci			AT_WRITE_REG(hw, REG_IMR,
13438c2ecf20Sopenharmony_ci				     IMR_NORMAL_MASK & ~ISR_RX_EVENT);
13448c2ecf20Sopenharmony_ci			AT_WRITE_FLUSH(hw);
13458c2ecf20Sopenharmony_ci			if (likely(napi_schedule_prep(
13468c2ecf20Sopenharmony_ci				   &adapter->napi)))
13478c2ecf20Sopenharmony_ci				__napi_schedule(&adapter->napi);
13488c2ecf20Sopenharmony_ci		}
13498c2ecf20Sopenharmony_ci	} while (--max_ints > 0);
13508c2ecf20Sopenharmony_ci	/* re-enable Interrupt*/
13518c2ecf20Sopenharmony_ci	AT_WRITE_REG(&adapter->hw, REG_ISR, 0);
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	return handled;
13548c2ecf20Sopenharmony_ci}
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_cistatic inline void atl1e_rx_checksum(struct atl1e_adapter *adapter,
13578c2ecf20Sopenharmony_ci		  struct sk_buff *skb, struct atl1e_recv_ret_status *prrs)
13588c2ecf20Sopenharmony_ci{
13598c2ecf20Sopenharmony_ci	u8 *packet = (u8 *)(prrs + 1);
13608c2ecf20Sopenharmony_ci	struct iphdr *iph;
13618c2ecf20Sopenharmony_ci	u16 head_len = ETH_HLEN;
13628c2ecf20Sopenharmony_ci	u16 pkt_flags;
13638c2ecf20Sopenharmony_ci	u16 err_flags;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	skb_checksum_none_assert(skb);
13668c2ecf20Sopenharmony_ci	pkt_flags = prrs->pkt_flag;
13678c2ecf20Sopenharmony_ci	err_flags = prrs->err_flag;
13688c2ecf20Sopenharmony_ci	if (((pkt_flags & RRS_IS_IPV4) || (pkt_flags & RRS_IS_IPV6)) &&
13698c2ecf20Sopenharmony_ci		((pkt_flags & RRS_IS_TCP) || (pkt_flags & RRS_IS_UDP))) {
13708c2ecf20Sopenharmony_ci		if (pkt_flags & RRS_IS_IPV4) {
13718c2ecf20Sopenharmony_ci			if (pkt_flags & RRS_IS_802_3)
13728c2ecf20Sopenharmony_ci				head_len += 8;
13738c2ecf20Sopenharmony_ci			iph = (struct iphdr *) (packet + head_len);
13748c2ecf20Sopenharmony_ci			if (iph->frag_off != 0 && !(pkt_flags & RRS_IS_IP_DF))
13758c2ecf20Sopenharmony_ci				goto hw_xsum;
13768c2ecf20Sopenharmony_ci		}
13778c2ecf20Sopenharmony_ci		if (!(err_flags & (RRS_ERR_IP_CSUM | RRS_ERR_L4_CSUM))) {
13788c2ecf20Sopenharmony_ci			skb->ip_summed = CHECKSUM_UNNECESSARY;
13798c2ecf20Sopenharmony_ci			return;
13808c2ecf20Sopenharmony_ci		}
13818c2ecf20Sopenharmony_ci	}
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_cihw_xsum :
13848c2ecf20Sopenharmony_ci	return;
13858c2ecf20Sopenharmony_ci}
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_cistatic struct atl1e_rx_page *atl1e_get_rx_page(struct atl1e_adapter *adapter,
13888c2ecf20Sopenharmony_ci					       u8 que)
13898c2ecf20Sopenharmony_ci{
13908c2ecf20Sopenharmony_ci	struct atl1e_rx_page_desc *rx_page_desc =
13918c2ecf20Sopenharmony_ci		(struct atl1e_rx_page_desc *) adapter->rx_ring.rx_page_desc;
13928c2ecf20Sopenharmony_ci	u8 rx_using = rx_page_desc[que].rx_using;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	return &(rx_page_desc[que].rx_page[rx_using]);
13958c2ecf20Sopenharmony_ci}
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_cistatic void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que,
13988c2ecf20Sopenharmony_ci		   int *work_done, int work_to_do)
13998c2ecf20Sopenharmony_ci{
14008c2ecf20Sopenharmony_ci	struct net_device *netdev  = adapter->netdev;
14018c2ecf20Sopenharmony_ci	struct atl1e_rx_ring *rx_ring = &adapter->rx_ring;
14028c2ecf20Sopenharmony_ci	struct atl1e_rx_page_desc *rx_page_desc =
14038c2ecf20Sopenharmony_ci		(struct atl1e_rx_page_desc *) rx_ring->rx_page_desc;
14048c2ecf20Sopenharmony_ci	struct sk_buff *skb = NULL;
14058c2ecf20Sopenharmony_ci	struct atl1e_rx_page *rx_page = atl1e_get_rx_page(adapter, que);
14068c2ecf20Sopenharmony_ci	u32 packet_size, write_offset;
14078c2ecf20Sopenharmony_ci	struct atl1e_recv_ret_status *prrs;
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	write_offset = *(rx_page->write_offset_addr);
14108c2ecf20Sopenharmony_ci	if (likely(rx_page->read_offset < write_offset)) {
14118c2ecf20Sopenharmony_ci		do {
14128c2ecf20Sopenharmony_ci			if (*work_done >= work_to_do)
14138c2ecf20Sopenharmony_ci				break;
14148c2ecf20Sopenharmony_ci			(*work_done)++;
14158c2ecf20Sopenharmony_ci			/* get new packet's  rrs */
14168c2ecf20Sopenharmony_ci			prrs = (struct atl1e_recv_ret_status *) (rx_page->addr +
14178c2ecf20Sopenharmony_ci						 rx_page->read_offset);
14188c2ecf20Sopenharmony_ci			/* check sequence number */
14198c2ecf20Sopenharmony_ci			if (prrs->seq_num != rx_page_desc[que].rx_nxseq) {
14208c2ecf20Sopenharmony_ci				netdev_err(netdev,
14218c2ecf20Sopenharmony_ci					   "rx sequence number error (rx=%d) (expect=%d)\n",
14228c2ecf20Sopenharmony_ci					   prrs->seq_num,
14238c2ecf20Sopenharmony_ci					   rx_page_desc[que].rx_nxseq);
14248c2ecf20Sopenharmony_ci				rx_page_desc[que].rx_nxseq++;
14258c2ecf20Sopenharmony_ci				/* just for debug use */
14268c2ecf20Sopenharmony_ci				AT_WRITE_REG(&adapter->hw, REG_DEBUG_DATA0,
14278c2ecf20Sopenharmony_ci					     (((u32)prrs->seq_num) << 16) |
14288c2ecf20Sopenharmony_ci					     rx_page_desc[que].rx_nxseq);
14298c2ecf20Sopenharmony_ci				goto fatal_err;
14308c2ecf20Sopenharmony_ci			}
14318c2ecf20Sopenharmony_ci			rx_page_desc[que].rx_nxseq++;
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci			/* error packet */
14348c2ecf20Sopenharmony_ci			if ((prrs->pkt_flag & RRS_IS_ERR_FRAME) &&
14358c2ecf20Sopenharmony_ci			    !(netdev->features & NETIF_F_RXALL)) {
14368c2ecf20Sopenharmony_ci				if (prrs->err_flag & (RRS_ERR_BAD_CRC |
14378c2ecf20Sopenharmony_ci					RRS_ERR_DRIBBLE | RRS_ERR_CODE |
14388c2ecf20Sopenharmony_ci					RRS_ERR_TRUNC)) {
14398c2ecf20Sopenharmony_ci				/* hardware error, discard this packet*/
14408c2ecf20Sopenharmony_ci					netdev_err(netdev,
14418c2ecf20Sopenharmony_ci						   "rx packet desc error %x\n",
14428c2ecf20Sopenharmony_ci						   *((u32 *)prrs + 1));
14438c2ecf20Sopenharmony_ci					goto skip_pkt;
14448c2ecf20Sopenharmony_ci				}
14458c2ecf20Sopenharmony_ci			}
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci			packet_size = ((prrs->word1 >> RRS_PKT_SIZE_SHIFT) &
14488c2ecf20Sopenharmony_ci					RRS_PKT_SIZE_MASK);
14498c2ecf20Sopenharmony_ci			if (likely(!(netdev->features & NETIF_F_RXFCS)))
14508c2ecf20Sopenharmony_ci				packet_size -= 4; /* CRC */
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci			skb = netdev_alloc_skb_ip_align(netdev, packet_size);
14538c2ecf20Sopenharmony_ci			if (skb == NULL)
14548c2ecf20Sopenharmony_ci				goto skip_pkt;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci			memcpy(skb->data, (u8 *)(prrs + 1), packet_size);
14578c2ecf20Sopenharmony_ci			skb_put(skb, packet_size);
14588c2ecf20Sopenharmony_ci			skb->protocol = eth_type_trans(skb, netdev);
14598c2ecf20Sopenharmony_ci			atl1e_rx_checksum(adapter, skb, prrs);
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci			if (prrs->pkt_flag & RRS_IS_VLAN_TAG) {
14628c2ecf20Sopenharmony_ci				u16 vlan_tag = (prrs->vtag >> 4) |
14638c2ecf20Sopenharmony_ci					       ((prrs->vtag & 7) << 13) |
14648c2ecf20Sopenharmony_ci					       ((prrs->vtag & 8) << 9);
14658c2ecf20Sopenharmony_ci				netdev_dbg(netdev,
14668c2ecf20Sopenharmony_ci					   "RXD VLAN TAG<RRD>=0x%04x\n",
14678c2ecf20Sopenharmony_ci					   prrs->vtag);
14688c2ecf20Sopenharmony_ci				__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
14698c2ecf20Sopenharmony_ci			}
14708c2ecf20Sopenharmony_ci			napi_gro_receive(&adapter->napi, skb);
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ciskip_pkt:
14738c2ecf20Sopenharmony_ci	/* skip current packet whether it's ok or not. */
14748c2ecf20Sopenharmony_ci			rx_page->read_offset +=
14758c2ecf20Sopenharmony_ci				(((u32)((prrs->word1 >> RRS_PKT_SIZE_SHIFT) &
14768c2ecf20Sopenharmony_ci				RRS_PKT_SIZE_MASK) +
14778c2ecf20Sopenharmony_ci				sizeof(struct atl1e_recv_ret_status) + 31) &
14788c2ecf20Sopenharmony_ci						0xFFFFFFE0);
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci			if (rx_page->read_offset >= rx_ring->page_size) {
14818c2ecf20Sopenharmony_ci				/* mark this page clean */
14828c2ecf20Sopenharmony_ci				u16 reg_addr;
14838c2ecf20Sopenharmony_ci				u8  rx_using;
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci				rx_page->read_offset =
14868c2ecf20Sopenharmony_ci					*(rx_page->write_offset_addr) = 0;
14878c2ecf20Sopenharmony_ci				rx_using = rx_page_desc[que].rx_using;
14888c2ecf20Sopenharmony_ci				reg_addr =
14898c2ecf20Sopenharmony_ci					atl1e_rx_page_vld_regs[que][rx_using];
14908c2ecf20Sopenharmony_ci				AT_WRITE_REGB(&adapter->hw, reg_addr, 1);
14918c2ecf20Sopenharmony_ci				rx_page_desc[que].rx_using ^= 1;
14928c2ecf20Sopenharmony_ci				rx_page = atl1e_get_rx_page(adapter, que);
14938c2ecf20Sopenharmony_ci			}
14948c2ecf20Sopenharmony_ci			write_offset = *(rx_page->write_offset_addr);
14958c2ecf20Sopenharmony_ci		} while (rx_page->read_offset < write_offset);
14968c2ecf20Sopenharmony_ci	}
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	return;
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_cifatal_err:
15018c2ecf20Sopenharmony_ci	if (!test_bit(__AT_DOWN, &adapter->flags))
15028c2ecf20Sopenharmony_ci		schedule_work(&adapter->reset_task);
15038c2ecf20Sopenharmony_ci}
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci/**
15068c2ecf20Sopenharmony_ci * atl1e_clean - NAPI Rx polling callback
15078c2ecf20Sopenharmony_ci * @napi: napi info
15088c2ecf20Sopenharmony_ci * @budget: number of packets to clean
15098c2ecf20Sopenharmony_ci */
15108c2ecf20Sopenharmony_cistatic int atl1e_clean(struct napi_struct *napi, int budget)
15118c2ecf20Sopenharmony_ci{
15128c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter =
15138c2ecf20Sopenharmony_ci			container_of(napi, struct atl1e_adapter, napi);
15148c2ecf20Sopenharmony_ci	u32 imr_data;
15158c2ecf20Sopenharmony_ci	int work_done = 0;
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	/* Keep link state information with original netdev */
15188c2ecf20Sopenharmony_ci	if (!netif_carrier_ok(adapter->netdev))
15198c2ecf20Sopenharmony_ci		goto quit_polling;
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci	atl1e_clean_rx_irq(adapter, 0, &work_done, budget);
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	/* If no Tx and not enough Rx work done, exit the polling mode */
15248c2ecf20Sopenharmony_ci	if (work_done < budget) {
15258c2ecf20Sopenharmony_ciquit_polling:
15268c2ecf20Sopenharmony_ci		napi_complete_done(napi, work_done);
15278c2ecf20Sopenharmony_ci		imr_data = AT_READ_REG(&adapter->hw, REG_IMR);
15288c2ecf20Sopenharmony_ci		AT_WRITE_REG(&adapter->hw, REG_IMR, imr_data | ISR_RX_EVENT);
15298c2ecf20Sopenharmony_ci		/* test debug */
15308c2ecf20Sopenharmony_ci		if (test_bit(__AT_DOWN, &adapter->flags)) {
15318c2ecf20Sopenharmony_ci			atomic_dec(&adapter->irq_sem);
15328c2ecf20Sopenharmony_ci			netdev_err(adapter->netdev,
15338c2ecf20Sopenharmony_ci				   "atl1e_clean is called when AT_DOWN\n");
15348c2ecf20Sopenharmony_ci		}
15358c2ecf20Sopenharmony_ci		/* reenable RX intr */
15368c2ecf20Sopenharmony_ci		/*atl1e_irq_enable(adapter); */
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	}
15398c2ecf20Sopenharmony_ci	return work_done;
15408c2ecf20Sopenharmony_ci}
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci/*
15458c2ecf20Sopenharmony_ci * Polling 'interrupt' - used by things like netconsole to send skbs
15468c2ecf20Sopenharmony_ci * without having to re-enable interrupts. It's not called while
15478c2ecf20Sopenharmony_ci * the interrupt routine is executing.
15488c2ecf20Sopenharmony_ci */
15498c2ecf20Sopenharmony_cistatic void atl1e_netpoll(struct net_device *netdev)
15508c2ecf20Sopenharmony_ci{
15518c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	disable_irq(adapter->pdev->irq);
15548c2ecf20Sopenharmony_ci	atl1e_intr(adapter->pdev->irq, netdev);
15558c2ecf20Sopenharmony_ci	enable_irq(adapter->pdev->irq);
15568c2ecf20Sopenharmony_ci}
15578c2ecf20Sopenharmony_ci#endif
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_cistatic inline u16 atl1e_tpd_avail(struct atl1e_adapter *adapter)
15608c2ecf20Sopenharmony_ci{
15618c2ecf20Sopenharmony_ci	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
15628c2ecf20Sopenharmony_ci	u16 next_to_use = 0;
15638c2ecf20Sopenharmony_ci	u16 next_to_clean = 0;
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	next_to_clean = atomic_read(&tx_ring->next_to_clean);
15668c2ecf20Sopenharmony_ci	next_to_use   = tx_ring->next_to_use;
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci	return (u16)(next_to_clean > next_to_use) ?
15698c2ecf20Sopenharmony_ci		(next_to_clean - next_to_use - 1) :
15708c2ecf20Sopenharmony_ci		(tx_ring->count + next_to_clean - next_to_use - 1);
15718c2ecf20Sopenharmony_ci}
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci/*
15748c2ecf20Sopenharmony_ci * get next usable tpd
15758c2ecf20Sopenharmony_ci * Note: should call atl1e_tdp_avail to make sure
15768c2ecf20Sopenharmony_ci * there is enough tpd to use
15778c2ecf20Sopenharmony_ci */
15788c2ecf20Sopenharmony_cistatic struct atl1e_tpd_desc *atl1e_get_tpd(struct atl1e_adapter *adapter)
15798c2ecf20Sopenharmony_ci{
15808c2ecf20Sopenharmony_ci	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
15818c2ecf20Sopenharmony_ci	u16 next_to_use = 0;
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	next_to_use = tx_ring->next_to_use;
15848c2ecf20Sopenharmony_ci	if (++tx_ring->next_to_use == tx_ring->count)
15858c2ecf20Sopenharmony_ci		tx_ring->next_to_use = 0;
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	memset(&tx_ring->desc[next_to_use], 0, sizeof(struct atl1e_tpd_desc));
15888c2ecf20Sopenharmony_ci	return &tx_ring->desc[next_to_use];
15898c2ecf20Sopenharmony_ci}
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_cistatic struct atl1e_tx_buffer *
15928c2ecf20Sopenharmony_ciatl1e_get_tx_buffer(struct atl1e_adapter *adapter, struct atl1e_tpd_desc *tpd)
15938c2ecf20Sopenharmony_ci{
15948c2ecf20Sopenharmony_ci	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci	return &tx_ring->tx_buffer[tpd - tx_ring->desc];
15978c2ecf20Sopenharmony_ci}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci/* Calculate the transmit packet descript needed*/
16008c2ecf20Sopenharmony_cistatic u16 atl1e_cal_tdp_req(const struct sk_buff *skb)
16018c2ecf20Sopenharmony_ci{
16028c2ecf20Sopenharmony_ci	int i = 0;
16038c2ecf20Sopenharmony_ci	u16 tpd_req = 1;
16048c2ecf20Sopenharmony_ci	u16 fg_size = 0;
16058c2ecf20Sopenharmony_ci	u16 proto_hdr_len = 0;
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
16088c2ecf20Sopenharmony_ci		fg_size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
16098c2ecf20Sopenharmony_ci		tpd_req += ((fg_size + MAX_TX_BUF_LEN - 1) >> MAX_TX_BUF_SHIFT);
16108c2ecf20Sopenharmony_ci	}
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	if (skb_is_gso(skb)) {
16138c2ecf20Sopenharmony_ci		if (skb->protocol == htons(ETH_P_IP) ||
16148c2ecf20Sopenharmony_ci		   (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6)) {
16158c2ecf20Sopenharmony_ci			proto_hdr_len = skb_transport_offset(skb) +
16168c2ecf20Sopenharmony_ci					tcp_hdrlen(skb);
16178c2ecf20Sopenharmony_ci			if (proto_hdr_len < skb_headlen(skb)) {
16188c2ecf20Sopenharmony_ci				tpd_req += ((skb_headlen(skb) - proto_hdr_len +
16198c2ecf20Sopenharmony_ci					   MAX_TX_BUF_LEN - 1) >>
16208c2ecf20Sopenharmony_ci					   MAX_TX_BUF_SHIFT);
16218c2ecf20Sopenharmony_ci			}
16228c2ecf20Sopenharmony_ci		}
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	}
16258c2ecf20Sopenharmony_ci	return tpd_req;
16268c2ecf20Sopenharmony_ci}
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_cistatic int atl1e_tso_csum(struct atl1e_adapter *adapter,
16298c2ecf20Sopenharmony_ci		       struct sk_buff *skb, struct atl1e_tpd_desc *tpd)
16308c2ecf20Sopenharmony_ci{
16318c2ecf20Sopenharmony_ci	unsigned short offload_type;
16328c2ecf20Sopenharmony_ci	u8 hdr_len;
16338c2ecf20Sopenharmony_ci	u32 real_len;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	if (skb_is_gso(skb)) {
16368c2ecf20Sopenharmony_ci		int err;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci		err = skb_cow_head(skb, 0);
16398c2ecf20Sopenharmony_ci		if (err < 0)
16408c2ecf20Sopenharmony_ci			return err;
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci		offload_type = skb_shinfo(skb)->gso_type;
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci		if (offload_type & SKB_GSO_TCPV4) {
16458c2ecf20Sopenharmony_ci			real_len = (((unsigned char *)ip_hdr(skb) - skb->data)
16468c2ecf20Sopenharmony_ci					+ ntohs(ip_hdr(skb)->tot_len));
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci			if (real_len < skb->len) {
16498c2ecf20Sopenharmony_ci				err = pskb_trim(skb, real_len);
16508c2ecf20Sopenharmony_ci				if (err)
16518c2ecf20Sopenharmony_ci					return err;
16528c2ecf20Sopenharmony_ci			}
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci			hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
16558c2ecf20Sopenharmony_ci			if (unlikely(skb->len == hdr_len)) {
16568c2ecf20Sopenharmony_ci				/* only xsum need */
16578c2ecf20Sopenharmony_ci				netdev_warn(adapter->netdev,
16588c2ecf20Sopenharmony_ci					    "IPV4 tso with zero data??\n");
16598c2ecf20Sopenharmony_ci				goto check_sum;
16608c2ecf20Sopenharmony_ci			} else {
16618c2ecf20Sopenharmony_ci				ip_hdr(skb)->check = 0;
16628c2ecf20Sopenharmony_ci				ip_hdr(skb)->tot_len = 0;
16638c2ecf20Sopenharmony_ci				tcp_hdr(skb)->check = ~csum_tcpudp_magic(
16648c2ecf20Sopenharmony_ci							ip_hdr(skb)->saddr,
16658c2ecf20Sopenharmony_ci							ip_hdr(skb)->daddr,
16668c2ecf20Sopenharmony_ci							0, IPPROTO_TCP, 0);
16678c2ecf20Sopenharmony_ci				tpd->word3 |= (ip_hdr(skb)->ihl &
16688c2ecf20Sopenharmony_ci					TDP_V4_IPHL_MASK) <<
16698c2ecf20Sopenharmony_ci					TPD_V4_IPHL_SHIFT;
16708c2ecf20Sopenharmony_ci				tpd->word3 |= ((tcp_hdrlen(skb) >> 2) &
16718c2ecf20Sopenharmony_ci					TPD_TCPHDRLEN_MASK) <<
16728c2ecf20Sopenharmony_ci					TPD_TCPHDRLEN_SHIFT;
16738c2ecf20Sopenharmony_ci				tpd->word3 |= ((skb_shinfo(skb)->gso_size) &
16748c2ecf20Sopenharmony_ci					TPD_MSS_MASK) << TPD_MSS_SHIFT;
16758c2ecf20Sopenharmony_ci				tpd->word3 |= 1 << TPD_SEGMENT_EN_SHIFT;
16768c2ecf20Sopenharmony_ci			}
16778c2ecf20Sopenharmony_ci			return 0;
16788c2ecf20Sopenharmony_ci		}
16798c2ecf20Sopenharmony_ci	}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_cicheck_sum:
16828c2ecf20Sopenharmony_ci	if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
16838c2ecf20Sopenharmony_ci		u8 css, cso;
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci		cso = skb_checksum_start_offset(skb);
16868c2ecf20Sopenharmony_ci		if (unlikely(cso & 0x1)) {
16878c2ecf20Sopenharmony_ci			netdev_err(adapter->netdev,
16888c2ecf20Sopenharmony_ci				   "payload offset should not ant event number\n");
16898c2ecf20Sopenharmony_ci			return -1;
16908c2ecf20Sopenharmony_ci		} else {
16918c2ecf20Sopenharmony_ci			css = cso + skb->csum_offset;
16928c2ecf20Sopenharmony_ci			tpd->word3 |= (cso & TPD_PLOADOFFSET_MASK) <<
16938c2ecf20Sopenharmony_ci					TPD_PLOADOFFSET_SHIFT;
16948c2ecf20Sopenharmony_ci			tpd->word3 |= (css & TPD_CCSUMOFFSET_MASK) <<
16958c2ecf20Sopenharmony_ci					TPD_CCSUMOFFSET_SHIFT;
16968c2ecf20Sopenharmony_ci			tpd->word3 |= 1 << TPD_CC_SEGMENT_EN_SHIFT;
16978c2ecf20Sopenharmony_ci		}
16988c2ecf20Sopenharmony_ci	}
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci	return 0;
17018c2ecf20Sopenharmony_ci}
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_cistatic int atl1e_tx_map(struct atl1e_adapter *adapter,
17048c2ecf20Sopenharmony_ci			struct sk_buff *skb, struct atl1e_tpd_desc *tpd)
17058c2ecf20Sopenharmony_ci{
17068c2ecf20Sopenharmony_ci	struct atl1e_tpd_desc *use_tpd = NULL;
17078c2ecf20Sopenharmony_ci	struct atl1e_tx_buffer *tx_buffer = NULL;
17088c2ecf20Sopenharmony_ci	u16 buf_len = skb_headlen(skb);
17098c2ecf20Sopenharmony_ci	u16 map_len = 0;
17108c2ecf20Sopenharmony_ci	u16 mapped_len = 0;
17118c2ecf20Sopenharmony_ci	u16 hdr_len = 0;
17128c2ecf20Sopenharmony_ci	u16 nr_frags;
17138c2ecf20Sopenharmony_ci	u16 f;
17148c2ecf20Sopenharmony_ci	int segment;
17158c2ecf20Sopenharmony_ci	int ring_start = adapter->tx_ring.next_to_use;
17168c2ecf20Sopenharmony_ci	int ring_end;
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	nr_frags = skb_shinfo(skb)->nr_frags;
17198c2ecf20Sopenharmony_ci	segment = (tpd->word3 >> TPD_SEGMENT_EN_SHIFT) & TPD_SEGMENT_EN_MASK;
17208c2ecf20Sopenharmony_ci	if (segment) {
17218c2ecf20Sopenharmony_ci		/* TSO */
17228c2ecf20Sopenharmony_ci		map_len = hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
17238c2ecf20Sopenharmony_ci		use_tpd = tpd;
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci		tx_buffer = atl1e_get_tx_buffer(adapter, use_tpd);
17268c2ecf20Sopenharmony_ci		tx_buffer->length = map_len;
17278c2ecf20Sopenharmony_ci		tx_buffer->dma = dma_map_single(&adapter->pdev->dev,
17288c2ecf20Sopenharmony_ci						skb->data, hdr_len,
17298c2ecf20Sopenharmony_ci						DMA_TO_DEVICE);
17308c2ecf20Sopenharmony_ci		if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma))
17318c2ecf20Sopenharmony_ci			return -ENOSPC;
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci		ATL1E_SET_PCIMAP_TYPE(tx_buffer, ATL1E_TX_PCIMAP_SINGLE);
17348c2ecf20Sopenharmony_ci		mapped_len += map_len;
17358c2ecf20Sopenharmony_ci		use_tpd->buffer_addr = cpu_to_le64(tx_buffer->dma);
17368c2ecf20Sopenharmony_ci		use_tpd->word2 = (use_tpd->word2 & (~TPD_BUFLEN_MASK)) |
17378c2ecf20Sopenharmony_ci			((cpu_to_le32(tx_buffer->length) &
17388c2ecf20Sopenharmony_ci			TPD_BUFLEN_MASK) << TPD_BUFLEN_SHIFT);
17398c2ecf20Sopenharmony_ci	}
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	while (mapped_len < buf_len) {
17428c2ecf20Sopenharmony_ci		/* mapped_len == 0, means we should use the first tpd,
17438c2ecf20Sopenharmony_ci		   which is given by caller  */
17448c2ecf20Sopenharmony_ci		if (mapped_len == 0) {
17458c2ecf20Sopenharmony_ci			use_tpd = tpd;
17468c2ecf20Sopenharmony_ci		} else {
17478c2ecf20Sopenharmony_ci			use_tpd = atl1e_get_tpd(adapter);
17488c2ecf20Sopenharmony_ci			memcpy(use_tpd, tpd, sizeof(struct atl1e_tpd_desc));
17498c2ecf20Sopenharmony_ci		}
17508c2ecf20Sopenharmony_ci		tx_buffer = atl1e_get_tx_buffer(adapter, use_tpd);
17518c2ecf20Sopenharmony_ci		tx_buffer->skb = NULL;
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci		tx_buffer->length = map_len =
17548c2ecf20Sopenharmony_ci			((buf_len - mapped_len) >= MAX_TX_BUF_LEN) ?
17558c2ecf20Sopenharmony_ci			MAX_TX_BUF_LEN : (buf_len - mapped_len);
17568c2ecf20Sopenharmony_ci		tx_buffer->dma =
17578c2ecf20Sopenharmony_ci			dma_map_single(&adapter->pdev->dev,
17588c2ecf20Sopenharmony_ci				       skb->data + mapped_len, map_len,
17598c2ecf20Sopenharmony_ci				       DMA_TO_DEVICE);
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci		if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) {
17628c2ecf20Sopenharmony_ci			/* We need to unwind the mappings we've done */
17638c2ecf20Sopenharmony_ci			ring_end = adapter->tx_ring.next_to_use;
17648c2ecf20Sopenharmony_ci			adapter->tx_ring.next_to_use = ring_start;
17658c2ecf20Sopenharmony_ci			while (adapter->tx_ring.next_to_use != ring_end) {
17668c2ecf20Sopenharmony_ci				tpd = atl1e_get_tpd(adapter);
17678c2ecf20Sopenharmony_ci				tx_buffer = atl1e_get_tx_buffer(adapter, tpd);
17688c2ecf20Sopenharmony_ci				dma_unmap_single(&adapter->pdev->dev,
17698c2ecf20Sopenharmony_ci						 tx_buffer->dma,
17708c2ecf20Sopenharmony_ci						 tx_buffer->length,
17718c2ecf20Sopenharmony_ci						 DMA_TO_DEVICE);
17728c2ecf20Sopenharmony_ci			}
17738c2ecf20Sopenharmony_ci			/* Reset the tx rings next pointer */
17748c2ecf20Sopenharmony_ci			adapter->tx_ring.next_to_use = ring_start;
17758c2ecf20Sopenharmony_ci			return -ENOSPC;
17768c2ecf20Sopenharmony_ci		}
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci		ATL1E_SET_PCIMAP_TYPE(tx_buffer, ATL1E_TX_PCIMAP_SINGLE);
17798c2ecf20Sopenharmony_ci		mapped_len  += map_len;
17808c2ecf20Sopenharmony_ci		use_tpd->buffer_addr = cpu_to_le64(tx_buffer->dma);
17818c2ecf20Sopenharmony_ci		use_tpd->word2 = (use_tpd->word2 & (~TPD_BUFLEN_MASK)) |
17828c2ecf20Sopenharmony_ci			((cpu_to_le32(tx_buffer->length) &
17838c2ecf20Sopenharmony_ci			TPD_BUFLEN_MASK) << TPD_BUFLEN_SHIFT);
17848c2ecf20Sopenharmony_ci	}
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	for (f = 0; f < nr_frags; f++) {
17878c2ecf20Sopenharmony_ci		const skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
17888c2ecf20Sopenharmony_ci		u16 i;
17898c2ecf20Sopenharmony_ci		u16 seg_num;
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci		buf_len = skb_frag_size(frag);
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci		seg_num = (buf_len + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
17948c2ecf20Sopenharmony_ci		for (i = 0; i < seg_num; i++) {
17958c2ecf20Sopenharmony_ci			use_tpd = atl1e_get_tpd(adapter);
17968c2ecf20Sopenharmony_ci			memcpy(use_tpd, tpd, sizeof(struct atl1e_tpd_desc));
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci			tx_buffer = atl1e_get_tx_buffer(adapter, use_tpd);
17998c2ecf20Sopenharmony_ci			BUG_ON(tx_buffer->skb);
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci			tx_buffer->skb = NULL;
18028c2ecf20Sopenharmony_ci			tx_buffer->length =
18038c2ecf20Sopenharmony_ci				(buf_len > MAX_TX_BUF_LEN) ?
18048c2ecf20Sopenharmony_ci				MAX_TX_BUF_LEN : buf_len;
18058c2ecf20Sopenharmony_ci			buf_len -= tx_buffer->length;
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci			tx_buffer->dma = skb_frag_dma_map(&adapter->pdev->dev,
18088c2ecf20Sopenharmony_ci							  frag,
18098c2ecf20Sopenharmony_ci							  (i * MAX_TX_BUF_LEN),
18108c2ecf20Sopenharmony_ci							  tx_buffer->length,
18118c2ecf20Sopenharmony_ci							  DMA_TO_DEVICE);
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci			if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) {
18148c2ecf20Sopenharmony_ci				/* We need to unwind the mappings we've done */
18158c2ecf20Sopenharmony_ci				ring_end = adapter->tx_ring.next_to_use;
18168c2ecf20Sopenharmony_ci				adapter->tx_ring.next_to_use = ring_start;
18178c2ecf20Sopenharmony_ci				while (adapter->tx_ring.next_to_use != ring_end) {
18188c2ecf20Sopenharmony_ci					tpd = atl1e_get_tpd(adapter);
18198c2ecf20Sopenharmony_ci					tx_buffer = atl1e_get_tx_buffer(adapter, tpd);
18208c2ecf20Sopenharmony_ci					dma_unmap_page(&adapter->pdev->dev, tx_buffer->dma,
18218c2ecf20Sopenharmony_ci						       tx_buffer->length, DMA_TO_DEVICE);
18228c2ecf20Sopenharmony_ci				}
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci				/* Reset the ring next to use pointer */
18258c2ecf20Sopenharmony_ci				adapter->tx_ring.next_to_use = ring_start;
18268c2ecf20Sopenharmony_ci				return -ENOSPC;
18278c2ecf20Sopenharmony_ci			}
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci			ATL1E_SET_PCIMAP_TYPE(tx_buffer, ATL1E_TX_PCIMAP_PAGE);
18308c2ecf20Sopenharmony_ci			use_tpd->buffer_addr = cpu_to_le64(tx_buffer->dma);
18318c2ecf20Sopenharmony_ci			use_tpd->word2 = (use_tpd->word2 & (~TPD_BUFLEN_MASK)) |
18328c2ecf20Sopenharmony_ci					((cpu_to_le32(tx_buffer->length) &
18338c2ecf20Sopenharmony_ci					TPD_BUFLEN_MASK) << TPD_BUFLEN_SHIFT);
18348c2ecf20Sopenharmony_ci		}
18358c2ecf20Sopenharmony_ci	}
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	if ((tpd->word3 >> TPD_SEGMENT_EN_SHIFT) & TPD_SEGMENT_EN_MASK)
18388c2ecf20Sopenharmony_ci		/* note this one is a tcp header */
18398c2ecf20Sopenharmony_ci		tpd->word3 |= 1 << TPD_HDRFLAG_SHIFT;
18408c2ecf20Sopenharmony_ci	/* The last tpd */
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	use_tpd->word3 |= 1 << TPD_EOP_SHIFT;
18438c2ecf20Sopenharmony_ci	/* The last buffer info contain the skb address,
18448c2ecf20Sopenharmony_ci	   so it will be free after unmap */
18458c2ecf20Sopenharmony_ci	tx_buffer->skb = skb;
18468c2ecf20Sopenharmony_ci	return 0;
18478c2ecf20Sopenharmony_ci}
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_cistatic void atl1e_tx_queue(struct atl1e_adapter *adapter, u16 count,
18508c2ecf20Sopenharmony_ci			   struct atl1e_tpd_desc *tpd)
18518c2ecf20Sopenharmony_ci{
18528c2ecf20Sopenharmony_ci	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
18538c2ecf20Sopenharmony_ci	/* Force memory writes to complete before letting h/w
18548c2ecf20Sopenharmony_ci	 * know there are new descriptors to fetch.  (Only
18558c2ecf20Sopenharmony_ci	 * applicable for weak-ordered memory model archs,
18568c2ecf20Sopenharmony_ci	 * such as IA-64). */
18578c2ecf20Sopenharmony_ci	wmb();
18588c2ecf20Sopenharmony_ci	AT_WRITE_REG(&adapter->hw, REG_MB_TPD_PROD_IDX, tx_ring->next_to_use);
18598c2ecf20Sopenharmony_ci}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_cistatic netdev_tx_t atl1e_xmit_frame(struct sk_buff *skb,
18628c2ecf20Sopenharmony_ci					  struct net_device *netdev)
18638c2ecf20Sopenharmony_ci{
18648c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
18658c2ecf20Sopenharmony_ci	u16 tpd_req = 1;
18668c2ecf20Sopenharmony_ci	struct atl1e_tpd_desc *tpd;
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	if (test_bit(__AT_DOWN, &adapter->flags)) {
18698c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
18708c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
18718c2ecf20Sopenharmony_ci	}
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	if (unlikely(skb->len <= 0)) {
18748c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
18758c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
18768c2ecf20Sopenharmony_ci	}
18778c2ecf20Sopenharmony_ci	tpd_req = atl1e_cal_tdp_req(skb);
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	if (atl1e_tpd_avail(adapter) < tpd_req) {
18808c2ecf20Sopenharmony_ci		/* no enough descriptor, just stop queue */
18818c2ecf20Sopenharmony_ci		netif_stop_queue(netdev);
18828c2ecf20Sopenharmony_ci		return NETDEV_TX_BUSY;
18838c2ecf20Sopenharmony_ci	}
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	tpd = atl1e_get_tpd(adapter);
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci	if (skb_vlan_tag_present(skb)) {
18888c2ecf20Sopenharmony_ci		u16 vlan_tag = skb_vlan_tag_get(skb);
18898c2ecf20Sopenharmony_ci		u16 atl1e_vlan_tag;
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci		tpd->word3 |= 1 << TPD_INS_VL_TAG_SHIFT;
18928c2ecf20Sopenharmony_ci		AT_VLAN_TAG_TO_TPD_TAG(vlan_tag, atl1e_vlan_tag);
18938c2ecf20Sopenharmony_ci		tpd->word2 |= (atl1e_vlan_tag & TPD_VLANTAG_MASK) <<
18948c2ecf20Sopenharmony_ci				TPD_VLAN_SHIFT;
18958c2ecf20Sopenharmony_ci	}
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	if (skb->protocol == htons(ETH_P_8021Q))
18988c2ecf20Sopenharmony_ci		tpd->word3 |= 1 << TPD_VL_TAGGED_SHIFT;
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	if (skb_network_offset(skb) != ETH_HLEN)
19018c2ecf20Sopenharmony_ci		tpd->word3 |= 1 << TPD_ETHTYPE_SHIFT; /* 802.3 frame */
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci	/* do TSO and check sum */
19048c2ecf20Sopenharmony_ci	if (atl1e_tso_csum(adapter, skb, tpd) != 0) {
19058c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
19068c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
19078c2ecf20Sopenharmony_ci	}
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	if (atl1e_tx_map(adapter, skb, tpd)) {
19108c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
19118c2ecf20Sopenharmony_ci		goto out;
19128c2ecf20Sopenharmony_ci	}
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	atl1e_tx_queue(adapter, tpd_req, tpd);
19158c2ecf20Sopenharmony_ciout:
19168c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
19178c2ecf20Sopenharmony_ci}
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_cistatic void atl1e_free_irq(struct atl1e_adapter *adapter)
19208c2ecf20Sopenharmony_ci{
19218c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	free_irq(adapter->pdev->irq, netdev);
19248c2ecf20Sopenharmony_ci}
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_cistatic int atl1e_request_irq(struct atl1e_adapter *adapter)
19278c2ecf20Sopenharmony_ci{
19288c2ecf20Sopenharmony_ci	struct pci_dev    *pdev   = adapter->pdev;
19298c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
19308c2ecf20Sopenharmony_ci	int err = 0;
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	err = request_irq(pdev->irq, atl1e_intr, IRQF_SHARED, netdev->name,
19338c2ecf20Sopenharmony_ci			  netdev);
19348c2ecf20Sopenharmony_ci	if (err) {
19358c2ecf20Sopenharmony_ci		netdev_dbg(adapter->netdev,
19368c2ecf20Sopenharmony_ci			   "Unable to allocate interrupt Error: %d\n", err);
19378c2ecf20Sopenharmony_ci		return err;
19388c2ecf20Sopenharmony_ci	}
19398c2ecf20Sopenharmony_ci	netdev_dbg(netdev, "atl1e_request_irq OK\n");
19408c2ecf20Sopenharmony_ci	return err;
19418c2ecf20Sopenharmony_ci}
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ciint atl1e_up(struct atl1e_adapter *adapter)
19448c2ecf20Sopenharmony_ci{
19458c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
19468c2ecf20Sopenharmony_ci	int err = 0;
19478c2ecf20Sopenharmony_ci	u32 val;
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	/* hardware has been reset, we need to reload some things */
19508c2ecf20Sopenharmony_ci	err = atl1e_init_hw(&adapter->hw);
19518c2ecf20Sopenharmony_ci	if (err) {
19528c2ecf20Sopenharmony_ci		err = -EIO;
19538c2ecf20Sopenharmony_ci		return err;
19548c2ecf20Sopenharmony_ci	}
19558c2ecf20Sopenharmony_ci	atl1e_init_ring_ptrs(adapter);
19568c2ecf20Sopenharmony_ci	atl1e_set_multi(netdev);
19578c2ecf20Sopenharmony_ci	atl1e_restore_vlan(adapter);
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci	if (atl1e_configure(adapter)) {
19608c2ecf20Sopenharmony_ci		err = -EIO;
19618c2ecf20Sopenharmony_ci		goto err_up;
19628c2ecf20Sopenharmony_ci	}
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci	clear_bit(__AT_DOWN, &adapter->flags);
19658c2ecf20Sopenharmony_ci	napi_enable(&adapter->napi);
19668c2ecf20Sopenharmony_ci	atl1e_irq_enable(adapter);
19678c2ecf20Sopenharmony_ci	val = AT_READ_REG(&adapter->hw, REG_MASTER_CTRL);
19688c2ecf20Sopenharmony_ci	AT_WRITE_REG(&adapter->hw, REG_MASTER_CTRL,
19698c2ecf20Sopenharmony_ci		      val | MASTER_CTRL_MANUAL_INT);
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_cierr_up:
19728c2ecf20Sopenharmony_ci	return err;
19738c2ecf20Sopenharmony_ci}
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_civoid atl1e_down(struct atl1e_adapter *adapter)
19768c2ecf20Sopenharmony_ci{
19778c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	/* signal that we're down so the interrupt handler does not
19808c2ecf20Sopenharmony_ci	 * reschedule our watchdog timer */
19818c2ecf20Sopenharmony_ci	set_bit(__AT_DOWN, &adapter->flags);
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci	netif_stop_queue(netdev);
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci	/* reset MAC to disable all RX/TX */
19868c2ecf20Sopenharmony_ci	atl1e_reset_hw(&adapter->hw);
19878c2ecf20Sopenharmony_ci	msleep(1);
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci	napi_disable(&adapter->napi);
19908c2ecf20Sopenharmony_ci	atl1e_del_timer(adapter);
19918c2ecf20Sopenharmony_ci	atl1e_irq_disable(adapter);
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_ci	netif_carrier_off(netdev);
19948c2ecf20Sopenharmony_ci	adapter->link_speed = SPEED_0;
19958c2ecf20Sopenharmony_ci	adapter->link_duplex = -1;
19968c2ecf20Sopenharmony_ci	atl1e_clean_tx_ring(adapter);
19978c2ecf20Sopenharmony_ci	atl1e_clean_rx_ring(adapter);
19988c2ecf20Sopenharmony_ci}
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci/**
20018c2ecf20Sopenharmony_ci * atl1e_open - Called when a network interface is made active
20028c2ecf20Sopenharmony_ci * @netdev: network interface device structure
20038c2ecf20Sopenharmony_ci *
20048c2ecf20Sopenharmony_ci * Returns 0 on success, negative value on failure
20058c2ecf20Sopenharmony_ci *
20068c2ecf20Sopenharmony_ci * The open entry point is called when a network interface is made
20078c2ecf20Sopenharmony_ci * active by the system (IFF_UP).  At this point all resources needed
20088c2ecf20Sopenharmony_ci * for transmit and receive operations are allocated, the interrupt
20098c2ecf20Sopenharmony_ci * handler is registered with the OS, the watchdog timer is started,
20108c2ecf20Sopenharmony_ci * and the stack is notified that the interface is ready.
20118c2ecf20Sopenharmony_ci */
20128c2ecf20Sopenharmony_cistatic int atl1e_open(struct net_device *netdev)
20138c2ecf20Sopenharmony_ci{
20148c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
20158c2ecf20Sopenharmony_ci	int err;
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci	/* disallow open during test */
20188c2ecf20Sopenharmony_ci	if (test_bit(__AT_TESTING, &adapter->flags))
20198c2ecf20Sopenharmony_ci		return -EBUSY;
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	/* allocate rx/tx dma buffer & descriptors */
20228c2ecf20Sopenharmony_ci	atl1e_init_ring_resources(adapter);
20238c2ecf20Sopenharmony_ci	err = atl1e_setup_ring_resources(adapter);
20248c2ecf20Sopenharmony_ci	if (unlikely(err))
20258c2ecf20Sopenharmony_ci		return err;
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci	err = atl1e_request_irq(adapter);
20288c2ecf20Sopenharmony_ci	if (unlikely(err))
20298c2ecf20Sopenharmony_ci		goto err_req_irq;
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	err = atl1e_up(adapter);
20328c2ecf20Sopenharmony_ci	if (unlikely(err))
20338c2ecf20Sopenharmony_ci		goto err_up;
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	return 0;
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_cierr_up:
20388c2ecf20Sopenharmony_ci	atl1e_free_irq(adapter);
20398c2ecf20Sopenharmony_cierr_req_irq:
20408c2ecf20Sopenharmony_ci	atl1e_free_ring_resources(adapter);
20418c2ecf20Sopenharmony_ci	atl1e_reset_hw(&adapter->hw);
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	return err;
20448c2ecf20Sopenharmony_ci}
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci/**
20478c2ecf20Sopenharmony_ci * atl1e_close - Disables a network interface
20488c2ecf20Sopenharmony_ci * @netdev: network interface device structure
20498c2ecf20Sopenharmony_ci *
20508c2ecf20Sopenharmony_ci * Returns 0, this is not allowed to fail
20518c2ecf20Sopenharmony_ci *
20528c2ecf20Sopenharmony_ci * The close entry point is called when an interface is de-activated
20538c2ecf20Sopenharmony_ci * by the OS.  The hardware is still under the drivers control, but
20548c2ecf20Sopenharmony_ci * needs to be disabled.  A global MAC reset is issued to stop the
20558c2ecf20Sopenharmony_ci * hardware, and all transmit and receive resources are freed.
20568c2ecf20Sopenharmony_ci */
20578c2ecf20Sopenharmony_cistatic int atl1e_close(struct net_device *netdev)
20588c2ecf20Sopenharmony_ci{
20598c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
20628c2ecf20Sopenharmony_ci	atl1e_down(adapter);
20638c2ecf20Sopenharmony_ci	atl1e_free_irq(adapter);
20648c2ecf20Sopenharmony_ci	atl1e_free_ring_resources(adapter);
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci	return 0;
20678c2ecf20Sopenharmony_ci}
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_cistatic int atl1e_suspend(struct pci_dev *pdev, pm_message_t state)
20708c2ecf20Sopenharmony_ci{
20718c2ecf20Sopenharmony_ci	struct net_device *netdev = pci_get_drvdata(pdev);
20728c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
20738c2ecf20Sopenharmony_ci	struct atl1e_hw *hw = &adapter->hw;
20748c2ecf20Sopenharmony_ci	u32 ctrl = 0;
20758c2ecf20Sopenharmony_ci	u32 mac_ctrl_data = 0;
20768c2ecf20Sopenharmony_ci	u32 wol_ctrl_data = 0;
20778c2ecf20Sopenharmony_ci	u16 mii_advertise_data = 0;
20788c2ecf20Sopenharmony_ci	u16 mii_bmsr_data = 0;
20798c2ecf20Sopenharmony_ci	u16 mii_intr_status_data = 0;
20808c2ecf20Sopenharmony_ci	u32 wufc = adapter->wol;
20818c2ecf20Sopenharmony_ci	u32 i;
20828c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
20838c2ecf20Sopenharmony_ci	int retval = 0;
20848c2ecf20Sopenharmony_ci#endif
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci	if (netif_running(netdev)) {
20878c2ecf20Sopenharmony_ci		WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
20888c2ecf20Sopenharmony_ci		atl1e_down(adapter);
20898c2ecf20Sopenharmony_ci	}
20908c2ecf20Sopenharmony_ci	netif_device_detach(netdev);
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
20938c2ecf20Sopenharmony_ci	retval = pci_save_state(pdev);
20948c2ecf20Sopenharmony_ci	if (retval)
20958c2ecf20Sopenharmony_ci		return retval;
20968c2ecf20Sopenharmony_ci#endif
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_ci	if (wufc) {
20998c2ecf20Sopenharmony_ci		/* get link status */
21008c2ecf20Sopenharmony_ci		atl1e_read_phy_reg(hw, MII_BMSR, &mii_bmsr_data);
21018c2ecf20Sopenharmony_ci		atl1e_read_phy_reg(hw, MII_BMSR, &mii_bmsr_data);
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_ci		mii_advertise_data = ADVERTISE_10HALF;
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci		if ((atl1e_write_phy_reg(hw, MII_CTRL1000, 0) != 0) ||
21068c2ecf20Sopenharmony_ci		    (atl1e_write_phy_reg(hw,
21078c2ecf20Sopenharmony_ci			   MII_ADVERTISE, mii_advertise_data) != 0) ||
21088c2ecf20Sopenharmony_ci		    (atl1e_phy_commit(hw)) != 0) {
21098c2ecf20Sopenharmony_ci			netdev_dbg(adapter->netdev, "set phy register failed\n");
21108c2ecf20Sopenharmony_ci			goto wol_dis;
21118c2ecf20Sopenharmony_ci		}
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci		hw->phy_configured = false; /* re-init PHY when resume */
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci		/* turn on magic packet wol */
21168c2ecf20Sopenharmony_ci		if (wufc & AT_WUFC_MAG)
21178c2ecf20Sopenharmony_ci			wol_ctrl_data |= WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci		if (wufc & AT_WUFC_LNKC) {
21208c2ecf20Sopenharmony_ci		/* if orignal link status is link, just wait for retrive link */
21218c2ecf20Sopenharmony_ci			if (mii_bmsr_data & BMSR_LSTATUS) {
21228c2ecf20Sopenharmony_ci				for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
21238c2ecf20Sopenharmony_ci					msleep(100);
21248c2ecf20Sopenharmony_ci					atl1e_read_phy_reg(hw, MII_BMSR,
21258c2ecf20Sopenharmony_ci							&mii_bmsr_data);
21268c2ecf20Sopenharmony_ci					if (mii_bmsr_data & BMSR_LSTATUS)
21278c2ecf20Sopenharmony_ci						break;
21288c2ecf20Sopenharmony_ci				}
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci				if ((mii_bmsr_data & BMSR_LSTATUS) == 0)
21318c2ecf20Sopenharmony_ci					netdev_dbg(adapter->netdev,
21328c2ecf20Sopenharmony_ci						   "Link may change when suspend\n");
21338c2ecf20Sopenharmony_ci			}
21348c2ecf20Sopenharmony_ci			wol_ctrl_data |=  WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN;
21358c2ecf20Sopenharmony_ci			/* only link up can wake up */
21368c2ecf20Sopenharmony_ci			if (atl1e_write_phy_reg(hw, MII_INT_CTRL, 0x400) != 0) {
21378c2ecf20Sopenharmony_ci				netdev_dbg(adapter->netdev,
21388c2ecf20Sopenharmony_ci					   "read write phy register failed\n");
21398c2ecf20Sopenharmony_ci				goto wol_dis;
21408c2ecf20Sopenharmony_ci			}
21418c2ecf20Sopenharmony_ci		}
21428c2ecf20Sopenharmony_ci		/* clear phy interrupt */
21438c2ecf20Sopenharmony_ci		atl1e_read_phy_reg(hw, MII_INT_STATUS, &mii_intr_status_data);
21448c2ecf20Sopenharmony_ci		/* Config MAC Ctrl register */
21458c2ecf20Sopenharmony_ci		mac_ctrl_data = MAC_CTRL_RX_EN;
21468c2ecf20Sopenharmony_ci		/* set to 10/100M halt duplex */
21478c2ecf20Sopenharmony_ci		mac_ctrl_data |= MAC_CTRL_SPEED_10_100 << MAC_CTRL_SPEED_SHIFT;
21488c2ecf20Sopenharmony_ci		mac_ctrl_data |= (((u32)adapter->hw.preamble_len &
21498c2ecf20Sopenharmony_ci				 MAC_CTRL_PRMLEN_MASK) <<
21508c2ecf20Sopenharmony_ci				 MAC_CTRL_PRMLEN_SHIFT);
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci		__atl1e_vlan_mode(netdev->features, &mac_ctrl_data);
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci		/* magic packet maybe Broadcast&multicast&Unicast frame */
21558c2ecf20Sopenharmony_ci		if (wufc & AT_WUFC_MAG)
21568c2ecf20Sopenharmony_ci			mac_ctrl_data |= MAC_CTRL_BC_EN;
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci		netdev_dbg(adapter->netdev, "suspend MAC=0x%x\n",
21598c2ecf20Sopenharmony_ci			   mac_ctrl_data);
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci		AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data);
21628c2ecf20Sopenharmony_ci		AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
21638c2ecf20Sopenharmony_ci		/* pcie patch */
21648c2ecf20Sopenharmony_ci		ctrl = AT_READ_REG(hw, REG_PCIE_PHYMISC);
21658c2ecf20Sopenharmony_ci		ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
21668c2ecf20Sopenharmony_ci		AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
21678c2ecf20Sopenharmony_ci		pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
21688c2ecf20Sopenharmony_ci		goto suspend_exit;
21698c2ecf20Sopenharmony_ci	}
21708c2ecf20Sopenharmony_ciwol_dis:
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci	/* WOL disabled */
21738c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci	/* pcie patch */
21768c2ecf20Sopenharmony_ci	ctrl = AT_READ_REG(hw, REG_PCIE_PHYMISC);
21778c2ecf20Sopenharmony_ci	ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
21788c2ecf20Sopenharmony_ci	AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci	atl1e_force_ps(hw);
21818c2ecf20Sopenharmony_ci	hw->phy_configured = false; /* re-init PHY when resume */
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_cisuspend_exit:
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci	if (netif_running(netdev))
21888c2ecf20Sopenharmony_ci		atl1e_free_irq(adapter);
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci	pci_set_power_state(pdev, pci_choose_state(pdev, state));
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	return 0;
21958c2ecf20Sopenharmony_ci}
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
21988c2ecf20Sopenharmony_cistatic int atl1e_resume(struct pci_dev *pdev)
21998c2ecf20Sopenharmony_ci{
22008c2ecf20Sopenharmony_ci	struct net_device *netdev = pci_get_drvdata(pdev);
22018c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
22028c2ecf20Sopenharmony_ci	u32 err;
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci	pci_set_power_state(pdev, PCI_D0);
22058c2ecf20Sopenharmony_ci	pci_restore_state(pdev);
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	err = pci_enable_device(pdev);
22088c2ecf20Sopenharmony_ci	if (err) {
22098c2ecf20Sopenharmony_ci		netdev_err(adapter->netdev,
22108c2ecf20Sopenharmony_ci			   "Cannot enable PCI device from suspend\n");
22118c2ecf20Sopenharmony_ci		return err;
22128c2ecf20Sopenharmony_ci	}
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_ci	pci_set_master(pdev);
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	AT_READ_REG(&adapter->hw, REG_WOL_CTRL); /* clear WOL status */
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci	pci_enable_wake(pdev, PCI_D3hot, 0);
22198c2ecf20Sopenharmony_ci	pci_enable_wake(pdev, PCI_D3cold, 0);
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_ci	AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0);
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	if (netif_running(netdev)) {
22248c2ecf20Sopenharmony_ci		err = atl1e_request_irq(adapter);
22258c2ecf20Sopenharmony_ci		if (err)
22268c2ecf20Sopenharmony_ci			return err;
22278c2ecf20Sopenharmony_ci	}
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci	atl1e_reset_hw(&adapter->hw);
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci	if (netif_running(netdev))
22328c2ecf20Sopenharmony_ci		atl1e_up(adapter);
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	netif_device_attach(netdev);
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci	return 0;
22378c2ecf20Sopenharmony_ci}
22388c2ecf20Sopenharmony_ci#endif
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_cistatic void atl1e_shutdown(struct pci_dev *pdev)
22418c2ecf20Sopenharmony_ci{
22428c2ecf20Sopenharmony_ci	atl1e_suspend(pdev, PMSG_SUSPEND);
22438c2ecf20Sopenharmony_ci}
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_cistatic const struct net_device_ops atl1e_netdev_ops = {
22468c2ecf20Sopenharmony_ci	.ndo_open		= atl1e_open,
22478c2ecf20Sopenharmony_ci	.ndo_stop		= atl1e_close,
22488c2ecf20Sopenharmony_ci	.ndo_start_xmit		= atl1e_xmit_frame,
22498c2ecf20Sopenharmony_ci	.ndo_get_stats		= atl1e_get_stats,
22508c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	= atl1e_set_multi,
22518c2ecf20Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
22528c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= atl1e_set_mac_addr,
22538c2ecf20Sopenharmony_ci	.ndo_fix_features	= atl1e_fix_features,
22548c2ecf20Sopenharmony_ci	.ndo_set_features	= atl1e_set_features,
22558c2ecf20Sopenharmony_ci	.ndo_change_mtu		= atl1e_change_mtu,
22568c2ecf20Sopenharmony_ci	.ndo_do_ioctl		= atl1e_ioctl,
22578c2ecf20Sopenharmony_ci	.ndo_tx_timeout		= atl1e_tx_timeout,
22588c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
22598c2ecf20Sopenharmony_ci	.ndo_poll_controller	= atl1e_netpoll,
22608c2ecf20Sopenharmony_ci#endif
22618c2ecf20Sopenharmony_ci
22628c2ecf20Sopenharmony_ci};
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_cistatic int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev)
22658c2ecf20Sopenharmony_ci{
22668c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(netdev, &pdev->dev);
22678c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, netdev);
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci	netdev->netdev_ops = &atl1e_netdev_ops;
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci	netdev->watchdog_timeo = AT_TX_WATCHDOG;
22728c2ecf20Sopenharmony_ci	/* MTU range: 42 - 8170 */
22738c2ecf20Sopenharmony_ci	netdev->min_mtu = ETH_ZLEN - (ETH_HLEN + VLAN_HLEN);
22748c2ecf20Sopenharmony_ci	netdev->max_mtu = MAX_JUMBO_FRAME_SIZE -
22758c2ecf20Sopenharmony_ci			  (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
22768c2ecf20Sopenharmony_ci	atl1e_set_ethtool_ops(netdev);
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_ci	netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO |
22798c2ecf20Sopenharmony_ci			      NETIF_F_HW_VLAN_CTAG_RX;
22808c2ecf20Sopenharmony_ci	netdev->features = netdev->hw_features | NETIF_F_HW_VLAN_CTAG_TX;
22818c2ecf20Sopenharmony_ci	/* not enabled by default */
22828c2ecf20Sopenharmony_ci	netdev->hw_features |= NETIF_F_RXALL | NETIF_F_RXFCS;
22838c2ecf20Sopenharmony_ci	return 0;
22848c2ecf20Sopenharmony_ci}
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci/**
22878c2ecf20Sopenharmony_ci * atl1e_probe - Device Initialization Routine
22888c2ecf20Sopenharmony_ci * @pdev: PCI device information struct
22898c2ecf20Sopenharmony_ci * @ent: entry in atl1e_pci_tbl
22908c2ecf20Sopenharmony_ci *
22918c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure
22928c2ecf20Sopenharmony_ci *
22938c2ecf20Sopenharmony_ci * atl1e_probe initializes an adapter identified by a pci_dev structure.
22948c2ecf20Sopenharmony_ci * The OS initialization, configuring of the adapter private structure,
22958c2ecf20Sopenharmony_ci * and a hardware reset occur.
22968c2ecf20Sopenharmony_ci */
22978c2ecf20Sopenharmony_cistatic int atl1e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
22988c2ecf20Sopenharmony_ci{
22998c2ecf20Sopenharmony_ci	struct net_device *netdev;
23008c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = NULL;
23018c2ecf20Sopenharmony_ci	static int cards_found;
23028c2ecf20Sopenharmony_ci
23038c2ecf20Sopenharmony_ci	int err = 0;
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_ci	err = pci_enable_device(pdev);
23068c2ecf20Sopenharmony_ci	if (err) {
23078c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "cannot enable PCI device\n");
23088c2ecf20Sopenharmony_ci		return err;
23098c2ecf20Sopenharmony_ci	}
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci	/*
23128c2ecf20Sopenharmony_ci	 * The atl1e chip can DMA to 64-bit addresses, but it uses a single
23138c2ecf20Sopenharmony_ci	 * shared register for the high 32 bits, so only a single, aligned,
23148c2ecf20Sopenharmony_ci	 * 4 GB physical address range can be used at a time.
23158c2ecf20Sopenharmony_ci	 *
23168c2ecf20Sopenharmony_ci	 * Supporting 64-bit DMA on this hardware is more trouble than it's
23178c2ecf20Sopenharmony_ci	 * worth.  It is far easier to limit to 32-bit DMA than update
23188c2ecf20Sopenharmony_ci	 * various kernel subsystems to support the mechanics required by a
23198c2ecf20Sopenharmony_ci	 * fixed-high-32-bit system.
23208c2ecf20Sopenharmony_ci	 */
23218c2ecf20Sopenharmony_ci	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
23228c2ecf20Sopenharmony_ci	if (err) {
23238c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "No usable DMA configuration,aborting\n");
23248c2ecf20Sopenharmony_ci		goto err_dma;
23258c2ecf20Sopenharmony_ci	}
23268c2ecf20Sopenharmony_ci
23278c2ecf20Sopenharmony_ci	err = pci_request_regions(pdev, atl1e_driver_name);
23288c2ecf20Sopenharmony_ci	if (err) {
23298c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "cannot obtain PCI resources\n");
23308c2ecf20Sopenharmony_ci		goto err_pci_reg;
23318c2ecf20Sopenharmony_ci	}
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	pci_set_master(pdev);
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci	netdev = alloc_etherdev(sizeof(struct atl1e_adapter));
23368c2ecf20Sopenharmony_ci	if (netdev == NULL) {
23378c2ecf20Sopenharmony_ci		err = -ENOMEM;
23388c2ecf20Sopenharmony_ci		goto err_alloc_etherdev;
23398c2ecf20Sopenharmony_ci	}
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci	err = atl1e_init_netdev(netdev, pdev);
23428c2ecf20Sopenharmony_ci	if (err) {
23438c2ecf20Sopenharmony_ci		netdev_err(netdev, "init netdevice failed\n");
23448c2ecf20Sopenharmony_ci		goto err_init_netdev;
23458c2ecf20Sopenharmony_ci	}
23468c2ecf20Sopenharmony_ci	adapter = netdev_priv(netdev);
23478c2ecf20Sopenharmony_ci	adapter->bd_number = cards_found;
23488c2ecf20Sopenharmony_ci	adapter->netdev = netdev;
23498c2ecf20Sopenharmony_ci	adapter->pdev = pdev;
23508c2ecf20Sopenharmony_ci	adapter->hw.adapter = adapter;
23518c2ecf20Sopenharmony_ci	adapter->hw.hw_addr = pci_iomap(pdev, BAR_0, 0);
23528c2ecf20Sopenharmony_ci	if (!adapter->hw.hw_addr) {
23538c2ecf20Sopenharmony_ci		err = -EIO;
23548c2ecf20Sopenharmony_ci		netdev_err(netdev, "cannot map device registers\n");
23558c2ecf20Sopenharmony_ci		goto err_ioremap;
23568c2ecf20Sopenharmony_ci	}
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	/* init mii data */
23598c2ecf20Sopenharmony_ci	adapter->mii.dev = netdev;
23608c2ecf20Sopenharmony_ci	adapter->mii.mdio_read  = atl1e_mdio_read;
23618c2ecf20Sopenharmony_ci	adapter->mii.mdio_write = atl1e_mdio_write;
23628c2ecf20Sopenharmony_ci	adapter->mii.phy_id_mask = 0x1f;
23638c2ecf20Sopenharmony_ci	adapter->mii.reg_num_mask = MDIO_REG_ADDR_MASK;
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci	netif_napi_add(netdev, &adapter->napi, atl1e_clean, 64);
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci	timer_setup(&adapter->phy_config_timer, atl1e_phy_config, 0);
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci	/* get user settings */
23708c2ecf20Sopenharmony_ci	atl1e_check_options(adapter);
23718c2ecf20Sopenharmony_ci	/*
23728c2ecf20Sopenharmony_ci	 * Mark all PCI regions associated with PCI device
23738c2ecf20Sopenharmony_ci	 * pdev as being reserved by owner atl1e_driver_name
23748c2ecf20Sopenharmony_ci	 * Enables bus-mastering on the device and calls
23758c2ecf20Sopenharmony_ci	 * pcibios_set_master to do the needed arch specific settings
23768c2ecf20Sopenharmony_ci	 */
23778c2ecf20Sopenharmony_ci	atl1e_setup_pcicmd(pdev);
23788c2ecf20Sopenharmony_ci	/* setup the private structure */
23798c2ecf20Sopenharmony_ci	err = atl1e_sw_init(adapter);
23808c2ecf20Sopenharmony_ci	if (err) {
23818c2ecf20Sopenharmony_ci		netdev_err(netdev, "net device private data init failed\n");
23828c2ecf20Sopenharmony_ci		goto err_sw_init;
23838c2ecf20Sopenharmony_ci	}
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci	/* Init GPHY as early as possible due to power saving issue  */
23868c2ecf20Sopenharmony_ci	atl1e_phy_init(&adapter->hw);
23878c2ecf20Sopenharmony_ci	/* reset the controller to
23888c2ecf20Sopenharmony_ci	 * put the device in a known good starting state */
23898c2ecf20Sopenharmony_ci	err = atl1e_reset_hw(&adapter->hw);
23908c2ecf20Sopenharmony_ci	if (err) {
23918c2ecf20Sopenharmony_ci		err = -EIO;
23928c2ecf20Sopenharmony_ci		goto err_reset;
23938c2ecf20Sopenharmony_ci	}
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci	if (atl1e_read_mac_addr(&adapter->hw) != 0) {
23968c2ecf20Sopenharmony_ci		err = -EIO;
23978c2ecf20Sopenharmony_ci		netdev_err(netdev, "get mac address failed\n");
23988c2ecf20Sopenharmony_ci		goto err_eeprom;
23998c2ecf20Sopenharmony_ci	}
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_ci	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
24028c2ecf20Sopenharmony_ci	netdev_dbg(netdev, "mac address : %pM\n", adapter->hw.mac_addr);
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci	INIT_WORK(&adapter->reset_task, atl1e_reset_task);
24058c2ecf20Sopenharmony_ci	INIT_WORK(&adapter->link_chg_task, atl1e_link_chg_task);
24068c2ecf20Sopenharmony_ci	netif_set_gso_max_size(netdev, MAX_TSO_SEG_SIZE);
24078c2ecf20Sopenharmony_ci	err = register_netdev(netdev);
24088c2ecf20Sopenharmony_ci	if (err) {
24098c2ecf20Sopenharmony_ci		netdev_err(netdev, "register netdevice failed\n");
24108c2ecf20Sopenharmony_ci		goto err_register;
24118c2ecf20Sopenharmony_ci	}
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci	/* assume we have no link for now */
24148c2ecf20Sopenharmony_ci	netif_stop_queue(netdev);
24158c2ecf20Sopenharmony_ci	netif_carrier_off(netdev);
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci	cards_found++;
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_ci	return 0;
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_cierr_reset:
24228c2ecf20Sopenharmony_cierr_register:
24238c2ecf20Sopenharmony_cierr_sw_init:
24248c2ecf20Sopenharmony_cierr_eeprom:
24258c2ecf20Sopenharmony_ci	pci_iounmap(pdev, adapter->hw.hw_addr);
24268c2ecf20Sopenharmony_cierr_init_netdev:
24278c2ecf20Sopenharmony_cierr_ioremap:
24288c2ecf20Sopenharmony_ci	free_netdev(netdev);
24298c2ecf20Sopenharmony_cierr_alloc_etherdev:
24308c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
24318c2ecf20Sopenharmony_cierr_pci_reg:
24328c2ecf20Sopenharmony_cierr_dma:
24338c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
24348c2ecf20Sopenharmony_ci	return err;
24358c2ecf20Sopenharmony_ci}
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci/**
24388c2ecf20Sopenharmony_ci * atl1e_remove - Device Removal Routine
24398c2ecf20Sopenharmony_ci * @pdev: PCI device information struct
24408c2ecf20Sopenharmony_ci *
24418c2ecf20Sopenharmony_ci * atl1e_remove is called by the PCI subsystem to alert the driver
24428c2ecf20Sopenharmony_ci * that it should release a PCI device.  The could be caused by a
24438c2ecf20Sopenharmony_ci * Hot-Plug event, or because the driver is going to be removed from
24448c2ecf20Sopenharmony_ci * memory.
24458c2ecf20Sopenharmony_ci */
24468c2ecf20Sopenharmony_cistatic void atl1e_remove(struct pci_dev *pdev)
24478c2ecf20Sopenharmony_ci{
24488c2ecf20Sopenharmony_ci	struct net_device *netdev = pci_get_drvdata(pdev);
24498c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_ci	/*
24528c2ecf20Sopenharmony_ci	 * flush_scheduled work may reschedule our watchdog task, so
24538c2ecf20Sopenharmony_ci	 * explicitly disable watchdog tasks from being rescheduled
24548c2ecf20Sopenharmony_ci	 */
24558c2ecf20Sopenharmony_ci	set_bit(__AT_DOWN, &adapter->flags);
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_ci	atl1e_del_timer(adapter);
24588c2ecf20Sopenharmony_ci	atl1e_cancel_work(adapter);
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci	unregister_netdev(netdev);
24618c2ecf20Sopenharmony_ci	atl1e_free_ring_resources(adapter);
24628c2ecf20Sopenharmony_ci	atl1e_force_ps(&adapter->hw);
24638c2ecf20Sopenharmony_ci	pci_iounmap(pdev, adapter->hw.hw_addr);
24648c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
24658c2ecf20Sopenharmony_ci	free_netdev(netdev);
24668c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
24678c2ecf20Sopenharmony_ci}
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci/**
24708c2ecf20Sopenharmony_ci * atl1e_io_error_detected - called when PCI error is detected
24718c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device
24728c2ecf20Sopenharmony_ci * @state: The current pci connection state
24738c2ecf20Sopenharmony_ci *
24748c2ecf20Sopenharmony_ci * This function is called after a PCI bus error affecting
24758c2ecf20Sopenharmony_ci * this device has been detected.
24768c2ecf20Sopenharmony_ci */
24778c2ecf20Sopenharmony_cistatic pci_ers_result_t
24788c2ecf20Sopenharmony_ciatl1e_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
24798c2ecf20Sopenharmony_ci{
24808c2ecf20Sopenharmony_ci	struct net_device *netdev = pci_get_drvdata(pdev);
24818c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci	netif_device_detach(netdev);
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci	if (state == pci_channel_io_perm_failure)
24868c2ecf20Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci	if (netif_running(netdev))
24898c2ecf20Sopenharmony_ci		atl1e_down(adapter);
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
24928c2ecf20Sopenharmony_ci
24938c2ecf20Sopenharmony_ci	/* Request a slot slot reset. */
24948c2ecf20Sopenharmony_ci	return PCI_ERS_RESULT_NEED_RESET;
24958c2ecf20Sopenharmony_ci}
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci/**
24988c2ecf20Sopenharmony_ci * atl1e_io_slot_reset - called after the pci bus has been reset.
24998c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device
25008c2ecf20Sopenharmony_ci *
25018c2ecf20Sopenharmony_ci * Restart the card from scratch, as if from a cold-boot. Implementation
25028c2ecf20Sopenharmony_ci * resembles the first-half of the e1000_resume routine.
25038c2ecf20Sopenharmony_ci */
25048c2ecf20Sopenharmony_cistatic pci_ers_result_t atl1e_io_slot_reset(struct pci_dev *pdev)
25058c2ecf20Sopenharmony_ci{
25068c2ecf20Sopenharmony_ci	struct net_device *netdev = pci_get_drvdata(pdev);
25078c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci	if (pci_enable_device(pdev)) {
25108c2ecf20Sopenharmony_ci		netdev_err(adapter->netdev,
25118c2ecf20Sopenharmony_ci			   "Cannot re-enable PCI device after reset\n");
25128c2ecf20Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
25138c2ecf20Sopenharmony_ci	}
25148c2ecf20Sopenharmony_ci	pci_set_master(pdev);
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_ci	pci_enable_wake(pdev, PCI_D3hot, 0);
25178c2ecf20Sopenharmony_ci	pci_enable_wake(pdev, PCI_D3cold, 0);
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci	atl1e_reset_hw(&adapter->hw);
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci	return PCI_ERS_RESULT_RECOVERED;
25228c2ecf20Sopenharmony_ci}
25238c2ecf20Sopenharmony_ci
25248c2ecf20Sopenharmony_ci/**
25258c2ecf20Sopenharmony_ci * atl1e_io_resume - called when traffic can start flowing again.
25268c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device
25278c2ecf20Sopenharmony_ci *
25288c2ecf20Sopenharmony_ci * This callback is called when the error recovery driver tells us that
25298c2ecf20Sopenharmony_ci * its OK to resume normal operation. Implementation resembles the
25308c2ecf20Sopenharmony_ci * second-half of the atl1e_resume routine.
25318c2ecf20Sopenharmony_ci */
25328c2ecf20Sopenharmony_cistatic void atl1e_io_resume(struct pci_dev *pdev)
25338c2ecf20Sopenharmony_ci{
25348c2ecf20Sopenharmony_ci	struct net_device *netdev = pci_get_drvdata(pdev);
25358c2ecf20Sopenharmony_ci	struct atl1e_adapter *adapter = netdev_priv(netdev);
25368c2ecf20Sopenharmony_ci
25378c2ecf20Sopenharmony_ci	if (netif_running(netdev)) {
25388c2ecf20Sopenharmony_ci		if (atl1e_up(adapter)) {
25398c2ecf20Sopenharmony_ci			netdev_err(adapter->netdev,
25408c2ecf20Sopenharmony_ci				   "can't bring device back up after reset\n");
25418c2ecf20Sopenharmony_ci			return;
25428c2ecf20Sopenharmony_ci		}
25438c2ecf20Sopenharmony_ci	}
25448c2ecf20Sopenharmony_ci
25458c2ecf20Sopenharmony_ci	netif_device_attach(netdev);
25468c2ecf20Sopenharmony_ci}
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_cistatic const struct pci_error_handlers atl1e_err_handler = {
25498c2ecf20Sopenharmony_ci	.error_detected = atl1e_io_error_detected,
25508c2ecf20Sopenharmony_ci	.slot_reset = atl1e_io_slot_reset,
25518c2ecf20Sopenharmony_ci	.resume = atl1e_io_resume,
25528c2ecf20Sopenharmony_ci};
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_cistatic struct pci_driver atl1e_driver = {
25558c2ecf20Sopenharmony_ci	.name     = atl1e_driver_name,
25568c2ecf20Sopenharmony_ci	.id_table = atl1e_pci_tbl,
25578c2ecf20Sopenharmony_ci	.probe    = atl1e_probe,
25588c2ecf20Sopenharmony_ci	.remove   = atl1e_remove,
25598c2ecf20Sopenharmony_ci	/* Power Management Hooks */
25608c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
25618c2ecf20Sopenharmony_ci	.suspend  = atl1e_suspend,
25628c2ecf20Sopenharmony_ci	.resume   = atl1e_resume,
25638c2ecf20Sopenharmony_ci#endif
25648c2ecf20Sopenharmony_ci	.shutdown = atl1e_shutdown,
25658c2ecf20Sopenharmony_ci	.err_handler = &atl1e_err_handler
25668c2ecf20Sopenharmony_ci};
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_cimodule_pci_driver(atl1e_driver);
2569