162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright(c) 2007 Atheros Corporation. All rights reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Derived from Intel e1000 driver 662306a36Sopenharmony_ci * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "atl1e.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cichar atl1e_driver_name[] = "ATL1E"; 1262306a36Sopenharmony_ci#define PCI_DEVICE_ID_ATTANSIC_L1E 0x1026 1362306a36Sopenharmony_ci/* 1462306a36Sopenharmony_ci * atl1e_pci_tbl - PCI Device ID Table 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Wildcard entries (PCI_ANY_ID) should come last 1762306a36Sopenharmony_ci * Last entry must be all 0s 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, 2062306a36Sopenharmony_ci * Class, Class Mask, private data (not used) } 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_cistatic const struct pci_device_id atl1e_pci_tbl[] = { 2362306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1E)}, 2462306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1066)}, 2562306a36Sopenharmony_ci /* required last entry */ 2662306a36Sopenharmony_ci { 0 } 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, atl1e_pci_tbl); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ciMODULE_AUTHOR("Atheros Corporation, <xiong.huang@atheros.com>, Jie Yang <jie.yang@atheros.com>"); 3162306a36Sopenharmony_ciMODULE_DESCRIPTION("Atheros 1000M Ethernet Network Driver"); 3262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic const u16 3762306a36Sopenharmony_ciatl1e_rx_page_vld_regs[AT_MAX_RECEIVE_QUEUE][AT_PAGE_NUM_PER_QUEUE] = 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci {REG_HOST_RXF0_PAGE0_VLD, REG_HOST_RXF0_PAGE1_VLD}, 4062306a36Sopenharmony_ci {REG_HOST_RXF1_PAGE0_VLD, REG_HOST_RXF1_PAGE1_VLD}, 4162306a36Sopenharmony_ci {REG_HOST_RXF2_PAGE0_VLD, REG_HOST_RXF2_PAGE1_VLD}, 4262306a36Sopenharmony_ci {REG_HOST_RXF3_PAGE0_VLD, REG_HOST_RXF3_PAGE1_VLD} 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic const u16 atl1e_rx_page_hi_addr_regs[AT_MAX_RECEIVE_QUEUE] = 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci REG_RXF0_BASE_ADDR_HI, 4862306a36Sopenharmony_ci REG_RXF1_BASE_ADDR_HI, 4962306a36Sopenharmony_ci REG_RXF2_BASE_ADDR_HI, 5062306a36Sopenharmony_ci REG_RXF3_BASE_ADDR_HI 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic const u16 5462306a36Sopenharmony_ciatl1e_rx_page_lo_addr_regs[AT_MAX_RECEIVE_QUEUE][AT_PAGE_NUM_PER_QUEUE] = 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci {REG_HOST_RXF0_PAGE0_LO, REG_HOST_RXF0_PAGE1_LO}, 5762306a36Sopenharmony_ci {REG_HOST_RXF1_PAGE0_LO, REG_HOST_RXF1_PAGE1_LO}, 5862306a36Sopenharmony_ci {REG_HOST_RXF2_PAGE0_LO, REG_HOST_RXF2_PAGE1_LO}, 5962306a36Sopenharmony_ci {REG_HOST_RXF3_PAGE0_LO, REG_HOST_RXF3_PAGE1_LO} 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic const u16 6362306a36Sopenharmony_ciatl1e_rx_page_write_offset_regs[AT_MAX_RECEIVE_QUEUE][AT_PAGE_NUM_PER_QUEUE] = 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci {REG_HOST_RXF0_MB0_LO, REG_HOST_RXF0_MB1_LO}, 6662306a36Sopenharmony_ci {REG_HOST_RXF1_MB0_LO, REG_HOST_RXF1_MB1_LO}, 6762306a36Sopenharmony_ci {REG_HOST_RXF2_MB0_LO, REG_HOST_RXF2_MB1_LO}, 6862306a36Sopenharmony_ci {REG_HOST_RXF3_MB0_LO, REG_HOST_RXF3_MB1_LO} 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic const u16 atl1e_pay_load_size[] = { 7262306a36Sopenharmony_ci 128, 256, 512, 1024, 2048, 4096, 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/** 7662306a36Sopenharmony_ci * atl1e_irq_enable - Enable default interrupt generation settings 7762306a36Sopenharmony_ci * @adapter: board private structure 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_cistatic inline void atl1e_irq_enable(struct atl1e_adapter *adapter) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci if (likely(atomic_dec_and_test(&adapter->irq_sem))) { 8262306a36Sopenharmony_ci AT_WRITE_REG(&adapter->hw, REG_ISR, 0); 8362306a36Sopenharmony_ci AT_WRITE_REG(&adapter->hw, REG_IMR, IMR_NORMAL_MASK); 8462306a36Sopenharmony_ci AT_WRITE_FLUSH(&adapter->hw); 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/** 8962306a36Sopenharmony_ci * atl1e_irq_disable - Mask off interrupt generation on the NIC 9062306a36Sopenharmony_ci * @adapter: board private structure 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_cistatic inline void atl1e_irq_disable(struct atl1e_adapter *adapter) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci atomic_inc(&adapter->irq_sem); 9562306a36Sopenharmony_ci AT_WRITE_REG(&adapter->hw, REG_IMR, 0); 9662306a36Sopenharmony_ci AT_WRITE_FLUSH(&adapter->hw); 9762306a36Sopenharmony_ci synchronize_irq(adapter->pdev->irq); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/** 10162306a36Sopenharmony_ci * atl1e_irq_reset - reset interrupt confiure on the NIC 10262306a36Sopenharmony_ci * @adapter: board private structure 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_cistatic inline void atl1e_irq_reset(struct atl1e_adapter *adapter) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci atomic_set(&adapter->irq_sem, 0); 10762306a36Sopenharmony_ci AT_WRITE_REG(&adapter->hw, REG_ISR, 0); 10862306a36Sopenharmony_ci AT_WRITE_REG(&adapter->hw, REG_IMR, 0); 10962306a36Sopenharmony_ci AT_WRITE_FLUSH(&adapter->hw); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/** 11362306a36Sopenharmony_ci * atl1e_phy_config - Timer Call-back 11462306a36Sopenharmony_ci * @t: timer list containing pointer to netdev cast into an unsigned long 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_cistatic void atl1e_phy_config(struct timer_list *t) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct atl1e_adapter *adapter = from_timer(adapter, t, 11962306a36Sopenharmony_ci phy_config_timer); 12062306a36Sopenharmony_ci struct atl1e_hw *hw = &adapter->hw; 12162306a36Sopenharmony_ci unsigned long flags; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci spin_lock_irqsave(&adapter->mdio_lock, flags); 12462306a36Sopenharmony_ci atl1e_restart_autoneg(hw); 12562306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->mdio_lock, flags); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_civoid atl1e_reinit_locked(struct atl1e_adapter *adapter) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci while (test_and_set_bit(__AT_RESETTING, &adapter->flags)) 13162306a36Sopenharmony_ci msleep(1); 13262306a36Sopenharmony_ci atl1e_down(adapter); 13362306a36Sopenharmony_ci atl1e_up(adapter); 13462306a36Sopenharmony_ci clear_bit(__AT_RESETTING, &adapter->flags); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic void atl1e_reset_task(struct work_struct *work) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct atl1e_adapter *adapter; 14062306a36Sopenharmony_ci adapter = container_of(work, struct atl1e_adapter, reset_task); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci atl1e_reinit_locked(adapter); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int atl1e_check_link(struct atl1e_adapter *adapter) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct atl1e_hw *hw = &adapter->hw; 14862306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 14962306a36Sopenharmony_ci int err = 0; 15062306a36Sopenharmony_ci u16 speed, duplex, phy_data; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* MII_BMSR must read twice */ 15362306a36Sopenharmony_ci atl1e_read_phy_reg(hw, MII_BMSR, &phy_data); 15462306a36Sopenharmony_ci atl1e_read_phy_reg(hw, MII_BMSR, &phy_data); 15562306a36Sopenharmony_ci if ((phy_data & BMSR_LSTATUS) == 0) { 15662306a36Sopenharmony_ci /* link down */ 15762306a36Sopenharmony_ci if (netif_carrier_ok(netdev)) { /* old link state: Up */ 15862306a36Sopenharmony_ci u32 value; 15962306a36Sopenharmony_ci /* disable rx */ 16062306a36Sopenharmony_ci value = AT_READ_REG(hw, REG_MAC_CTRL); 16162306a36Sopenharmony_ci value &= ~MAC_CTRL_RX_EN; 16262306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_MAC_CTRL, value); 16362306a36Sopenharmony_ci adapter->link_speed = SPEED_0; 16462306a36Sopenharmony_ci netif_carrier_off(netdev); 16562306a36Sopenharmony_ci netif_stop_queue(netdev); 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci } else { 16862306a36Sopenharmony_ci /* Link Up */ 16962306a36Sopenharmony_ci err = atl1e_get_speed_and_duplex(hw, &speed, &duplex); 17062306a36Sopenharmony_ci if (unlikely(err)) 17162306a36Sopenharmony_ci return err; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* link result is our setting */ 17462306a36Sopenharmony_ci if (adapter->link_speed != speed || 17562306a36Sopenharmony_ci adapter->link_duplex != duplex) { 17662306a36Sopenharmony_ci adapter->link_speed = speed; 17762306a36Sopenharmony_ci adapter->link_duplex = duplex; 17862306a36Sopenharmony_ci atl1e_setup_mac_ctrl(adapter); 17962306a36Sopenharmony_ci netdev_info(netdev, 18062306a36Sopenharmony_ci "NIC Link is Up <%d Mbps %s Duplex>\n", 18162306a36Sopenharmony_ci adapter->link_speed, 18262306a36Sopenharmony_ci adapter->link_duplex == FULL_DUPLEX ? 18362306a36Sopenharmony_ci "Full" : "Half"); 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (!netif_carrier_ok(netdev)) { 18762306a36Sopenharmony_ci /* Link down -> Up */ 18862306a36Sopenharmony_ci netif_carrier_on(netdev); 18962306a36Sopenharmony_ci netif_wake_queue(netdev); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci/** 19662306a36Sopenharmony_ci * atl1e_link_chg_task - deal with link change event Out of interrupt context 19762306a36Sopenharmony_ci * @work: work struct with driver info 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_cistatic void atl1e_link_chg_task(struct work_struct *work) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct atl1e_adapter *adapter; 20262306a36Sopenharmony_ci unsigned long flags; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci adapter = container_of(work, struct atl1e_adapter, link_chg_task); 20562306a36Sopenharmony_ci spin_lock_irqsave(&adapter->mdio_lock, flags); 20662306a36Sopenharmony_ci atl1e_check_link(adapter); 20762306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->mdio_lock, flags); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic void atl1e_link_chg_event(struct atl1e_adapter *adapter) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 21362306a36Sopenharmony_ci u16 phy_data = 0; 21462306a36Sopenharmony_ci u16 link_up = 0; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci spin_lock(&adapter->mdio_lock); 21762306a36Sopenharmony_ci atl1e_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); 21862306a36Sopenharmony_ci atl1e_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); 21962306a36Sopenharmony_ci spin_unlock(&adapter->mdio_lock); 22062306a36Sopenharmony_ci link_up = phy_data & BMSR_LSTATUS; 22162306a36Sopenharmony_ci /* notify upper layer link down ASAP */ 22262306a36Sopenharmony_ci if (!link_up) { 22362306a36Sopenharmony_ci if (netif_carrier_ok(netdev)) { 22462306a36Sopenharmony_ci /* old link state: Up */ 22562306a36Sopenharmony_ci netdev_info(netdev, "NIC Link is Down\n"); 22662306a36Sopenharmony_ci adapter->link_speed = SPEED_0; 22762306a36Sopenharmony_ci netif_stop_queue(netdev); 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci schedule_work(&adapter->link_chg_task); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic void atl1e_del_timer(struct atl1e_adapter *adapter) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci del_timer_sync(&adapter->phy_config_timer); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic void atl1e_cancel_work(struct atl1e_adapter *adapter) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci cancel_work_sync(&adapter->reset_task); 24162306a36Sopenharmony_ci cancel_work_sync(&adapter->link_chg_task); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci/** 24562306a36Sopenharmony_ci * atl1e_tx_timeout - Respond to a Tx Hang 24662306a36Sopenharmony_ci * @netdev: network interface device structure 24762306a36Sopenharmony_ci * @txqueue: the index of the hanging queue 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_cistatic void atl1e_tx_timeout(struct net_device *netdev, unsigned int txqueue) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* Do the reset outside of interrupt context */ 25462306a36Sopenharmony_ci schedule_work(&adapter->reset_task); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/** 25862306a36Sopenharmony_ci * atl1e_set_multi - Multicast and Promiscuous mode set 25962306a36Sopenharmony_ci * @netdev: network interface device structure 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * The set_multi entry point is called whenever the multicast address 26262306a36Sopenharmony_ci * list or the network interface flags are updated. This routine is 26362306a36Sopenharmony_ci * responsible for configuring the hardware for proper multicast, 26462306a36Sopenharmony_ci * promiscuous mode, and all-multi behavior. 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_cistatic void atl1e_set_multi(struct net_device *netdev) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 26962306a36Sopenharmony_ci struct atl1e_hw *hw = &adapter->hw; 27062306a36Sopenharmony_ci struct netdev_hw_addr *ha; 27162306a36Sopenharmony_ci u32 mac_ctrl_data = 0; 27262306a36Sopenharmony_ci u32 hash_value; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Check for Promiscuous and All Multicast modes */ 27562306a36Sopenharmony_ci mac_ctrl_data = AT_READ_REG(hw, REG_MAC_CTRL); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (netdev->flags & IFF_PROMISC) { 27862306a36Sopenharmony_ci mac_ctrl_data |= MAC_CTRL_PROMIS_EN; 27962306a36Sopenharmony_ci } else if (netdev->flags & IFF_ALLMULTI) { 28062306a36Sopenharmony_ci mac_ctrl_data |= MAC_CTRL_MC_ALL_EN; 28162306a36Sopenharmony_ci mac_ctrl_data &= ~MAC_CTRL_PROMIS_EN; 28262306a36Sopenharmony_ci } else { 28362306a36Sopenharmony_ci mac_ctrl_data &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN); 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* clear the old settings from the multicast hash table */ 28962306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_RX_HASH_TABLE, 0); 29062306a36Sopenharmony_ci AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* comoute mc addresses' hash value ,and put it into hash table */ 29362306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, netdev) { 29462306a36Sopenharmony_ci hash_value = atl1e_hash_mc_addr(hw, ha->addr); 29562306a36Sopenharmony_ci atl1e_hash_set(hw, hash_value); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic void __atl1e_rx_mode(netdev_features_t features, u32 *mac_ctrl_data) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (features & NETIF_F_RXALL) { 30362306a36Sopenharmony_ci /* enable RX of ALL frames */ 30462306a36Sopenharmony_ci *mac_ctrl_data |= MAC_CTRL_DBG; 30562306a36Sopenharmony_ci } else { 30662306a36Sopenharmony_ci /* disable RX of ALL frames */ 30762306a36Sopenharmony_ci *mac_ctrl_data &= ~MAC_CTRL_DBG; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic void atl1e_rx_mode(struct net_device *netdev, 31262306a36Sopenharmony_ci netdev_features_t features) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 31562306a36Sopenharmony_ci u32 mac_ctrl_data = 0; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci netdev_dbg(adapter->netdev, "%s\n", __func__); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci atl1e_irq_disable(adapter); 32062306a36Sopenharmony_ci mac_ctrl_data = AT_READ_REG(&adapter->hw, REG_MAC_CTRL); 32162306a36Sopenharmony_ci __atl1e_rx_mode(features, &mac_ctrl_data); 32262306a36Sopenharmony_ci AT_WRITE_REG(&adapter->hw, REG_MAC_CTRL, mac_ctrl_data); 32362306a36Sopenharmony_ci atl1e_irq_enable(adapter); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void __atl1e_vlan_mode(netdev_features_t features, u32 *mac_ctrl_data) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci if (features & NETIF_F_HW_VLAN_CTAG_RX) { 33062306a36Sopenharmony_ci /* enable VLAN tag insert/strip */ 33162306a36Sopenharmony_ci *mac_ctrl_data |= MAC_CTRL_RMV_VLAN; 33262306a36Sopenharmony_ci } else { 33362306a36Sopenharmony_ci /* disable VLAN tag insert/strip */ 33462306a36Sopenharmony_ci *mac_ctrl_data &= ~MAC_CTRL_RMV_VLAN; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic void atl1e_vlan_mode(struct net_device *netdev, 33962306a36Sopenharmony_ci netdev_features_t features) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 34262306a36Sopenharmony_ci u32 mac_ctrl_data = 0; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci netdev_dbg(adapter->netdev, "%s\n", __func__); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci atl1e_irq_disable(adapter); 34762306a36Sopenharmony_ci mac_ctrl_data = AT_READ_REG(&adapter->hw, REG_MAC_CTRL); 34862306a36Sopenharmony_ci __atl1e_vlan_mode(features, &mac_ctrl_data); 34962306a36Sopenharmony_ci AT_WRITE_REG(&adapter->hw, REG_MAC_CTRL, mac_ctrl_data); 35062306a36Sopenharmony_ci atl1e_irq_enable(adapter); 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic void atl1e_restore_vlan(struct atl1e_adapter *adapter) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci netdev_dbg(adapter->netdev, "%s\n", __func__); 35662306a36Sopenharmony_ci atl1e_vlan_mode(adapter->netdev, adapter->netdev->features); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci/** 36062306a36Sopenharmony_ci * atl1e_set_mac_addr - Change the Ethernet Address of the NIC 36162306a36Sopenharmony_ci * @netdev: network interface device structure 36262306a36Sopenharmony_ci * @p: pointer to an address structure 36362306a36Sopenharmony_ci * 36462306a36Sopenharmony_ci * Returns 0 on success, negative on failure 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_cistatic int atl1e_set_mac_addr(struct net_device *netdev, void *p) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 36962306a36Sopenharmony_ci struct sockaddr *addr = p; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 37262306a36Sopenharmony_ci return -EADDRNOTAVAIL; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (netif_running(netdev)) 37562306a36Sopenharmony_ci return -EBUSY; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci eth_hw_addr_set(netdev, addr->sa_data); 37862306a36Sopenharmony_ci memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci atl1e_hw_set_mac_addr(&adapter->hw); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return 0; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic netdev_features_t atl1e_fix_features(struct net_device *netdev, 38662306a36Sopenharmony_ci netdev_features_t features) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci /* 38962306a36Sopenharmony_ci * Since there is no support for separate rx/tx vlan accel 39062306a36Sopenharmony_ci * enable/disable make sure tx flag is always in same state as rx. 39162306a36Sopenharmony_ci */ 39262306a36Sopenharmony_ci if (features & NETIF_F_HW_VLAN_CTAG_RX) 39362306a36Sopenharmony_ci features |= NETIF_F_HW_VLAN_CTAG_TX; 39462306a36Sopenharmony_ci else 39562306a36Sopenharmony_ci features &= ~NETIF_F_HW_VLAN_CTAG_TX; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci return features; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic int atl1e_set_features(struct net_device *netdev, 40162306a36Sopenharmony_ci netdev_features_t features) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci netdev_features_t changed = netdev->features ^ features; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (changed & NETIF_F_HW_VLAN_CTAG_RX) 40662306a36Sopenharmony_ci atl1e_vlan_mode(netdev, features); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (changed & NETIF_F_RXALL) 40962306a36Sopenharmony_ci atl1e_rx_mode(netdev, features); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return 0; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci/** 41662306a36Sopenharmony_ci * atl1e_change_mtu - Change the Maximum Transfer Unit 41762306a36Sopenharmony_ci * @netdev: network interface device structure 41862306a36Sopenharmony_ci * @new_mtu: new value for maximum frame size 41962306a36Sopenharmony_ci * 42062306a36Sopenharmony_ci * Returns 0 on success, negative on failure 42162306a36Sopenharmony_ci */ 42262306a36Sopenharmony_cistatic int atl1e_change_mtu(struct net_device *netdev, int new_mtu) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 42562306a36Sopenharmony_ci int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* set MTU */ 42862306a36Sopenharmony_ci if (netif_running(netdev)) { 42962306a36Sopenharmony_ci while (test_and_set_bit(__AT_RESETTING, &adapter->flags)) 43062306a36Sopenharmony_ci msleep(1); 43162306a36Sopenharmony_ci netdev->mtu = new_mtu; 43262306a36Sopenharmony_ci adapter->hw.max_frame_size = new_mtu; 43362306a36Sopenharmony_ci adapter->hw.rx_jumbo_th = (max_frame + 7) >> 3; 43462306a36Sopenharmony_ci atl1e_down(adapter); 43562306a36Sopenharmony_ci atl1e_up(adapter); 43662306a36Sopenharmony_ci clear_bit(__AT_RESETTING, &adapter->flags); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci return 0; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/* 44262306a36Sopenharmony_ci * caller should hold mdio_lock 44362306a36Sopenharmony_ci */ 44462306a36Sopenharmony_cistatic int atl1e_mdio_read(struct net_device *netdev, int phy_id, int reg_num) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 44762306a36Sopenharmony_ci u16 result; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci atl1e_read_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, &result); 45062306a36Sopenharmony_ci return result; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic void atl1e_mdio_write(struct net_device *netdev, int phy_id, 45462306a36Sopenharmony_ci int reg_num, int val) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (atl1e_write_phy_reg(&adapter->hw, 45962306a36Sopenharmony_ci reg_num & MDIO_REG_ADDR_MASK, val)) 46062306a36Sopenharmony_ci netdev_err(netdev, "write phy register failed\n"); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic int atl1e_mii_ioctl(struct net_device *netdev, 46462306a36Sopenharmony_ci struct ifreq *ifr, int cmd) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 46762306a36Sopenharmony_ci struct mii_ioctl_data *data = if_mii(ifr); 46862306a36Sopenharmony_ci unsigned long flags; 46962306a36Sopenharmony_ci int retval = 0; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (!netif_running(netdev)) 47262306a36Sopenharmony_ci return -EINVAL; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci spin_lock_irqsave(&adapter->mdio_lock, flags); 47562306a36Sopenharmony_ci switch (cmd) { 47662306a36Sopenharmony_ci case SIOCGMIIPHY: 47762306a36Sopenharmony_ci data->phy_id = 0; 47862306a36Sopenharmony_ci break; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci case SIOCGMIIREG: 48162306a36Sopenharmony_ci if (atl1e_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, 48262306a36Sopenharmony_ci &data->val_out)) { 48362306a36Sopenharmony_ci retval = -EIO; 48462306a36Sopenharmony_ci goto out; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci case SIOCSMIIREG: 48962306a36Sopenharmony_ci if (data->reg_num & ~(0x1F)) { 49062306a36Sopenharmony_ci retval = -EFAULT; 49162306a36Sopenharmony_ci goto out; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci netdev_dbg(adapter->netdev, "<atl1e_mii_ioctl> write %x %x\n", 49562306a36Sopenharmony_ci data->reg_num, data->val_in); 49662306a36Sopenharmony_ci if (atl1e_write_phy_reg(&adapter->hw, 49762306a36Sopenharmony_ci data->reg_num, data->val_in)) { 49862306a36Sopenharmony_ci retval = -EIO; 49962306a36Sopenharmony_ci goto out; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci break; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci default: 50462306a36Sopenharmony_ci retval = -EOPNOTSUPP; 50562306a36Sopenharmony_ci break; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ciout: 50862306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->mdio_lock, flags); 50962306a36Sopenharmony_ci return retval; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic int atl1e_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci switch (cmd) { 51662306a36Sopenharmony_ci case SIOCGMIIPHY: 51762306a36Sopenharmony_ci case SIOCGMIIREG: 51862306a36Sopenharmony_ci case SIOCSMIIREG: 51962306a36Sopenharmony_ci return atl1e_mii_ioctl(netdev, ifr, cmd); 52062306a36Sopenharmony_ci default: 52162306a36Sopenharmony_ci return -EOPNOTSUPP; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic void atl1e_setup_pcicmd(struct pci_dev *pdev) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci u16 cmd; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci pci_read_config_word(pdev, PCI_COMMAND, &cmd); 53062306a36Sopenharmony_ci cmd &= ~(PCI_COMMAND_INTX_DISABLE | PCI_COMMAND_IO); 53162306a36Sopenharmony_ci cmd |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); 53262306a36Sopenharmony_ci pci_write_config_word(pdev, PCI_COMMAND, cmd); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* 53562306a36Sopenharmony_ci * some motherboards BIOS(PXE/EFI) driver may set PME 53662306a36Sopenharmony_ci * while they transfer control to OS (Windows/Linux) 53762306a36Sopenharmony_ci * so we should clear this bit before NIC work normally 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci pci_write_config_dword(pdev, REG_PM_CTRLSTAT, 0); 54062306a36Sopenharmony_ci msleep(1); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci/** 54462306a36Sopenharmony_ci * atl1e_alloc_queues - Allocate memory for all rings 54562306a36Sopenharmony_ci * @adapter: board private structure to initialize 54662306a36Sopenharmony_ci * 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_cistatic int atl1e_alloc_queues(struct atl1e_adapter *adapter) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci return 0; 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci/** 55462306a36Sopenharmony_ci * atl1e_sw_init - Initialize general software structures (struct atl1e_adapter) 55562306a36Sopenharmony_ci * @adapter: board private structure to initialize 55662306a36Sopenharmony_ci * 55762306a36Sopenharmony_ci * atl1e_sw_init initializes the Adapter private data structure. 55862306a36Sopenharmony_ci * Fields are initialized based on PCI device information and 55962306a36Sopenharmony_ci * OS network device settings (MTU size). 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_cistatic int atl1e_sw_init(struct atl1e_adapter *adapter) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci struct atl1e_hw *hw = &adapter->hw; 56462306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 56562306a36Sopenharmony_ci u32 phy_status_data = 0; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci adapter->wol = 0; 56862306a36Sopenharmony_ci adapter->link_speed = SPEED_0; /* hardware init */ 56962306a36Sopenharmony_ci adapter->link_duplex = FULL_DUPLEX; 57062306a36Sopenharmony_ci adapter->num_rx_queues = 1; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* PCI config space info */ 57362306a36Sopenharmony_ci hw->vendor_id = pdev->vendor; 57462306a36Sopenharmony_ci hw->device_id = pdev->device; 57562306a36Sopenharmony_ci hw->subsystem_vendor_id = pdev->subsystem_vendor; 57662306a36Sopenharmony_ci hw->subsystem_id = pdev->subsystem_device; 57762306a36Sopenharmony_ci hw->revision_id = pdev->revision; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci phy_status_data = AT_READ_REG(hw, REG_PHY_STATUS); 58262306a36Sopenharmony_ci /* nic type */ 58362306a36Sopenharmony_ci if (hw->revision_id >= 0xF0) { 58462306a36Sopenharmony_ci hw->nic_type = athr_l2e_revB; 58562306a36Sopenharmony_ci } else { 58662306a36Sopenharmony_ci if (phy_status_data & PHY_STATUS_100M) 58762306a36Sopenharmony_ci hw->nic_type = athr_l1e; 58862306a36Sopenharmony_ci else 58962306a36Sopenharmony_ci hw->nic_type = athr_l2e_revA; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci phy_status_data = AT_READ_REG(hw, REG_PHY_STATUS); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (phy_status_data & PHY_STATUS_EMI_CA) 59562306a36Sopenharmony_ci hw->emi_ca = true; 59662306a36Sopenharmony_ci else 59762306a36Sopenharmony_ci hw->emi_ca = false; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci hw->phy_configured = false; 60062306a36Sopenharmony_ci hw->preamble_len = 7; 60162306a36Sopenharmony_ci hw->max_frame_size = adapter->netdev->mtu; 60262306a36Sopenharmony_ci hw->rx_jumbo_th = (hw->max_frame_size + ETH_HLEN + 60362306a36Sopenharmony_ci VLAN_HLEN + ETH_FCS_LEN + 7) >> 3; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci hw->rrs_type = atl1e_rrs_disable; 60662306a36Sopenharmony_ci hw->indirect_tab = 0; 60762306a36Sopenharmony_ci hw->base_cpu = 0; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* need confirm */ 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci hw->ict = 50000; /* 100ms */ 61262306a36Sopenharmony_ci hw->smb_timer = 200000; /* 200ms */ 61362306a36Sopenharmony_ci hw->tpd_burst = 5; 61462306a36Sopenharmony_ci hw->rrd_thresh = 1; 61562306a36Sopenharmony_ci hw->tpd_thresh = adapter->tx_ring.count / 2; 61662306a36Sopenharmony_ci hw->rx_count_down = 4; /* 2us resolution */ 61762306a36Sopenharmony_ci hw->tx_count_down = hw->imt * 4 / 3; 61862306a36Sopenharmony_ci hw->dmar_block = atl1e_dma_req_1024; 61962306a36Sopenharmony_ci hw->dmaw_block = atl1e_dma_req_1024; 62062306a36Sopenharmony_ci hw->dmar_dly_cnt = 15; 62162306a36Sopenharmony_ci hw->dmaw_dly_cnt = 4; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (atl1e_alloc_queues(adapter)) { 62462306a36Sopenharmony_ci netdev_err(adapter->netdev, "Unable to allocate memory for queues\n"); 62562306a36Sopenharmony_ci return -ENOMEM; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci atomic_set(&adapter->irq_sem, 1); 62962306a36Sopenharmony_ci spin_lock_init(&adapter->mdio_lock); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci set_bit(__AT_DOWN, &adapter->flags); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci return 0; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci/** 63762306a36Sopenharmony_ci * atl1e_clean_tx_ring - Free Tx-skb 63862306a36Sopenharmony_ci * @adapter: board private structure 63962306a36Sopenharmony_ci */ 64062306a36Sopenharmony_cistatic void atl1e_clean_tx_ring(struct atl1e_adapter *adapter) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci struct atl1e_tx_ring *tx_ring = &adapter->tx_ring; 64362306a36Sopenharmony_ci struct atl1e_tx_buffer *tx_buffer = NULL; 64462306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 64562306a36Sopenharmony_ci u16 index, ring_count; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci if (tx_ring->desc == NULL || tx_ring->tx_buffer == NULL) 64862306a36Sopenharmony_ci return; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci ring_count = tx_ring->count; 65162306a36Sopenharmony_ci /* first unmmap dma */ 65262306a36Sopenharmony_ci for (index = 0; index < ring_count; index++) { 65362306a36Sopenharmony_ci tx_buffer = &tx_ring->tx_buffer[index]; 65462306a36Sopenharmony_ci if (tx_buffer->dma) { 65562306a36Sopenharmony_ci if (tx_buffer->flags & ATL1E_TX_PCIMAP_SINGLE) 65662306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, tx_buffer->dma, 65762306a36Sopenharmony_ci tx_buffer->length, 65862306a36Sopenharmony_ci DMA_TO_DEVICE); 65962306a36Sopenharmony_ci else if (tx_buffer->flags & ATL1E_TX_PCIMAP_PAGE) 66062306a36Sopenharmony_ci dma_unmap_page(&pdev->dev, tx_buffer->dma, 66162306a36Sopenharmony_ci tx_buffer->length, 66262306a36Sopenharmony_ci DMA_TO_DEVICE); 66362306a36Sopenharmony_ci tx_buffer->dma = 0; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci /* second free skb */ 66762306a36Sopenharmony_ci for (index = 0; index < ring_count; index++) { 66862306a36Sopenharmony_ci tx_buffer = &tx_ring->tx_buffer[index]; 66962306a36Sopenharmony_ci if (tx_buffer->skb) { 67062306a36Sopenharmony_ci dev_kfree_skb_any(tx_buffer->skb); 67162306a36Sopenharmony_ci tx_buffer->skb = NULL; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci /* Zero out Tx-buffers */ 67562306a36Sopenharmony_ci memset(tx_ring->desc, 0, sizeof(struct atl1e_tpd_desc) * 67662306a36Sopenharmony_ci ring_count); 67762306a36Sopenharmony_ci memset(tx_ring->tx_buffer, 0, sizeof(struct atl1e_tx_buffer) * 67862306a36Sopenharmony_ci ring_count); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci/** 68262306a36Sopenharmony_ci * atl1e_clean_rx_ring - Free rx-reservation skbs 68362306a36Sopenharmony_ci * @adapter: board private structure 68462306a36Sopenharmony_ci */ 68562306a36Sopenharmony_cistatic void atl1e_clean_rx_ring(struct atl1e_adapter *adapter) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci struct atl1e_rx_ring *rx_ring = 68862306a36Sopenharmony_ci &adapter->rx_ring; 68962306a36Sopenharmony_ci struct atl1e_rx_page_desc *rx_page_desc = rx_ring->rx_page_desc; 69062306a36Sopenharmony_ci u16 i, j; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (adapter->ring_vir_addr == NULL) 69462306a36Sopenharmony_ci return; 69562306a36Sopenharmony_ci /* Zero out the descriptor ring */ 69662306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 69762306a36Sopenharmony_ci for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) { 69862306a36Sopenharmony_ci if (rx_page_desc[i].rx_page[j].addr != NULL) { 69962306a36Sopenharmony_ci memset(rx_page_desc[i].rx_page[j].addr, 0, 70062306a36Sopenharmony_ci rx_ring->real_page_size); 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic void atl1e_cal_ring_size(struct atl1e_adapter *adapter, u32 *ring_size) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci *ring_size = ((u32)(adapter->tx_ring.count * 70962306a36Sopenharmony_ci sizeof(struct atl1e_tpd_desc) + 7 71062306a36Sopenharmony_ci /* tx ring, qword align */ 71162306a36Sopenharmony_ci + adapter->rx_ring.real_page_size * AT_PAGE_NUM_PER_QUEUE * 71262306a36Sopenharmony_ci adapter->num_rx_queues + 31 71362306a36Sopenharmony_ci /* rx ring, 32 bytes align */ 71462306a36Sopenharmony_ci + (1 + AT_PAGE_NUM_PER_QUEUE * adapter->num_rx_queues) * 71562306a36Sopenharmony_ci sizeof(u32) + 3)); 71662306a36Sopenharmony_ci /* tx, rx cmd, dword align */ 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic void atl1e_init_ring_resources(struct atl1e_adapter *adapter) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci struct atl1e_rx_ring *rx_ring = NULL; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci rx_ring = &adapter->rx_ring; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci rx_ring->real_page_size = adapter->rx_ring.page_size 72662306a36Sopenharmony_ci + adapter->hw.max_frame_size 72762306a36Sopenharmony_ci + ETH_HLEN + VLAN_HLEN 72862306a36Sopenharmony_ci + ETH_FCS_LEN; 72962306a36Sopenharmony_ci rx_ring->real_page_size = roundup(rx_ring->real_page_size, 32); 73062306a36Sopenharmony_ci atl1e_cal_ring_size(adapter, &adapter->ring_size); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci adapter->ring_vir_addr = NULL; 73362306a36Sopenharmony_ci adapter->rx_ring.desc = NULL; 73462306a36Sopenharmony_ci rwlock_init(&adapter->tx_ring.tx_lock); 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci/* 73862306a36Sopenharmony_ci * Read / Write Ptr Initialize: 73962306a36Sopenharmony_ci */ 74062306a36Sopenharmony_cistatic void atl1e_init_ring_ptrs(struct atl1e_adapter *adapter) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct atl1e_tx_ring *tx_ring = NULL; 74362306a36Sopenharmony_ci struct atl1e_rx_ring *rx_ring = NULL; 74462306a36Sopenharmony_ci struct atl1e_rx_page_desc *rx_page_desc = NULL; 74562306a36Sopenharmony_ci int i, j; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci tx_ring = &adapter->tx_ring; 74862306a36Sopenharmony_ci rx_ring = &adapter->rx_ring; 74962306a36Sopenharmony_ci rx_page_desc = rx_ring->rx_page_desc; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci tx_ring->next_to_use = 0; 75262306a36Sopenharmony_ci atomic_set(&tx_ring->next_to_clean, 0); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 75562306a36Sopenharmony_ci rx_page_desc[i].rx_using = 0; 75662306a36Sopenharmony_ci rx_page_desc[i].rx_nxseq = 0; 75762306a36Sopenharmony_ci for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) { 75862306a36Sopenharmony_ci *rx_page_desc[i].rx_page[j].write_offset_addr = 0; 75962306a36Sopenharmony_ci rx_page_desc[i].rx_page[j].read_offset = 0; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci/** 76562306a36Sopenharmony_ci * atl1e_free_ring_resources - Free Tx / RX descriptor Resources 76662306a36Sopenharmony_ci * @adapter: board private structure 76762306a36Sopenharmony_ci * 76862306a36Sopenharmony_ci * Free all transmit software resources 76962306a36Sopenharmony_ci */ 77062306a36Sopenharmony_cistatic void atl1e_free_ring_resources(struct atl1e_adapter *adapter) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci atl1e_clean_tx_ring(adapter); 77562306a36Sopenharmony_ci atl1e_clean_rx_ring(adapter); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (adapter->ring_vir_addr) { 77862306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, adapter->ring_size, 77962306a36Sopenharmony_ci adapter->ring_vir_addr, adapter->ring_dma); 78062306a36Sopenharmony_ci adapter->ring_vir_addr = NULL; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci if (adapter->tx_ring.tx_buffer) { 78462306a36Sopenharmony_ci kfree(adapter->tx_ring.tx_buffer); 78562306a36Sopenharmony_ci adapter->tx_ring.tx_buffer = NULL; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci/** 79062306a36Sopenharmony_ci * atl1e_setup_ring_resources - allocate Tx / RX descriptor resources 79162306a36Sopenharmony_ci * @adapter: board private structure 79262306a36Sopenharmony_ci * 79362306a36Sopenharmony_ci * Return 0 on success, negative on failure 79462306a36Sopenharmony_ci */ 79562306a36Sopenharmony_cistatic int atl1e_setup_ring_resources(struct atl1e_adapter *adapter) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 79862306a36Sopenharmony_ci struct atl1e_tx_ring *tx_ring; 79962306a36Sopenharmony_ci struct atl1e_rx_ring *rx_ring; 80062306a36Sopenharmony_ci struct atl1e_rx_page_desc *rx_page_desc; 80162306a36Sopenharmony_ci int size, i, j; 80262306a36Sopenharmony_ci u32 offset = 0; 80362306a36Sopenharmony_ci int err = 0; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (adapter->ring_vir_addr != NULL) 80662306a36Sopenharmony_ci return 0; /* alloced already */ 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci tx_ring = &adapter->tx_ring; 80962306a36Sopenharmony_ci rx_ring = &adapter->rx_ring; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci /* real ring DMA buffer */ 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci size = adapter->ring_size; 81462306a36Sopenharmony_ci adapter->ring_vir_addr = dma_alloc_coherent(&pdev->dev, 81562306a36Sopenharmony_ci adapter->ring_size, 81662306a36Sopenharmony_ci &adapter->ring_dma, GFP_KERNEL); 81762306a36Sopenharmony_ci if (adapter->ring_vir_addr == NULL) { 81862306a36Sopenharmony_ci netdev_err(adapter->netdev, 81962306a36Sopenharmony_ci "dma_alloc_coherent failed, size = D%d\n", size); 82062306a36Sopenharmony_ci return -ENOMEM; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci rx_page_desc = rx_ring->rx_page_desc; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci /* Init TPD Ring */ 82662306a36Sopenharmony_ci tx_ring->dma = roundup(adapter->ring_dma, 8); 82762306a36Sopenharmony_ci offset = tx_ring->dma - adapter->ring_dma; 82862306a36Sopenharmony_ci tx_ring->desc = adapter->ring_vir_addr + offset; 82962306a36Sopenharmony_ci size = sizeof(struct atl1e_tx_buffer) * (tx_ring->count); 83062306a36Sopenharmony_ci tx_ring->tx_buffer = kzalloc(size, GFP_KERNEL); 83162306a36Sopenharmony_ci if (tx_ring->tx_buffer == NULL) { 83262306a36Sopenharmony_ci err = -ENOMEM; 83362306a36Sopenharmony_ci goto failed; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* Init RXF-Pages */ 83762306a36Sopenharmony_ci offset += (sizeof(struct atl1e_tpd_desc) * tx_ring->count); 83862306a36Sopenharmony_ci offset = roundup(offset, 32); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 84162306a36Sopenharmony_ci for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) { 84262306a36Sopenharmony_ci rx_page_desc[i].rx_page[j].dma = 84362306a36Sopenharmony_ci adapter->ring_dma + offset; 84462306a36Sopenharmony_ci rx_page_desc[i].rx_page[j].addr = 84562306a36Sopenharmony_ci adapter->ring_vir_addr + offset; 84662306a36Sopenharmony_ci offset += rx_ring->real_page_size; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci /* Init CMB dma address */ 85162306a36Sopenharmony_ci tx_ring->cmb_dma = adapter->ring_dma + offset; 85262306a36Sopenharmony_ci tx_ring->cmb = adapter->ring_vir_addr + offset; 85362306a36Sopenharmony_ci offset += sizeof(u32); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 85662306a36Sopenharmony_ci for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) { 85762306a36Sopenharmony_ci rx_page_desc[i].rx_page[j].write_offset_dma = 85862306a36Sopenharmony_ci adapter->ring_dma + offset; 85962306a36Sopenharmony_ci rx_page_desc[i].rx_page[j].write_offset_addr = 86062306a36Sopenharmony_ci adapter->ring_vir_addr + offset; 86162306a36Sopenharmony_ci offset += sizeof(u32); 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (unlikely(offset > adapter->ring_size)) { 86662306a36Sopenharmony_ci netdev_err(adapter->netdev, "offset(%d) > ring size(%d) !!\n", 86762306a36Sopenharmony_ci offset, adapter->ring_size); 86862306a36Sopenharmony_ci err = -1; 86962306a36Sopenharmony_ci goto free_buffer; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci return 0; 87362306a36Sopenharmony_cifree_buffer: 87462306a36Sopenharmony_ci kfree(tx_ring->tx_buffer); 87562306a36Sopenharmony_ci tx_ring->tx_buffer = NULL; 87662306a36Sopenharmony_cifailed: 87762306a36Sopenharmony_ci if (adapter->ring_vir_addr != NULL) { 87862306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, adapter->ring_size, 87962306a36Sopenharmony_ci adapter->ring_vir_addr, adapter->ring_dma); 88062306a36Sopenharmony_ci adapter->ring_vir_addr = NULL; 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci return err; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic inline void atl1e_configure_des_ring(struct atl1e_adapter *adapter) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci struct atl1e_hw *hw = &adapter->hw; 88962306a36Sopenharmony_ci struct atl1e_rx_ring *rx_ring = &adapter->rx_ring; 89062306a36Sopenharmony_ci struct atl1e_tx_ring *tx_ring = &adapter->tx_ring; 89162306a36Sopenharmony_ci struct atl1e_rx_page_desc *rx_page_desc = NULL; 89262306a36Sopenharmony_ci int i, j; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_DESC_BASE_ADDR_HI, 89562306a36Sopenharmony_ci (u32)((adapter->ring_dma & AT_DMA_HI_ADDR_MASK) >> 32)); 89662306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_TPD_BASE_ADDR_LO, 89762306a36Sopenharmony_ci (u32)((tx_ring->dma) & AT_DMA_LO_ADDR_MASK)); 89862306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_TPD_RING_SIZE, (u16)(tx_ring->count)); 89962306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_HOST_TX_CMB_LO, 90062306a36Sopenharmony_ci (u32)((tx_ring->cmb_dma) & AT_DMA_LO_ADDR_MASK)); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci rx_page_desc = rx_ring->rx_page_desc; 90362306a36Sopenharmony_ci /* RXF Page Physical address / Page Length */ 90462306a36Sopenharmony_ci for (i = 0; i < AT_MAX_RECEIVE_QUEUE; i++) { 90562306a36Sopenharmony_ci AT_WRITE_REG(hw, atl1e_rx_page_hi_addr_regs[i], 90662306a36Sopenharmony_ci (u32)((adapter->ring_dma & 90762306a36Sopenharmony_ci AT_DMA_HI_ADDR_MASK) >> 32)); 90862306a36Sopenharmony_ci for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) { 90962306a36Sopenharmony_ci u32 page_phy_addr; 91062306a36Sopenharmony_ci u32 offset_phy_addr; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci page_phy_addr = rx_page_desc[i].rx_page[j].dma; 91362306a36Sopenharmony_ci offset_phy_addr = 91462306a36Sopenharmony_ci rx_page_desc[i].rx_page[j].write_offset_dma; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci AT_WRITE_REG(hw, atl1e_rx_page_lo_addr_regs[i][j], 91762306a36Sopenharmony_ci page_phy_addr & AT_DMA_LO_ADDR_MASK); 91862306a36Sopenharmony_ci AT_WRITE_REG(hw, atl1e_rx_page_write_offset_regs[i][j], 91962306a36Sopenharmony_ci offset_phy_addr & AT_DMA_LO_ADDR_MASK); 92062306a36Sopenharmony_ci AT_WRITE_REGB(hw, atl1e_rx_page_vld_regs[i][j], 1); 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci /* Page Length */ 92462306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_HOST_RXFPAGE_SIZE, rx_ring->page_size); 92562306a36Sopenharmony_ci /* Load all of base address above */ 92662306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_LOAD_PTR, 1); 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_cistatic inline void atl1e_configure_tx(struct atl1e_adapter *adapter) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci struct atl1e_hw *hw = &adapter->hw; 93262306a36Sopenharmony_ci u32 dev_ctrl_data = 0; 93362306a36Sopenharmony_ci u32 max_pay_load = 0; 93462306a36Sopenharmony_ci u32 jumbo_thresh = 0; 93562306a36Sopenharmony_ci u32 extra_size = 0; /* Jumbo frame threshold in QWORD unit */ 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci /* configure TXQ param */ 93862306a36Sopenharmony_ci if (hw->nic_type != athr_l2e_revB) { 93962306a36Sopenharmony_ci extra_size = ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN; 94062306a36Sopenharmony_ci if (hw->max_frame_size <= 1500) { 94162306a36Sopenharmony_ci jumbo_thresh = hw->max_frame_size + extra_size; 94262306a36Sopenharmony_ci } else if (hw->max_frame_size < 6*1024) { 94362306a36Sopenharmony_ci jumbo_thresh = 94462306a36Sopenharmony_ci (hw->max_frame_size + extra_size) * 2 / 3; 94562306a36Sopenharmony_ci } else { 94662306a36Sopenharmony_ci jumbo_thresh = (hw->max_frame_size + extra_size) / 2; 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_TX_EARLY_TH, (jumbo_thresh + 7) >> 3); 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci dev_ctrl_data = AT_READ_REG(hw, REG_DEVICE_CTRL); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci max_pay_load = ((dev_ctrl_data >> DEVICE_CTRL_MAX_PAYLOAD_SHIFT)) & 95462306a36Sopenharmony_ci DEVICE_CTRL_MAX_PAYLOAD_MASK; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci hw->dmaw_block = min_t(u32, max_pay_load, hw->dmaw_block); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci max_pay_load = ((dev_ctrl_data >> DEVICE_CTRL_MAX_RREQ_SZ_SHIFT)) & 95962306a36Sopenharmony_ci DEVICE_CTRL_MAX_RREQ_SZ_MASK; 96062306a36Sopenharmony_ci hw->dmar_block = min_t(u32, max_pay_load, hw->dmar_block); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (hw->nic_type != athr_l2e_revB) 96362306a36Sopenharmony_ci AT_WRITE_REGW(hw, REG_TXQ_CTRL + 2, 96462306a36Sopenharmony_ci atl1e_pay_load_size[hw->dmar_block]); 96562306a36Sopenharmony_ci /* enable TXQ */ 96662306a36Sopenharmony_ci AT_WRITE_REGW(hw, REG_TXQ_CTRL, 96762306a36Sopenharmony_ci (((u16)hw->tpd_burst & TXQ_CTRL_NUM_TPD_BURST_MASK) 96862306a36Sopenharmony_ci << TXQ_CTRL_NUM_TPD_BURST_SHIFT) 96962306a36Sopenharmony_ci | TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN); 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_cistatic inline void atl1e_configure_rx(struct atl1e_adapter *adapter) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci struct atl1e_hw *hw = &adapter->hw; 97562306a36Sopenharmony_ci u32 rxf_len = 0; 97662306a36Sopenharmony_ci u32 rxf_low = 0; 97762306a36Sopenharmony_ci u32 rxf_high = 0; 97862306a36Sopenharmony_ci u32 rxf_thresh_data = 0; 97962306a36Sopenharmony_ci u32 rxq_ctrl_data = 0; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (hw->nic_type != athr_l2e_revB) { 98262306a36Sopenharmony_ci AT_WRITE_REGW(hw, REG_RXQ_JMBOSZ_RRDTIM, 98362306a36Sopenharmony_ci (u16)((hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK) << 98462306a36Sopenharmony_ci RXQ_JMBOSZ_TH_SHIFT | 98562306a36Sopenharmony_ci (1 & RXQ_JMBO_LKAH_MASK) << 98662306a36Sopenharmony_ci RXQ_JMBO_LKAH_SHIFT)); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci rxf_len = AT_READ_REG(hw, REG_SRAM_RXF_LEN); 98962306a36Sopenharmony_ci rxf_high = rxf_len * 4 / 5; 99062306a36Sopenharmony_ci rxf_low = rxf_len / 5; 99162306a36Sopenharmony_ci rxf_thresh_data = ((rxf_high & RXQ_RXF_PAUSE_TH_HI_MASK) 99262306a36Sopenharmony_ci << RXQ_RXF_PAUSE_TH_HI_SHIFT) | 99362306a36Sopenharmony_ci ((rxf_low & RXQ_RXF_PAUSE_TH_LO_MASK) 99462306a36Sopenharmony_ci << RXQ_RXF_PAUSE_TH_LO_SHIFT); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_RXQ_RXF_PAUSE_THRESH, rxf_thresh_data); 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* RRS */ 100062306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_IDT_TABLE, hw->indirect_tab); 100162306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_BASE_CPU_NUMBER, hw->base_cpu); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (hw->rrs_type & atl1e_rrs_ipv4) 100462306a36Sopenharmony_ci rxq_ctrl_data |= RXQ_CTRL_HASH_TYPE_IPV4; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci if (hw->rrs_type & atl1e_rrs_ipv4_tcp) 100762306a36Sopenharmony_ci rxq_ctrl_data |= RXQ_CTRL_HASH_TYPE_IPV4_TCP; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (hw->rrs_type & atl1e_rrs_ipv6) 101062306a36Sopenharmony_ci rxq_ctrl_data |= RXQ_CTRL_HASH_TYPE_IPV6; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (hw->rrs_type & atl1e_rrs_ipv6_tcp) 101362306a36Sopenharmony_ci rxq_ctrl_data |= RXQ_CTRL_HASH_TYPE_IPV6_TCP; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci if (hw->rrs_type != atl1e_rrs_disable) 101662306a36Sopenharmony_ci rxq_ctrl_data |= 101762306a36Sopenharmony_ci (RXQ_CTRL_HASH_ENABLE | RXQ_CTRL_RSS_MODE_MQUESINT); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci rxq_ctrl_data |= RXQ_CTRL_IPV6_XSUM_VERIFY_EN | RXQ_CTRL_PBA_ALIGN_32 | 102062306a36Sopenharmony_ci RXQ_CTRL_CUT_THRU_EN | RXQ_CTRL_EN; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data); 102362306a36Sopenharmony_ci} 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cistatic inline void atl1e_configure_dma(struct atl1e_adapter *adapter) 102662306a36Sopenharmony_ci{ 102762306a36Sopenharmony_ci struct atl1e_hw *hw = &adapter->hw; 102862306a36Sopenharmony_ci u32 dma_ctrl_data = 0; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci dma_ctrl_data = DMA_CTRL_RXCMB_EN; 103162306a36Sopenharmony_ci dma_ctrl_data |= (((u32)hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK) 103262306a36Sopenharmony_ci << DMA_CTRL_DMAR_BURST_LEN_SHIFT; 103362306a36Sopenharmony_ci dma_ctrl_data |= (((u32)hw->dmaw_block) & DMA_CTRL_DMAW_BURST_LEN_MASK) 103462306a36Sopenharmony_ci << DMA_CTRL_DMAW_BURST_LEN_SHIFT; 103562306a36Sopenharmony_ci dma_ctrl_data |= DMA_CTRL_DMAR_REQ_PRI | DMA_CTRL_DMAR_OUT_ORDER; 103662306a36Sopenharmony_ci dma_ctrl_data |= (((u32)hw->dmar_dly_cnt) & DMA_CTRL_DMAR_DLY_CNT_MASK) 103762306a36Sopenharmony_ci << DMA_CTRL_DMAR_DLY_CNT_SHIFT; 103862306a36Sopenharmony_ci dma_ctrl_data |= (((u32)hw->dmaw_dly_cnt) & DMA_CTRL_DMAW_DLY_CNT_MASK) 103962306a36Sopenharmony_ci << DMA_CTRL_DMAW_DLY_CNT_SHIFT; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_DMA_CTRL, dma_ctrl_data); 104262306a36Sopenharmony_ci} 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_cistatic void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter) 104562306a36Sopenharmony_ci{ 104662306a36Sopenharmony_ci u32 value; 104762306a36Sopenharmony_ci struct atl1e_hw *hw = &adapter->hw; 104862306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci /* Config MAC CTRL Register */ 105162306a36Sopenharmony_ci value = MAC_CTRL_TX_EN | 105262306a36Sopenharmony_ci MAC_CTRL_RX_EN ; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (FULL_DUPLEX == adapter->link_duplex) 105562306a36Sopenharmony_ci value |= MAC_CTRL_DUPLX; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci value |= ((u32)((SPEED_1000 == adapter->link_speed) ? 105862306a36Sopenharmony_ci MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100) << 105962306a36Sopenharmony_ci MAC_CTRL_SPEED_SHIFT); 106062306a36Sopenharmony_ci value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); 106362306a36Sopenharmony_ci value |= (((u32)adapter->hw.preamble_len & 106462306a36Sopenharmony_ci MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci __atl1e_vlan_mode(netdev->features, &value); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci value |= MAC_CTRL_BC_EN; 106962306a36Sopenharmony_ci if (netdev->flags & IFF_PROMISC) 107062306a36Sopenharmony_ci value |= MAC_CTRL_PROMIS_EN; 107162306a36Sopenharmony_ci if (netdev->flags & IFF_ALLMULTI) 107262306a36Sopenharmony_ci value |= MAC_CTRL_MC_ALL_EN; 107362306a36Sopenharmony_ci if (netdev->features & NETIF_F_RXALL) 107462306a36Sopenharmony_ci value |= MAC_CTRL_DBG; 107562306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_MAC_CTRL, value); 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci/** 107962306a36Sopenharmony_ci * atl1e_configure - Configure Transmit&Receive Unit after Reset 108062306a36Sopenharmony_ci * @adapter: board private structure 108162306a36Sopenharmony_ci * 108262306a36Sopenharmony_ci * Configure the Tx /Rx unit of the MAC after a reset. 108362306a36Sopenharmony_ci */ 108462306a36Sopenharmony_cistatic int atl1e_configure(struct atl1e_adapter *adapter) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci struct atl1e_hw *hw = &adapter->hw; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci u32 intr_status_data = 0; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci /* clear interrupt status */ 109162306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_ISR, ~0); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci /* 1. set MAC Address */ 109462306a36Sopenharmony_ci atl1e_hw_set_mac_addr(hw); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* 2. Init the Multicast HASH table done by set_muti */ 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci /* 3. Clear any WOL status */ 109962306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_WOL_CTRL, 0); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci /* 4. Descripter Ring BaseMem/Length/Read ptr/Write ptr 110262306a36Sopenharmony_ci * TPD Ring/SMB/RXF0 Page CMBs, they use the same 110362306a36Sopenharmony_ci * High 32bits memory */ 110462306a36Sopenharmony_ci atl1e_configure_des_ring(adapter); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci /* 5. set Interrupt Moderator Timer */ 110762306a36Sopenharmony_ci AT_WRITE_REGW(hw, REG_IRQ_MODU_TIMER_INIT, hw->imt); 110862306a36Sopenharmony_ci AT_WRITE_REGW(hw, REG_IRQ_MODU_TIMER2_INIT, hw->imt); 110962306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_LED_MODE | 111062306a36Sopenharmony_ci MASTER_CTRL_ITIMER_EN | MASTER_CTRL_ITIMER2_EN); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci /* 6. rx/tx threshold to trig interrupt */ 111362306a36Sopenharmony_ci AT_WRITE_REGW(hw, REG_TRIG_RRD_THRESH, hw->rrd_thresh); 111462306a36Sopenharmony_ci AT_WRITE_REGW(hw, REG_TRIG_TPD_THRESH, hw->tpd_thresh); 111562306a36Sopenharmony_ci AT_WRITE_REGW(hw, REG_TRIG_RXTIMER, hw->rx_count_down); 111662306a36Sopenharmony_ci AT_WRITE_REGW(hw, REG_TRIG_TXTIMER, hw->tx_count_down); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci /* 7. set Interrupt Clear Timer */ 111962306a36Sopenharmony_ci AT_WRITE_REGW(hw, REG_CMBDISDMA_TIMER, hw->ict); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci /* 8. set MTU */ 112262306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_MTU, hw->max_frame_size + ETH_HLEN + 112362306a36Sopenharmony_ci VLAN_HLEN + ETH_FCS_LEN); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci /* 9. config TXQ early tx threshold */ 112662306a36Sopenharmony_ci atl1e_configure_tx(adapter); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci /* 10. config RXQ */ 112962306a36Sopenharmony_ci atl1e_configure_rx(adapter); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci /* 11. config DMA Engine */ 113262306a36Sopenharmony_ci atl1e_configure_dma(adapter); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci /* 12. smb timer to trig interrupt */ 113562306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_SMB_STAT_TIMER, hw->smb_timer); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci intr_status_data = AT_READ_REG(hw, REG_ISR); 113862306a36Sopenharmony_ci if (unlikely((intr_status_data & ISR_PHY_LINKDOWN) != 0)) { 113962306a36Sopenharmony_ci netdev_err(adapter->netdev, 114062306a36Sopenharmony_ci "atl1e_configure failed, PCIE phy link down\n"); 114162306a36Sopenharmony_ci return -1; 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_ISR, 0x7fffffff); 114562306a36Sopenharmony_ci return 0; 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci/** 114962306a36Sopenharmony_ci * atl1e_get_stats - Get System Network Statistics 115062306a36Sopenharmony_ci * @netdev: network interface device structure 115162306a36Sopenharmony_ci * 115262306a36Sopenharmony_ci * Returns the address of the device statistics structure. 115362306a36Sopenharmony_ci * The statistics are actually updated from the timer callback. 115462306a36Sopenharmony_ci */ 115562306a36Sopenharmony_cistatic struct net_device_stats *atl1e_get_stats(struct net_device *netdev) 115662306a36Sopenharmony_ci{ 115762306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 115862306a36Sopenharmony_ci struct atl1e_hw_stats *hw_stats = &adapter->hw_stats; 115962306a36Sopenharmony_ci struct net_device_stats *net_stats = &netdev->stats; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci net_stats->rx_bytes = hw_stats->rx_byte_cnt; 116262306a36Sopenharmony_ci net_stats->tx_bytes = hw_stats->tx_byte_cnt; 116362306a36Sopenharmony_ci net_stats->multicast = hw_stats->rx_mcast; 116462306a36Sopenharmony_ci net_stats->collisions = hw_stats->tx_1_col + 116562306a36Sopenharmony_ci hw_stats->tx_2_col + 116662306a36Sopenharmony_ci hw_stats->tx_late_col + 116762306a36Sopenharmony_ci hw_stats->tx_abort_col; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci net_stats->rx_errors = hw_stats->rx_frag + 117062306a36Sopenharmony_ci hw_stats->rx_fcs_err + 117162306a36Sopenharmony_ci hw_stats->rx_len_err + 117262306a36Sopenharmony_ci hw_stats->rx_sz_ov + 117362306a36Sopenharmony_ci hw_stats->rx_rrd_ov + 117462306a36Sopenharmony_ci hw_stats->rx_align_err + 117562306a36Sopenharmony_ci hw_stats->rx_rxf_ov; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci net_stats->rx_fifo_errors = hw_stats->rx_rxf_ov; 117862306a36Sopenharmony_ci net_stats->rx_length_errors = hw_stats->rx_len_err; 117962306a36Sopenharmony_ci net_stats->rx_crc_errors = hw_stats->rx_fcs_err; 118062306a36Sopenharmony_ci net_stats->rx_frame_errors = hw_stats->rx_align_err; 118162306a36Sopenharmony_ci net_stats->rx_dropped = hw_stats->rx_rrd_ov; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci net_stats->tx_errors = hw_stats->tx_late_col + 118462306a36Sopenharmony_ci hw_stats->tx_abort_col + 118562306a36Sopenharmony_ci hw_stats->tx_underrun + 118662306a36Sopenharmony_ci hw_stats->tx_trunc; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci net_stats->tx_fifo_errors = hw_stats->tx_underrun; 118962306a36Sopenharmony_ci net_stats->tx_aborted_errors = hw_stats->tx_abort_col; 119062306a36Sopenharmony_ci net_stats->tx_window_errors = hw_stats->tx_late_col; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors; 119362306a36Sopenharmony_ci net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci return net_stats; 119662306a36Sopenharmony_ci} 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_cistatic void atl1e_update_hw_stats(struct atl1e_adapter *adapter) 119962306a36Sopenharmony_ci{ 120062306a36Sopenharmony_ci u16 hw_reg_addr = 0; 120162306a36Sopenharmony_ci unsigned long *stats_item = NULL; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci /* update rx status */ 120462306a36Sopenharmony_ci hw_reg_addr = REG_MAC_RX_STATUS_BIN; 120562306a36Sopenharmony_ci stats_item = &adapter->hw_stats.rx_ok; 120662306a36Sopenharmony_ci while (hw_reg_addr <= REG_MAC_RX_STATUS_END) { 120762306a36Sopenharmony_ci *stats_item += AT_READ_REG(&adapter->hw, hw_reg_addr); 120862306a36Sopenharmony_ci stats_item++; 120962306a36Sopenharmony_ci hw_reg_addr += 4; 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci /* update tx status */ 121262306a36Sopenharmony_ci hw_reg_addr = REG_MAC_TX_STATUS_BIN; 121362306a36Sopenharmony_ci stats_item = &adapter->hw_stats.tx_ok; 121462306a36Sopenharmony_ci while (hw_reg_addr <= REG_MAC_TX_STATUS_END) { 121562306a36Sopenharmony_ci *stats_item += AT_READ_REG(&adapter->hw, hw_reg_addr); 121662306a36Sopenharmony_ci stats_item++; 121762306a36Sopenharmony_ci hw_reg_addr += 4; 121862306a36Sopenharmony_ci } 121962306a36Sopenharmony_ci} 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_cistatic inline void atl1e_clear_phy_int(struct atl1e_adapter *adapter) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci u16 phy_data; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci spin_lock(&adapter->mdio_lock); 122662306a36Sopenharmony_ci atl1e_read_phy_reg(&adapter->hw, MII_INT_STATUS, &phy_data); 122762306a36Sopenharmony_ci spin_unlock(&adapter->mdio_lock); 122862306a36Sopenharmony_ci} 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_cistatic bool atl1e_clean_tx_irq(struct atl1e_adapter *adapter) 123162306a36Sopenharmony_ci{ 123262306a36Sopenharmony_ci struct atl1e_tx_ring *tx_ring = &adapter->tx_ring; 123362306a36Sopenharmony_ci struct atl1e_tx_buffer *tx_buffer = NULL; 123462306a36Sopenharmony_ci u16 hw_next_to_clean = AT_READ_REGW(&adapter->hw, REG_TPD_CONS_IDX); 123562306a36Sopenharmony_ci u16 next_to_clean = atomic_read(&tx_ring->next_to_clean); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci while (next_to_clean != hw_next_to_clean) { 123862306a36Sopenharmony_ci tx_buffer = &tx_ring->tx_buffer[next_to_clean]; 123962306a36Sopenharmony_ci if (tx_buffer->dma) { 124062306a36Sopenharmony_ci if (tx_buffer->flags & ATL1E_TX_PCIMAP_SINGLE) 124162306a36Sopenharmony_ci dma_unmap_single(&adapter->pdev->dev, 124262306a36Sopenharmony_ci tx_buffer->dma, 124362306a36Sopenharmony_ci tx_buffer->length, 124462306a36Sopenharmony_ci DMA_TO_DEVICE); 124562306a36Sopenharmony_ci else if (tx_buffer->flags & ATL1E_TX_PCIMAP_PAGE) 124662306a36Sopenharmony_ci dma_unmap_page(&adapter->pdev->dev, 124762306a36Sopenharmony_ci tx_buffer->dma, 124862306a36Sopenharmony_ci tx_buffer->length, 124962306a36Sopenharmony_ci DMA_TO_DEVICE); 125062306a36Sopenharmony_ci tx_buffer->dma = 0; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci if (tx_buffer->skb) { 125462306a36Sopenharmony_ci dev_consume_skb_irq(tx_buffer->skb); 125562306a36Sopenharmony_ci tx_buffer->skb = NULL; 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci if (++next_to_clean == tx_ring->count) 125962306a36Sopenharmony_ci next_to_clean = 0; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci atomic_set(&tx_ring->next_to_clean, next_to_clean); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci if (netif_queue_stopped(adapter->netdev) && 126562306a36Sopenharmony_ci netif_carrier_ok(adapter->netdev)) { 126662306a36Sopenharmony_ci netif_wake_queue(adapter->netdev); 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci return true; 127062306a36Sopenharmony_ci} 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci/** 127362306a36Sopenharmony_ci * atl1e_intr - Interrupt Handler 127462306a36Sopenharmony_ci * @irq: interrupt number 127562306a36Sopenharmony_ci * @data: pointer to a network interface device structure 127662306a36Sopenharmony_ci */ 127762306a36Sopenharmony_cistatic irqreturn_t atl1e_intr(int irq, void *data) 127862306a36Sopenharmony_ci{ 127962306a36Sopenharmony_ci struct net_device *netdev = data; 128062306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 128162306a36Sopenharmony_ci struct atl1e_hw *hw = &adapter->hw; 128262306a36Sopenharmony_ci int max_ints = AT_MAX_INT_WORK; 128362306a36Sopenharmony_ci int handled = IRQ_NONE; 128462306a36Sopenharmony_ci u32 status; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci do { 128762306a36Sopenharmony_ci status = AT_READ_REG(hw, REG_ISR); 128862306a36Sopenharmony_ci if ((status & IMR_NORMAL_MASK) == 0 || 128962306a36Sopenharmony_ci (status & ISR_DIS_INT) != 0) { 129062306a36Sopenharmony_ci if (max_ints != AT_MAX_INT_WORK) 129162306a36Sopenharmony_ci handled = IRQ_HANDLED; 129262306a36Sopenharmony_ci break; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci /* link event */ 129562306a36Sopenharmony_ci if (status & ISR_GPHY) 129662306a36Sopenharmony_ci atl1e_clear_phy_int(adapter); 129762306a36Sopenharmony_ci /* Ack ISR */ 129862306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_ISR, status | ISR_DIS_INT); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci handled = IRQ_HANDLED; 130162306a36Sopenharmony_ci /* check if PCIE PHY Link down */ 130262306a36Sopenharmony_ci if (status & ISR_PHY_LINKDOWN) { 130362306a36Sopenharmony_ci netdev_err(adapter->netdev, 130462306a36Sopenharmony_ci "pcie phy linkdown %x\n", status); 130562306a36Sopenharmony_ci if (netif_running(adapter->netdev)) { 130662306a36Sopenharmony_ci /* reset MAC */ 130762306a36Sopenharmony_ci atl1e_irq_reset(adapter); 130862306a36Sopenharmony_ci schedule_work(&adapter->reset_task); 130962306a36Sopenharmony_ci break; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci /* check if DMA read/write error */ 131462306a36Sopenharmony_ci if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) { 131562306a36Sopenharmony_ci netdev_err(adapter->netdev, 131662306a36Sopenharmony_ci "PCIE DMA RW error (status = 0x%x)\n", 131762306a36Sopenharmony_ci status); 131862306a36Sopenharmony_ci atl1e_irq_reset(adapter); 131962306a36Sopenharmony_ci schedule_work(&adapter->reset_task); 132062306a36Sopenharmony_ci break; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci if (status & ISR_SMB) 132462306a36Sopenharmony_ci atl1e_update_hw_stats(adapter); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci /* link event */ 132762306a36Sopenharmony_ci if (status & (ISR_GPHY | ISR_MANUAL)) { 132862306a36Sopenharmony_ci netdev->stats.tx_carrier_errors++; 132962306a36Sopenharmony_ci atl1e_link_chg_event(adapter); 133062306a36Sopenharmony_ci break; 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci /* transmit event */ 133462306a36Sopenharmony_ci if (status & ISR_TX_EVENT) 133562306a36Sopenharmony_ci atl1e_clean_tx_irq(adapter); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (status & ISR_RX_EVENT) { 133862306a36Sopenharmony_ci /* 133962306a36Sopenharmony_ci * disable rx interrupts, without 134062306a36Sopenharmony_ci * the synchronize_irq bit 134162306a36Sopenharmony_ci */ 134262306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_IMR, 134362306a36Sopenharmony_ci IMR_NORMAL_MASK & ~ISR_RX_EVENT); 134462306a36Sopenharmony_ci AT_WRITE_FLUSH(hw); 134562306a36Sopenharmony_ci if (likely(napi_schedule_prep( 134662306a36Sopenharmony_ci &adapter->napi))) 134762306a36Sopenharmony_ci __napi_schedule(&adapter->napi); 134862306a36Sopenharmony_ci } 134962306a36Sopenharmony_ci } while (--max_ints > 0); 135062306a36Sopenharmony_ci /* re-enable Interrupt*/ 135162306a36Sopenharmony_ci AT_WRITE_REG(&adapter->hw, REG_ISR, 0); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci return handled; 135462306a36Sopenharmony_ci} 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_cistatic inline void atl1e_rx_checksum(struct atl1e_adapter *adapter, 135762306a36Sopenharmony_ci struct sk_buff *skb, struct atl1e_recv_ret_status *prrs) 135862306a36Sopenharmony_ci{ 135962306a36Sopenharmony_ci u8 *packet = (u8 *)(prrs + 1); 136062306a36Sopenharmony_ci struct iphdr *iph; 136162306a36Sopenharmony_ci u16 head_len = ETH_HLEN; 136262306a36Sopenharmony_ci u16 pkt_flags; 136362306a36Sopenharmony_ci u16 err_flags; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci skb_checksum_none_assert(skb); 136662306a36Sopenharmony_ci pkt_flags = prrs->pkt_flag; 136762306a36Sopenharmony_ci err_flags = prrs->err_flag; 136862306a36Sopenharmony_ci if (((pkt_flags & RRS_IS_IPV4) || (pkt_flags & RRS_IS_IPV6)) && 136962306a36Sopenharmony_ci ((pkt_flags & RRS_IS_TCP) || (pkt_flags & RRS_IS_UDP))) { 137062306a36Sopenharmony_ci if (pkt_flags & RRS_IS_IPV4) { 137162306a36Sopenharmony_ci if (pkt_flags & RRS_IS_802_3) 137262306a36Sopenharmony_ci head_len += 8; 137362306a36Sopenharmony_ci iph = (struct iphdr *) (packet + head_len); 137462306a36Sopenharmony_ci if (iph->frag_off != 0 && !(pkt_flags & RRS_IS_IP_DF)) 137562306a36Sopenharmony_ci goto hw_xsum; 137662306a36Sopenharmony_ci } 137762306a36Sopenharmony_ci if (!(err_flags & (RRS_ERR_IP_CSUM | RRS_ERR_L4_CSUM))) { 137862306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 137962306a36Sopenharmony_ci return; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_cihw_xsum : 138462306a36Sopenharmony_ci return; 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_cistatic struct atl1e_rx_page *atl1e_get_rx_page(struct atl1e_adapter *adapter, 138862306a36Sopenharmony_ci u8 que) 138962306a36Sopenharmony_ci{ 139062306a36Sopenharmony_ci struct atl1e_rx_page_desc *rx_page_desc = 139162306a36Sopenharmony_ci (struct atl1e_rx_page_desc *) adapter->rx_ring.rx_page_desc; 139262306a36Sopenharmony_ci u8 rx_using = rx_page_desc[que].rx_using; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci return &(rx_page_desc[que].rx_page[rx_using]); 139562306a36Sopenharmony_ci} 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_cistatic void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que, 139862306a36Sopenharmony_ci int *work_done, int work_to_do) 139962306a36Sopenharmony_ci{ 140062306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 140162306a36Sopenharmony_ci struct atl1e_rx_ring *rx_ring = &adapter->rx_ring; 140262306a36Sopenharmony_ci struct atl1e_rx_page_desc *rx_page_desc = 140362306a36Sopenharmony_ci (struct atl1e_rx_page_desc *) rx_ring->rx_page_desc; 140462306a36Sopenharmony_ci struct sk_buff *skb = NULL; 140562306a36Sopenharmony_ci struct atl1e_rx_page *rx_page = atl1e_get_rx_page(adapter, que); 140662306a36Sopenharmony_ci u32 packet_size, write_offset; 140762306a36Sopenharmony_ci struct atl1e_recv_ret_status *prrs; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci write_offset = *(rx_page->write_offset_addr); 141062306a36Sopenharmony_ci if (likely(rx_page->read_offset < write_offset)) { 141162306a36Sopenharmony_ci do { 141262306a36Sopenharmony_ci if (*work_done >= work_to_do) 141362306a36Sopenharmony_ci break; 141462306a36Sopenharmony_ci (*work_done)++; 141562306a36Sopenharmony_ci /* get new packet's rrs */ 141662306a36Sopenharmony_ci prrs = (struct atl1e_recv_ret_status *) (rx_page->addr + 141762306a36Sopenharmony_ci rx_page->read_offset); 141862306a36Sopenharmony_ci /* check sequence number */ 141962306a36Sopenharmony_ci if (prrs->seq_num != rx_page_desc[que].rx_nxseq) { 142062306a36Sopenharmony_ci netdev_err(netdev, 142162306a36Sopenharmony_ci "rx sequence number error (rx=%d) (expect=%d)\n", 142262306a36Sopenharmony_ci prrs->seq_num, 142362306a36Sopenharmony_ci rx_page_desc[que].rx_nxseq); 142462306a36Sopenharmony_ci rx_page_desc[que].rx_nxseq++; 142562306a36Sopenharmony_ci /* just for debug use */ 142662306a36Sopenharmony_ci AT_WRITE_REG(&adapter->hw, REG_DEBUG_DATA0, 142762306a36Sopenharmony_ci (((u32)prrs->seq_num) << 16) | 142862306a36Sopenharmony_ci rx_page_desc[que].rx_nxseq); 142962306a36Sopenharmony_ci goto fatal_err; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci rx_page_desc[que].rx_nxseq++; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci /* error packet */ 143462306a36Sopenharmony_ci if ((prrs->pkt_flag & RRS_IS_ERR_FRAME) && 143562306a36Sopenharmony_ci !(netdev->features & NETIF_F_RXALL)) { 143662306a36Sopenharmony_ci if (prrs->err_flag & (RRS_ERR_BAD_CRC | 143762306a36Sopenharmony_ci RRS_ERR_DRIBBLE | RRS_ERR_CODE | 143862306a36Sopenharmony_ci RRS_ERR_TRUNC)) { 143962306a36Sopenharmony_ci /* hardware error, discard this packet*/ 144062306a36Sopenharmony_ci netdev_err(netdev, 144162306a36Sopenharmony_ci "rx packet desc error %x\n", 144262306a36Sopenharmony_ci *((u32 *)prrs + 1)); 144362306a36Sopenharmony_ci goto skip_pkt; 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci packet_size = ((prrs->word1 >> RRS_PKT_SIZE_SHIFT) & 144862306a36Sopenharmony_ci RRS_PKT_SIZE_MASK); 144962306a36Sopenharmony_ci if (likely(!(netdev->features & NETIF_F_RXFCS))) 145062306a36Sopenharmony_ci packet_size -= 4; /* CRC */ 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci skb = netdev_alloc_skb_ip_align(netdev, packet_size); 145362306a36Sopenharmony_ci if (skb == NULL) 145462306a36Sopenharmony_ci goto skip_pkt; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci memcpy(skb->data, (u8 *)(prrs + 1), packet_size); 145762306a36Sopenharmony_ci skb_put(skb, packet_size); 145862306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, netdev); 145962306a36Sopenharmony_ci atl1e_rx_checksum(adapter, skb, prrs); 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci if (prrs->pkt_flag & RRS_IS_VLAN_TAG) { 146262306a36Sopenharmony_ci u16 vlan_tag = (prrs->vtag >> 4) | 146362306a36Sopenharmony_ci ((prrs->vtag & 7) << 13) | 146462306a36Sopenharmony_ci ((prrs->vtag & 8) << 9); 146562306a36Sopenharmony_ci netdev_dbg(netdev, 146662306a36Sopenharmony_ci "RXD VLAN TAG<RRD>=0x%04x\n", 146762306a36Sopenharmony_ci prrs->vtag); 146862306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag); 146962306a36Sopenharmony_ci } 147062306a36Sopenharmony_ci napi_gro_receive(&adapter->napi, skb); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ciskip_pkt: 147362306a36Sopenharmony_ci /* skip current packet whether it's ok or not. */ 147462306a36Sopenharmony_ci rx_page->read_offset += 147562306a36Sopenharmony_ci (((u32)((prrs->word1 >> RRS_PKT_SIZE_SHIFT) & 147662306a36Sopenharmony_ci RRS_PKT_SIZE_MASK) + 147762306a36Sopenharmony_ci sizeof(struct atl1e_recv_ret_status) + 31) & 147862306a36Sopenharmony_ci 0xFFFFFFE0); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci if (rx_page->read_offset >= rx_ring->page_size) { 148162306a36Sopenharmony_ci /* mark this page clean */ 148262306a36Sopenharmony_ci u16 reg_addr; 148362306a36Sopenharmony_ci u8 rx_using; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci rx_page->read_offset = 148662306a36Sopenharmony_ci *(rx_page->write_offset_addr) = 0; 148762306a36Sopenharmony_ci rx_using = rx_page_desc[que].rx_using; 148862306a36Sopenharmony_ci reg_addr = 148962306a36Sopenharmony_ci atl1e_rx_page_vld_regs[que][rx_using]; 149062306a36Sopenharmony_ci AT_WRITE_REGB(&adapter->hw, reg_addr, 1); 149162306a36Sopenharmony_ci rx_page_desc[que].rx_using ^= 1; 149262306a36Sopenharmony_ci rx_page = atl1e_get_rx_page(adapter, que); 149362306a36Sopenharmony_ci } 149462306a36Sopenharmony_ci write_offset = *(rx_page->write_offset_addr); 149562306a36Sopenharmony_ci } while (rx_page->read_offset < write_offset); 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci return; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_cifatal_err: 150162306a36Sopenharmony_ci if (!test_bit(__AT_DOWN, &adapter->flags)) 150262306a36Sopenharmony_ci schedule_work(&adapter->reset_task); 150362306a36Sopenharmony_ci} 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci/** 150662306a36Sopenharmony_ci * atl1e_clean - NAPI Rx polling callback 150762306a36Sopenharmony_ci * @napi: napi info 150862306a36Sopenharmony_ci * @budget: number of packets to clean 150962306a36Sopenharmony_ci */ 151062306a36Sopenharmony_cistatic int atl1e_clean(struct napi_struct *napi, int budget) 151162306a36Sopenharmony_ci{ 151262306a36Sopenharmony_ci struct atl1e_adapter *adapter = 151362306a36Sopenharmony_ci container_of(napi, struct atl1e_adapter, napi); 151462306a36Sopenharmony_ci u32 imr_data; 151562306a36Sopenharmony_ci int work_done = 0; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci /* Keep link state information with original netdev */ 151862306a36Sopenharmony_ci if (!netif_carrier_ok(adapter->netdev)) 151962306a36Sopenharmony_ci goto quit_polling; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci atl1e_clean_rx_irq(adapter, 0, &work_done, budget); 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci /* If no Tx and not enough Rx work done, exit the polling mode */ 152462306a36Sopenharmony_ci if (work_done < budget) { 152562306a36Sopenharmony_ciquit_polling: 152662306a36Sopenharmony_ci napi_complete_done(napi, work_done); 152762306a36Sopenharmony_ci imr_data = AT_READ_REG(&adapter->hw, REG_IMR); 152862306a36Sopenharmony_ci AT_WRITE_REG(&adapter->hw, REG_IMR, imr_data | ISR_RX_EVENT); 152962306a36Sopenharmony_ci /* test debug */ 153062306a36Sopenharmony_ci if (test_bit(__AT_DOWN, &adapter->flags)) { 153162306a36Sopenharmony_ci atomic_dec(&adapter->irq_sem); 153262306a36Sopenharmony_ci netdev_err(adapter->netdev, 153362306a36Sopenharmony_ci "atl1e_clean is called when AT_DOWN\n"); 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci /* reenable RX intr */ 153662306a36Sopenharmony_ci /*atl1e_irq_enable(adapter); */ 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci return work_done; 154062306a36Sopenharmony_ci} 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci/* 154562306a36Sopenharmony_ci * Polling 'interrupt' - used by things like netconsole to send skbs 154662306a36Sopenharmony_ci * without having to re-enable interrupts. It's not called while 154762306a36Sopenharmony_ci * the interrupt routine is executing. 154862306a36Sopenharmony_ci */ 154962306a36Sopenharmony_cistatic void atl1e_netpoll(struct net_device *netdev) 155062306a36Sopenharmony_ci{ 155162306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci disable_irq(adapter->pdev->irq); 155462306a36Sopenharmony_ci atl1e_intr(adapter->pdev->irq, netdev); 155562306a36Sopenharmony_ci enable_irq(adapter->pdev->irq); 155662306a36Sopenharmony_ci} 155762306a36Sopenharmony_ci#endif 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_cistatic inline u16 atl1e_tpd_avail(struct atl1e_adapter *adapter) 156062306a36Sopenharmony_ci{ 156162306a36Sopenharmony_ci struct atl1e_tx_ring *tx_ring = &adapter->tx_ring; 156262306a36Sopenharmony_ci u16 next_to_use = 0; 156362306a36Sopenharmony_ci u16 next_to_clean = 0; 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci next_to_clean = atomic_read(&tx_ring->next_to_clean); 156662306a36Sopenharmony_ci next_to_use = tx_ring->next_to_use; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci return (u16)(next_to_clean > next_to_use) ? 156962306a36Sopenharmony_ci (next_to_clean - next_to_use - 1) : 157062306a36Sopenharmony_ci (tx_ring->count + next_to_clean - next_to_use - 1); 157162306a36Sopenharmony_ci} 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci/* 157462306a36Sopenharmony_ci * get next usable tpd 157562306a36Sopenharmony_ci * Note: should call atl1e_tdp_avail to make sure 157662306a36Sopenharmony_ci * there is enough tpd to use 157762306a36Sopenharmony_ci */ 157862306a36Sopenharmony_cistatic struct atl1e_tpd_desc *atl1e_get_tpd(struct atl1e_adapter *adapter) 157962306a36Sopenharmony_ci{ 158062306a36Sopenharmony_ci struct atl1e_tx_ring *tx_ring = &adapter->tx_ring; 158162306a36Sopenharmony_ci u16 next_to_use = 0; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci next_to_use = tx_ring->next_to_use; 158462306a36Sopenharmony_ci if (++tx_ring->next_to_use == tx_ring->count) 158562306a36Sopenharmony_ci tx_ring->next_to_use = 0; 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci memset(&tx_ring->desc[next_to_use], 0, sizeof(struct atl1e_tpd_desc)); 158862306a36Sopenharmony_ci return &tx_ring->desc[next_to_use]; 158962306a36Sopenharmony_ci} 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_cistatic struct atl1e_tx_buffer * 159262306a36Sopenharmony_ciatl1e_get_tx_buffer(struct atl1e_adapter *adapter, struct atl1e_tpd_desc *tpd) 159362306a36Sopenharmony_ci{ 159462306a36Sopenharmony_ci struct atl1e_tx_ring *tx_ring = &adapter->tx_ring; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci return &tx_ring->tx_buffer[tpd - tx_ring->desc]; 159762306a36Sopenharmony_ci} 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci/* Calculate the transmit packet descript needed*/ 160062306a36Sopenharmony_cistatic u16 atl1e_cal_tdp_req(const struct sk_buff *skb) 160162306a36Sopenharmony_ci{ 160262306a36Sopenharmony_ci int i = 0; 160362306a36Sopenharmony_ci u16 tpd_req = 1; 160462306a36Sopenharmony_ci u16 fg_size = 0; 160562306a36Sopenharmony_ci u16 proto_hdr_len = 0; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 160862306a36Sopenharmony_ci fg_size = skb_frag_size(&skb_shinfo(skb)->frags[i]); 160962306a36Sopenharmony_ci tpd_req += ((fg_size + MAX_TX_BUF_LEN - 1) >> MAX_TX_BUF_SHIFT); 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci if (skb_is_gso(skb)) { 161362306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP) || 161462306a36Sopenharmony_ci (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6)) { 161562306a36Sopenharmony_ci proto_hdr_len = skb_tcp_all_headers(skb); 161662306a36Sopenharmony_ci if (proto_hdr_len < skb_headlen(skb)) { 161762306a36Sopenharmony_ci tpd_req += ((skb_headlen(skb) - proto_hdr_len + 161862306a36Sopenharmony_ci MAX_TX_BUF_LEN - 1) >> 161962306a36Sopenharmony_ci MAX_TX_BUF_SHIFT); 162062306a36Sopenharmony_ci } 162162306a36Sopenharmony_ci } 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci } 162462306a36Sopenharmony_ci return tpd_req; 162562306a36Sopenharmony_ci} 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_cistatic int atl1e_tso_csum(struct atl1e_adapter *adapter, 162862306a36Sopenharmony_ci struct sk_buff *skb, struct atl1e_tpd_desc *tpd) 162962306a36Sopenharmony_ci{ 163062306a36Sopenharmony_ci unsigned short offload_type; 163162306a36Sopenharmony_ci u8 hdr_len; 163262306a36Sopenharmony_ci u32 real_len; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci if (skb_is_gso(skb)) { 163562306a36Sopenharmony_ci int err; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci err = skb_cow_head(skb, 0); 163862306a36Sopenharmony_ci if (err < 0) 163962306a36Sopenharmony_ci return err; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci offload_type = skb_shinfo(skb)->gso_type; 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci if (offload_type & SKB_GSO_TCPV4) { 164462306a36Sopenharmony_ci real_len = (((unsigned char *)ip_hdr(skb) - skb->data) 164562306a36Sopenharmony_ci + ntohs(ip_hdr(skb)->tot_len)); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci if (real_len < skb->len) { 164862306a36Sopenharmony_ci err = pskb_trim(skb, real_len); 164962306a36Sopenharmony_ci if (err) 165062306a36Sopenharmony_ci return err; 165162306a36Sopenharmony_ci } 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci hdr_len = skb_tcp_all_headers(skb); 165462306a36Sopenharmony_ci if (unlikely(skb->len == hdr_len)) { 165562306a36Sopenharmony_ci /* only xsum need */ 165662306a36Sopenharmony_ci netdev_warn(adapter->netdev, 165762306a36Sopenharmony_ci "IPV4 tso with zero data??\n"); 165862306a36Sopenharmony_ci goto check_sum; 165962306a36Sopenharmony_ci } else { 166062306a36Sopenharmony_ci ip_hdr(skb)->check = 0; 166162306a36Sopenharmony_ci ip_hdr(skb)->tot_len = 0; 166262306a36Sopenharmony_ci tcp_hdr(skb)->check = ~csum_tcpudp_magic( 166362306a36Sopenharmony_ci ip_hdr(skb)->saddr, 166462306a36Sopenharmony_ci ip_hdr(skb)->daddr, 166562306a36Sopenharmony_ci 0, IPPROTO_TCP, 0); 166662306a36Sopenharmony_ci tpd->word3 |= (ip_hdr(skb)->ihl & 166762306a36Sopenharmony_ci TDP_V4_IPHL_MASK) << 166862306a36Sopenharmony_ci TPD_V4_IPHL_SHIFT; 166962306a36Sopenharmony_ci tpd->word3 |= ((tcp_hdrlen(skb) >> 2) & 167062306a36Sopenharmony_ci TPD_TCPHDRLEN_MASK) << 167162306a36Sopenharmony_ci TPD_TCPHDRLEN_SHIFT; 167262306a36Sopenharmony_ci tpd->word3 |= ((skb_shinfo(skb)->gso_size) & 167362306a36Sopenharmony_ci TPD_MSS_MASK) << TPD_MSS_SHIFT; 167462306a36Sopenharmony_ci tpd->word3 |= 1 << TPD_SEGMENT_EN_SHIFT; 167562306a36Sopenharmony_ci } 167662306a36Sopenharmony_ci return 0; 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci } 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_cicheck_sum: 168162306a36Sopenharmony_ci if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { 168262306a36Sopenharmony_ci u8 css, cso; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci cso = skb_checksum_start_offset(skb); 168562306a36Sopenharmony_ci if (unlikely(cso & 0x1)) { 168662306a36Sopenharmony_ci netdev_err(adapter->netdev, 168762306a36Sopenharmony_ci "payload offset should not ant event number\n"); 168862306a36Sopenharmony_ci return -1; 168962306a36Sopenharmony_ci } else { 169062306a36Sopenharmony_ci css = cso + skb->csum_offset; 169162306a36Sopenharmony_ci tpd->word3 |= (cso & TPD_PLOADOFFSET_MASK) << 169262306a36Sopenharmony_ci TPD_PLOADOFFSET_SHIFT; 169362306a36Sopenharmony_ci tpd->word3 |= (css & TPD_CCSUMOFFSET_MASK) << 169462306a36Sopenharmony_ci TPD_CCSUMOFFSET_SHIFT; 169562306a36Sopenharmony_ci tpd->word3 |= 1 << TPD_CC_SEGMENT_EN_SHIFT; 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci } 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci return 0; 170062306a36Sopenharmony_ci} 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_cistatic int atl1e_tx_map(struct atl1e_adapter *adapter, 170362306a36Sopenharmony_ci struct sk_buff *skb, struct atl1e_tpd_desc *tpd) 170462306a36Sopenharmony_ci{ 170562306a36Sopenharmony_ci struct atl1e_tpd_desc *use_tpd = NULL; 170662306a36Sopenharmony_ci struct atl1e_tx_buffer *tx_buffer = NULL; 170762306a36Sopenharmony_ci u16 buf_len = skb_headlen(skb); 170862306a36Sopenharmony_ci u16 map_len = 0; 170962306a36Sopenharmony_ci u16 mapped_len = 0; 171062306a36Sopenharmony_ci u16 hdr_len = 0; 171162306a36Sopenharmony_ci u16 nr_frags; 171262306a36Sopenharmony_ci u16 f; 171362306a36Sopenharmony_ci int segment; 171462306a36Sopenharmony_ci int ring_start = adapter->tx_ring.next_to_use; 171562306a36Sopenharmony_ci int ring_end; 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 171862306a36Sopenharmony_ci segment = (tpd->word3 >> TPD_SEGMENT_EN_SHIFT) & TPD_SEGMENT_EN_MASK; 171962306a36Sopenharmony_ci if (segment) { 172062306a36Sopenharmony_ci /* TSO */ 172162306a36Sopenharmony_ci hdr_len = skb_tcp_all_headers(skb); 172262306a36Sopenharmony_ci map_len = hdr_len; 172362306a36Sopenharmony_ci use_tpd = tpd; 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci tx_buffer = atl1e_get_tx_buffer(adapter, use_tpd); 172662306a36Sopenharmony_ci tx_buffer->length = map_len; 172762306a36Sopenharmony_ci tx_buffer->dma = dma_map_single(&adapter->pdev->dev, 172862306a36Sopenharmony_ci skb->data, hdr_len, 172962306a36Sopenharmony_ci DMA_TO_DEVICE); 173062306a36Sopenharmony_ci if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) 173162306a36Sopenharmony_ci return -ENOSPC; 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci ATL1E_SET_PCIMAP_TYPE(tx_buffer, ATL1E_TX_PCIMAP_SINGLE); 173462306a36Sopenharmony_ci mapped_len += map_len; 173562306a36Sopenharmony_ci use_tpd->buffer_addr = cpu_to_le64(tx_buffer->dma); 173662306a36Sopenharmony_ci use_tpd->word2 = (use_tpd->word2 & (~TPD_BUFLEN_MASK)) | 173762306a36Sopenharmony_ci ((cpu_to_le32(tx_buffer->length) & 173862306a36Sopenharmony_ci TPD_BUFLEN_MASK) << TPD_BUFLEN_SHIFT); 173962306a36Sopenharmony_ci } 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci while (mapped_len < buf_len) { 174262306a36Sopenharmony_ci /* mapped_len == 0, means we should use the first tpd, 174362306a36Sopenharmony_ci which is given by caller */ 174462306a36Sopenharmony_ci if (mapped_len == 0) { 174562306a36Sopenharmony_ci use_tpd = tpd; 174662306a36Sopenharmony_ci } else { 174762306a36Sopenharmony_ci use_tpd = atl1e_get_tpd(adapter); 174862306a36Sopenharmony_ci memcpy(use_tpd, tpd, sizeof(struct atl1e_tpd_desc)); 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci tx_buffer = atl1e_get_tx_buffer(adapter, use_tpd); 175162306a36Sopenharmony_ci tx_buffer->skb = NULL; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci tx_buffer->length = map_len = 175462306a36Sopenharmony_ci ((buf_len - mapped_len) >= MAX_TX_BUF_LEN) ? 175562306a36Sopenharmony_ci MAX_TX_BUF_LEN : (buf_len - mapped_len); 175662306a36Sopenharmony_ci tx_buffer->dma = 175762306a36Sopenharmony_ci dma_map_single(&adapter->pdev->dev, 175862306a36Sopenharmony_ci skb->data + mapped_len, map_len, 175962306a36Sopenharmony_ci DMA_TO_DEVICE); 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) { 176262306a36Sopenharmony_ci /* We need to unwind the mappings we've done */ 176362306a36Sopenharmony_ci ring_end = adapter->tx_ring.next_to_use; 176462306a36Sopenharmony_ci adapter->tx_ring.next_to_use = ring_start; 176562306a36Sopenharmony_ci while (adapter->tx_ring.next_to_use != ring_end) { 176662306a36Sopenharmony_ci tpd = atl1e_get_tpd(adapter); 176762306a36Sopenharmony_ci tx_buffer = atl1e_get_tx_buffer(adapter, tpd); 176862306a36Sopenharmony_ci dma_unmap_single(&adapter->pdev->dev, 176962306a36Sopenharmony_ci tx_buffer->dma, 177062306a36Sopenharmony_ci tx_buffer->length, 177162306a36Sopenharmony_ci DMA_TO_DEVICE); 177262306a36Sopenharmony_ci } 177362306a36Sopenharmony_ci /* Reset the tx rings next pointer */ 177462306a36Sopenharmony_ci adapter->tx_ring.next_to_use = ring_start; 177562306a36Sopenharmony_ci return -ENOSPC; 177662306a36Sopenharmony_ci } 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci ATL1E_SET_PCIMAP_TYPE(tx_buffer, ATL1E_TX_PCIMAP_SINGLE); 177962306a36Sopenharmony_ci mapped_len += map_len; 178062306a36Sopenharmony_ci use_tpd->buffer_addr = cpu_to_le64(tx_buffer->dma); 178162306a36Sopenharmony_ci use_tpd->word2 = (use_tpd->word2 & (~TPD_BUFLEN_MASK)) | 178262306a36Sopenharmony_ci ((cpu_to_le32(tx_buffer->length) & 178362306a36Sopenharmony_ci TPD_BUFLEN_MASK) << TPD_BUFLEN_SHIFT); 178462306a36Sopenharmony_ci } 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci for (f = 0; f < nr_frags; f++) { 178762306a36Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; 178862306a36Sopenharmony_ci u16 i; 178962306a36Sopenharmony_ci u16 seg_num; 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci buf_len = skb_frag_size(frag); 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci seg_num = (buf_len + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; 179462306a36Sopenharmony_ci for (i = 0; i < seg_num; i++) { 179562306a36Sopenharmony_ci use_tpd = atl1e_get_tpd(adapter); 179662306a36Sopenharmony_ci memcpy(use_tpd, tpd, sizeof(struct atl1e_tpd_desc)); 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci tx_buffer = atl1e_get_tx_buffer(adapter, use_tpd); 179962306a36Sopenharmony_ci BUG_ON(tx_buffer->skb); 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci tx_buffer->skb = NULL; 180262306a36Sopenharmony_ci tx_buffer->length = 180362306a36Sopenharmony_ci (buf_len > MAX_TX_BUF_LEN) ? 180462306a36Sopenharmony_ci MAX_TX_BUF_LEN : buf_len; 180562306a36Sopenharmony_ci buf_len -= tx_buffer->length; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci tx_buffer->dma = skb_frag_dma_map(&adapter->pdev->dev, 180862306a36Sopenharmony_ci frag, 180962306a36Sopenharmony_ci (i * MAX_TX_BUF_LEN), 181062306a36Sopenharmony_ci tx_buffer->length, 181162306a36Sopenharmony_ci DMA_TO_DEVICE); 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) { 181462306a36Sopenharmony_ci /* We need to unwind the mappings we've done */ 181562306a36Sopenharmony_ci ring_end = adapter->tx_ring.next_to_use; 181662306a36Sopenharmony_ci adapter->tx_ring.next_to_use = ring_start; 181762306a36Sopenharmony_ci while (adapter->tx_ring.next_to_use != ring_end) { 181862306a36Sopenharmony_ci tpd = atl1e_get_tpd(adapter); 181962306a36Sopenharmony_ci tx_buffer = atl1e_get_tx_buffer(adapter, tpd); 182062306a36Sopenharmony_ci dma_unmap_page(&adapter->pdev->dev, tx_buffer->dma, 182162306a36Sopenharmony_ci tx_buffer->length, DMA_TO_DEVICE); 182262306a36Sopenharmony_ci } 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci /* Reset the ring next to use pointer */ 182562306a36Sopenharmony_ci adapter->tx_ring.next_to_use = ring_start; 182662306a36Sopenharmony_ci return -ENOSPC; 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci ATL1E_SET_PCIMAP_TYPE(tx_buffer, ATL1E_TX_PCIMAP_PAGE); 183062306a36Sopenharmony_ci use_tpd->buffer_addr = cpu_to_le64(tx_buffer->dma); 183162306a36Sopenharmony_ci use_tpd->word2 = (use_tpd->word2 & (~TPD_BUFLEN_MASK)) | 183262306a36Sopenharmony_ci ((cpu_to_le32(tx_buffer->length) & 183362306a36Sopenharmony_ci TPD_BUFLEN_MASK) << TPD_BUFLEN_SHIFT); 183462306a36Sopenharmony_ci } 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci if ((tpd->word3 >> TPD_SEGMENT_EN_SHIFT) & TPD_SEGMENT_EN_MASK) 183862306a36Sopenharmony_ci /* note this one is a tcp header */ 183962306a36Sopenharmony_ci tpd->word3 |= 1 << TPD_HDRFLAG_SHIFT; 184062306a36Sopenharmony_ci /* The last tpd */ 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci use_tpd->word3 |= 1 << TPD_EOP_SHIFT; 184362306a36Sopenharmony_ci /* The last buffer info contain the skb address, 184462306a36Sopenharmony_ci so it will be free after unmap */ 184562306a36Sopenharmony_ci tx_buffer->skb = skb; 184662306a36Sopenharmony_ci return 0; 184762306a36Sopenharmony_ci} 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_cistatic void atl1e_tx_queue(struct atl1e_adapter *adapter, u16 count, 185062306a36Sopenharmony_ci struct atl1e_tpd_desc *tpd) 185162306a36Sopenharmony_ci{ 185262306a36Sopenharmony_ci struct atl1e_tx_ring *tx_ring = &adapter->tx_ring; 185362306a36Sopenharmony_ci /* Force memory writes to complete before letting h/w 185462306a36Sopenharmony_ci * know there are new descriptors to fetch. (Only 185562306a36Sopenharmony_ci * applicable for weak-ordered memory model archs, 185662306a36Sopenharmony_ci * such as IA-64). */ 185762306a36Sopenharmony_ci wmb(); 185862306a36Sopenharmony_ci AT_WRITE_REG(&adapter->hw, REG_MB_TPD_PROD_IDX, tx_ring->next_to_use); 185962306a36Sopenharmony_ci} 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_cistatic netdev_tx_t atl1e_xmit_frame(struct sk_buff *skb, 186262306a36Sopenharmony_ci struct net_device *netdev) 186362306a36Sopenharmony_ci{ 186462306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 186562306a36Sopenharmony_ci u16 tpd_req = 1; 186662306a36Sopenharmony_ci struct atl1e_tpd_desc *tpd; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci if (test_bit(__AT_DOWN, &adapter->flags)) { 186962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 187062306a36Sopenharmony_ci return NETDEV_TX_OK; 187162306a36Sopenharmony_ci } 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci if (unlikely(skb->len <= 0)) { 187462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 187562306a36Sopenharmony_ci return NETDEV_TX_OK; 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci tpd_req = atl1e_cal_tdp_req(skb); 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci if (atl1e_tpd_avail(adapter) < tpd_req) { 188062306a36Sopenharmony_ci /* no enough descriptor, just stop queue */ 188162306a36Sopenharmony_ci netif_stop_queue(netdev); 188262306a36Sopenharmony_ci return NETDEV_TX_BUSY; 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci tpd = atl1e_get_tpd(adapter); 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 188862306a36Sopenharmony_ci u16 vlan_tag = skb_vlan_tag_get(skb); 188962306a36Sopenharmony_ci u16 atl1e_vlan_tag; 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci tpd->word3 |= 1 << TPD_INS_VL_TAG_SHIFT; 189262306a36Sopenharmony_ci AT_VLAN_TAG_TO_TPD_TAG(vlan_tag, atl1e_vlan_tag); 189362306a36Sopenharmony_ci tpd->word2 |= (atl1e_vlan_tag & TPD_VLANTAG_MASK) << 189462306a36Sopenharmony_ci TPD_VLAN_SHIFT; 189562306a36Sopenharmony_ci } 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_8021Q)) 189862306a36Sopenharmony_ci tpd->word3 |= 1 << TPD_VL_TAGGED_SHIFT; 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci if (skb_network_offset(skb) != ETH_HLEN) 190162306a36Sopenharmony_ci tpd->word3 |= 1 << TPD_ETHTYPE_SHIFT; /* 802.3 frame */ 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci /* do TSO and check sum */ 190462306a36Sopenharmony_ci if (atl1e_tso_csum(adapter, skb, tpd) != 0) { 190562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 190662306a36Sopenharmony_ci return NETDEV_TX_OK; 190762306a36Sopenharmony_ci } 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci if (atl1e_tx_map(adapter, skb, tpd)) { 191062306a36Sopenharmony_ci dev_kfree_skb_any(skb); 191162306a36Sopenharmony_ci goto out; 191262306a36Sopenharmony_ci } 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci atl1e_tx_queue(adapter, tpd_req, tpd); 191562306a36Sopenharmony_ciout: 191662306a36Sopenharmony_ci return NETDEV_TX_OK; 191762306a36Sopenharmony_ci} 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_cistatic void atl1e_free_irq(struct atl1e_adapter *adapter) 192062306a36Sopenharmony_ci{ 192162306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci free_irq(adapter->pdev->irq, netdev); 192462306a36Sopenharmony_ci} 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_cistatic int atl1e_request_irq(struct atl1e_adapter *adapter) 192762306a36Sopenharmony_ci{ 192862306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 192962306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 193062306a36Sopenharmony_ci int err = 0; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci err = request_irq(pdev->irq, atl1e_intr, IRQF_SHARED, netdev->name, 193362306a36Sopenharmony_ci netdev); 193462306a36Sopenharmony_ci if (err) { 193562306a36Sopenharmony_ci netdev_dbg(adapter->netdev, 193662306a36Sopenharmony_ci "Unable to allocate interrupt Error: %d\n", err); 193762306a36Sopenharmony_ci return err; 193862306a36Sopenharmony_ci } 193962306a36Sopenharmony_ci netdev_dbg(netdev, "atl1e_request_irq OK\n"); 194062306a36Sopenharmony_ci return err; 194162306a36Sopenharmony_ci} 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ciint atl1e_up(struct atl1e_adapter *adapter) 194462306a36Sopenharmony_ci{ 194562306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 194662306a36Sopenharmony_ci int err = 0; 194762306a36Sopenharmony_ci u32 val; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci /* hardware has been reset, we need to reload some things */ 195062306a36Sopenharmony_ci err = atl1e_init_hw(&adapter->hw); 195162306a36Sopenharmony_ci if (err) { 195262306a36Sopenharmony_ci err = -EIO; 195362306a36Sopenharmony_ci return err; 195462306a36Sopenharmony_ci } 195562306a36Sopenharmony_ci atl1e_init_ring_ptrs(adapter); 195662306a36Sopenharmony_ci atl1e_set_multi(netdev); 195762306a36Sopenharmony_ci atl1e_restore_vlan(adapter); 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci if (atl1e_configure(adapter)) { 196062306a36Sopenharmony_ci err = -EIO; 196162306a36Sopenharmony_ci goto err_up; 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci clear_bit(__AT_DOWN, &adapter->flags); 196562306a36Sopenharmony_ci napi_enable(&adapter->napi); 196662306a36Sopenharmony_ci atl1e_irq_enable(adapter); 196762306a36Sopenharmony_ci val = AT_READ_REG(&adapter->hw, REG_MASTER_CTRL); 196862306a36Sopenharmony_ci AT_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, 196962306a36Sopenharmony_ci val | MASTER_CTRL_MANUAL_INT); 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_cierr_up: 197262306a36Sopenharmony_ci return err; 197362306a36Sopenharmony_ci} 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_civoid atl1e_down(struct atl1e_adapter *adapter) 197662306a36Sopenharmony_ci{ 197762306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci /* signal that we're down so the interrupt handler does not 198062306a36Sopenharmony_ci * reschedule our watchdog timer */ 198162306a36Sopenharmony_ci set_bit(__AT_DOWN, &adapter->flags); 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci netif_stop_queue(netdev); 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci /* reset MAC to disable all RX/TX */ 198662306a36Sopenharmony_ci atl1e_reset_hw(&adapter->hw); 198762306a36Sopenharmony_ci msleep(1); 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci napi_disable(&adapter->napi); 199062306a36Sopenharmony_ci atl1e_del_timer(adapter); 199162306a36Sopenharmony_ci atl1e_irq_disable(adapter); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci netif_carrier_off(netdev); 199462306a36Sopenharmony_ci adapter->link_speed = SPEED_0; 199562306a36Sopenharmony_ci adapter->link_duplex = -1; 199662306a36Sopenharmony_ci atl1e_clean_tx_ring(adapter); 199762306a36Sopenharmony_ci atl1e_clean_rx_ring(adapter); 199862306a36Sopenharmony_ci} 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci/** 200162306a36Sopenharmony_ci * atl1e_open - Called when a network interface is made active 200262306a36Sopenharmony_ci * @netdev: network interface device structure 200362306a36Sopenharmony_ci * 200462306a36Sopenharmony_ci * Returns 0 on success, negative value on failure 200562306a36Sopenharmony_ci * 200662306a36Sopenharmony_ci * The open entry point is called when a network interface is made 200762306a36Sopenharmony_ci * active by the system (IFF_UP). At this point all resources needed 200862306a36Sopenharmony_ci * for transmit and receive operations are allocated, the interrupt 200962306a36Sopenharmony_ci * handler is registered with the OS, the watchdog timer is started, 201062306a36Sopenharmony_ci * and the stack is notified that the interface is ready. 201162306a36Sopenharmony_ci */ 201262306a36Sopenharmony_cistatic int atl1e_open(struct net_device *netdev) 201362306a36Sopenharmony_ci{ 201462306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 201562306a36Sopenharmony_ci int err; 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci /* disallow open during test */ 201862306a36Sopenharmony_ci if (test_bit(__AT_TESTING, &adapter->flags)) 201962306a36Sopenharmony_ci return -EBUSY; 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci /* allocate rx/tx dma buffer & descriptors */ 202262306a36Sopenharmony_ci atl1e_init_ring_resources(adapter); 202362306a36Sopenharmony_ci err = atl1e_setup_ring_resources(adapter); 202462306a36Sopenharmony_ci if (unlikely(err)) 202562306a36Sopenharmony_ci return err; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci err = atl1e_request_irq(adapter); 202862306a36Sopenharmony_ci if (unlikely(err)) 202962306a36Sopenharmony_ci goto err_req_irq; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci err = atl1e_up(adapter); 203262306a36Sopenharmony_ci if (unlikely(err)) 203362306a36Sopenharmony_ci goto err_up; 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci return 0; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_cierr_up: 203862306a36Sopenharmony_ci atl1e_free_irq(adapter); 203962306a36Sopenharmony_cierr_req_irq: 204062306a36Sopenharmony_ci atl1e_free_ring_resources(adapter); 204162306a36Sopenharmony_ci atl1e_reset_hw(&adapter->hw); 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci return err; 204462306a36Sopenharmony_ci} 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci/** 204762306a36Sopenharmony_ci * atl1e_close - Disables a network interface 204862306a36Sopenharmony_ci * @netdev: network interface device structure 204962306a36Sopenharmony_ci * 205062306a36Sopenharmony_ci * Returns 0, this is not allowed to fail 205162306a36Sopenharmony_ci * 205262306a36Sopenharmony_ci * The close entry point is called when an interface is de-activated 205362306a36Sopenharmony_ci * by the OS. The hardware is still under the drivers control, but 205462306a36Sopenharmony_ci * needs to be disabled. A global MAC reset is issued to stop the 205562306a36Sopenharmony_ci * hardware, and all transmit and receive resources are freed. 205662306a36Sopenharmony_ci */ 205762306a36Sopenharmony_cistatic int atl1e_close(struct net_device *netdev) 205862306a36Sopenharmony_ci{ 205962306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci WARN_ON(test_bit(__AT_RESETTING, &adapter->flags)); 206262306a36Sopenharmony_ci atl1e_down(adapter); 206362306a36Sopenharmony_ci atl1e_free_irq(adapter); 206462306a36Sopenharmony_ci atl1e_free_ring_resources(adapter); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci return 0; 206762306a36Sopenharmony_ci} 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_cistatic int atl1e_suspend(struct pci_dev *pdev, pm_message_t state) 207062306a36Sopenharmony_ci{ 207162306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 207262306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 207362306a36Sopenharmony_ci struct atl1e_hw *hw = &adapter->hw; 207462306a36Sopenharmony_ci u32 ctrl = 0; 207562306a36Sopenharmony_ci u32 mac_ctrl_data = 0; 207662306a36Sopenharmony_ci u32 wol_ctrl_data = 0; 207762306a36Sopenharmony_ci u16 mii_advertise_data = 0; 207862306a36Sopenharmony_ci u16 mii_bmsr_data = 0; 207962306a36Sopenharmony_ci u16 mii_intr_status_data = 0; 208062306a36Sopenharmony_ci u32 wufc = adapter->wol; 208162306a36Sopenharmony_ci u32 i; 208262306a36Sopenharmony_ci#ifdef CONFIG_PM 208362306a36Sopenharmony_ci int retval = 0; 208462306a36Sopenharmony_ci#endif 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci if (netif_running(netdev)) { 208762306a36Sopenharmony_ci WARN_ON(test_bit(__AT_RESETTING, &adapter->flags)); 208862306a36Sopenharmony_ci atl1e_down(adapter); 208962306a36Sopenharmony_ci } 209062306a36Sopenharmony_ci netif_device_detach(netdev); 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci#ifdef CONFIG_PM 209362306a36Sopenharmony_ci retval = pci_save_state(pdev); 209462306a36Sopenharmony_ci if (retval) 209562306a36Sopenharmony_ci return retval; 209662306a36Sopenharmony_ci#endif 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci if (wufc) { 209962306a36Sopenharmony_ci /* get link status */ 210062306a36Sopenharmony_ci atl1e_read_phy_reg(hw, MII_BMSR, &mii_bmsr_data); 210162306a36Sopenharmony_ci atl1e_read_phy_reg(hw, MII_BMSR, &mii_bmsr_data); 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci mii_advertise_data = ADVERTISE_10HALF; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci if ((atl1e_write_phy_reg(hw, MII_CTRL1000, 0) != 0) || 210662306a36Sopenharmony_ci (atl1e_write_phy_reg(hw, 210762306a36Sopenharmony_ci MII_ADVERTISE, mii_advertise_data) != 0) || 210862306a36Sopenharmony_ci (atl1e_phy_commit(hw)) != 0) { 210962306a36Sopenharmony_ci netdev_dbg(adapter->netdev, "set phy register failed\n"); 211062306a36Sopenharmony_ci goto wol_dis; 211162306a36Sopenharmony_ci } 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci hw->phy_configured = false; /* re-init PHY when resume */ 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci /* turn on magic packet wol */ 211662306a36Sopenharmony_ci if (wufc & AT_WUFC_MAG) 211762306a36Sopenharmony_ci wol_ctrl_data |= WOL_MAGIC_EN | WOL_MAGIC_PME_EN; 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci if (wufc & AT_WUFC_LNKC) { 212062306a36Sopenharmony_ci /* if orignal link status is link, just wait for retrive link */ 212162306a36Sopenharmony_ci if (mii_bmsr_data & BMSR_LSTATUS) { 212262306a36Sopenharmony_ci for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) { 212362306a36Sopenharmony_ci msleep(100); 212462306a36Sopenharmony_ci atl1e_read_phy_reg(hw, MII_BMSR, 212562306a36Sopenharmony_ci &mii_bmsr_data); 212662306a36Sopenharmony_ci if (mii_bmsr_data & BMSR_LSTATUS) 212762306a36Sopenharmony_ci break; 212862306a36Sopenharmony_ci } 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci if ((mii_bmsr_data & BMSR_LSTATUS) == 0) 213162306a36Sopenharmony_ci netdev_dbg(adapter->netdev, 213262306a36Sopenharmony_ci "Link may change when suspend\n"); 213362306a36Sopenharmony_ci } 213462306a36Sopenharmony_ci wol_ctrl_data |= WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN; 213562306a36Sopenharmony_ci /* only link up can wake up */ 213662306a36Sopenharmony_ci if (atl1e_write_phy_reg(hw, MII_INT_CTRL, 0x400) != 0) { 213762306a36Sopenharmony_ci netdev_dbg(adapter->netdev, 213862306a36Sopenharmony_ci "read write phy register failed\n"); 213962306a36Sopenharmony_ci goto wol_dis; 214062306a36Sopenharmony_ci } 214162306a36Sopenharmony_ci } 214262306a36Sopenharmony_ci /* clear phy interrupt */ 214362306a36Sopenharmony_ci atl1e_read_phy_reg(hw, MII_INT_STATUS, &mii_intr_status_data); 214462306a36Sopenharmony_ci /* Config MAC Ctrl register */ 214562306a36Sopenharmony_ci mac_ctrl_data = MAC_CTRL_RX_EN; 214662306a36Sopenharmony_ci /* set to 10/100M halt duplex */ 214762306a36Sopenharmony_ci mac_ctrl_data |= MAC_CTRL_SPEED_10_100 << MAC_CTRL_SPEED_SHIFT; 214862306a36Sopenharmony_ci mac_ctrl_data |= (((u32)adapter->hw.preamble_len & 214962306a36Sopenharmony_ci MAC_CTRL_PRMLEN_MASK) << 215062306a36Sopenharmony_ci MAC_CTRL_PRMLEN_SHIFT); 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci __atl1e_vlan_mode(netdev->features, &mac_ctrl_data); 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci /* magic packet maybe Broadcast&multicast&Unicast frame */ 215562306a36Sopenharmony_ci if (wufc & AT_WUFC_MAG) 215662306a36Sopenharmony_ci mac_ctrl_data |= MAC_CTRL_BC_EN; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci netdev_dbg(adapter->netdev, "suspend MAC=0x%x\n", 215962306a36Sopenharmony_ci mac_ctrl_data); 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data); 216262306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data); 216362306a36Sopenharmony_ci /* pcie patch */ 216462306a36Sopenharmony_ci ctrl = AT_READ_REG(hw, REG_PCIE_PHYMISC); 216562306a36Sopenharmony_ci ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; 216662306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); 216762306a36Sopenharmony_ci pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); 216862306a36Sopenharmony_ci goto suspend_exit; 216962306a36Sopenharmony_ci } 217062306a36Sopenharmony_ciwol_dis: 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci /* WOL disabled */ 217362306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_WOL_CTRL, 0); 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci /* pcie patch */ 217662306a36Sopenharmony_ci ctrl = AT_READ_REG(hw, REG_PCIE_PHYMISC); 217762306a36Sopenharmony_ci ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; 217862306a36Sopenharmony_ci AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci atl1e_force_ps(hw); 218162306a36Sopenharmony_ci hw->phy_configured = false; /* re-init PHY when resume */ 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_cisuspend_exit: 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci if (netif_running(netdev)) 218862306a36Sopenharmony_ci atl1e_free_irq(adapter); 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci pci_disable_device(pdev); 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci pci_set_power_state(pdev, pci_choose_state(pdev, state)); 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci return 0; 219562306a36Sopenharmony_ci} 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci#ifdef CONFIG_PM 219862306a36Sopenharmony_cistatic int atl1e_resume(struct pci_dev *pdev) 219962306a36Sopenharmony_ci{ 220062306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 220162306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 220262306a36Sopenharmony_ci u32 err; 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci pci_set_power_state(pdev, PCI_D0); 220562306a36Sopenharmony_ci pci_restore_state(pdev); 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci err = pci_enable_device(pdev); 220862306a36Sopenharmony_ci if (err) { 220962306a36Sopenharmony_ci netdev_err(adapter->netdev, 221062306a36Sopenharmony_ci "Cannot enable PCI device from suspend\n"); 221162306a36Sopenharmony_ci return err; 221262306a36Sopenharmony_ci } 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci pci_set_master(pdev); 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci AT_READ_REG(&adapter->hw, REG_WOL_CTRL); /* clear WOL status */ 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci pci_enable_wake(pdev, PCI_D3hot, 0); 221962306a36Sopenharmony_ci pci_enable_wake(pdev, PCI_D3cold, 0); 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0); 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci if (netif_running(netdev)) { 222462306a36Sopenharmony_ci err = atl1e_request_irq(adapter); 222562306a36Sopenharmony_ci if (err) 222662306a36Sopenharmony_ci return err; 222762306a36Sopenharmony_ci } 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci atl1e_reset_hw(&adapter->hw); 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci if (netif_running(netdev)) 223262306a36Sopenharmony_ci atl1e_up(adapter); 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci netif_device_attach(netdev); 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci return 0; 223762306a36Sopenharmony_ci} 223862306a36Sopenharmony_ci#endif 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_cistatic void atl1e_shutdown(struct pci_dev *pdev) 224162306a36Sopenharmony_ci{ 224262306a36Sopenharmony_ci atl1e_suspend(pdev, PMSG_SUSPEND); 224362306a36Sopenharmony_ci} 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_cistatic const struct net_device_ops atl1e_netdev_ops = { 224662306a36Sopenharmony_ci .ndo_open = atl1e_open, 224762306a36Sopenharmony_ci .ndo_stop = atl1e_close, 224862306a36Sopenharmony_ci .ndo_start_xmit = atl1e_xmit_frame, 224962306a36Sopenharmony_ci .ndo_get_stats = atl1e_get_stats, 225062306a36Sopenharmony_ci .ndo_set_rx_mode = atl1e_set_multi, 225162306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 225262306a36Sopenharmony_ci .ndo_set_mac_address = atl1e_set_mac_addr, 225362306a36Sopenharmony_ci .ndo_fix_features = atl1e_fix_features, 225462306a36Sopenharmony_ci .ndo_set_features = atl1e_set_features, 225562306a36Sopenharmony_ci .ndo_change_mtu = atl1e_change_mtu, 225662306a36Sopenharmony_ci .ndo_eth_ioctl = atl1e_ioctl, 225762306a36Sopenharmony_ci .ndo_tx_timeout = atl1e_tx_timeout, 225862306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 225962306a36Sopenharmony_ci .ndo_poll_controller = atl1e_netpoll, 226062306a36Sopenharmony_ci#endif 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci}; 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_cistatic int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev) 226562306a36Sopenharmony_ci{ 226662306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 226762306a36Sopenharmony_ci pci_set_drvdata(pdev, netdev); 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci netdev->netdev_ops = &atl1e_netdev_ops; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci netdev->watchdog_timeo = AT_TX_WATCHDOG; 227262306a36Sopenharmony_ci /* MTU range: 42 - 8170 */ 227362306a36Sopenharmony_ci netdev->min_mtu = ETH_ZLEN - (ETH_HLEN + VLAN_HLEN); 227462306a36Sopenharmony_ci netdev->max_mtu = MAX_JUMBO_FRAME_SIZE - 227562306a36Sopenharmony_ci (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN); 227662306a36Sopenharmony_ci atl1e_set_ethtool_ops(netdev); 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO | 227962306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX; 228062306a36Sopenharmony_ci netdev->features = netdev->hw_features | NETIF_F_HW_VLAN_CTAG_TX; 228162306a36Sopenharmony_ci /* not enabled by default */ 228262306a36Sopenharmony_ci netdev->hw_features |= NETIF_F_RXALL | NETIF_F_RXFCS; 228362306a36Sopenharmony_ci return 0; 228462306a36Sopenharmony_ci} 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci/** 228762306a36Sopenharmony_ci * atl1e_probe - Device Initialization Routine 228862306a36Sopenharmony_ci * @pdev: PCI device information struct 228962306a36Sopenharmony_ci * @ent: entry in atl1e_pci_tbl 229062306a36Sopenharmony_ci * 229162306a36Sopenharmony_ci * Returns 0 on success, negative on failure 229262306a36Sopenharmony_ci * 229362306a36Sopenharmony_ci * atl1e_probe initializes an adapter identified by a pci_dev structure. 229462306a36Sopenharmony_ci * The OS initialization, configuring of the adapter private structure, 229562306a36Sopenharmony_ci * and a hardware reset occur. 229662306a36Sopenharmony_ci */ 229762306a36Sopenharmony_cistatic int atl1e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 229862306a36Sopenharmony_ci{ 229962306a36Sopenharmony_ci struct net_device *netdev; 230062306a36Sopenharmony_ci struct atl1e_adapter *adapter = NULL; 230162306a36Sopenharmony_ci static int cards_found; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci int err = 0; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci err = pci_enable_device(pdev); 230662306a36Sopenharmony_ci if (err) 230762306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, err, "cannot enable PCI device\n"); 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci /* 231062306a36Sopenharmony_ci * The atl1e chip can DMA to 64-bit addresses, but it uses a single 231162306a36Sopenharmony_ci * shared register for the high 32 bits, so only a single, aligned, 231262306a36Sopenharmony_ci * 4 GB physical address range can be used at a time. 231362306a36Sopenharmony_ci * 231462306a36Sopenharmony_ci * Supporting 64-bit DMA on this hardware is more trouble than it's 231562306a36Sopenharmony_ci * worth. It is far easier to limit to 32-bit DMA than update 231662306a36Sopenharmony_ci * various kernel subsystems to support the mechanics required by a 231762306a36Sopenharmony_ci * fixed-high-32-bit system. 231862306a36Sopenharmony_ci */ 231962306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 232062306a36Sopenharmony_ci if (err) { 232162306a36Sopenharmony_ci dev_err(&pdev->dev, "No usable DMA configuration,aborting\n"); 232262306a36Sopenharmony_ci goto err_dma; 232362306a36Sopenharmony_ci } 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci err = pci_request_regions(pdev, atl1e_driver_name); 232662306a36Sopenharmony_ci if (err) { 232762306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot obtain PCI resources\n"); 232862306a36Sopenharmony_ci goto err_pci_reg; 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci pci_set_master(pdev); 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_ci netdev = alloc_etherdev(sizeof(struct atl1e_adapter)); 233462306a36Sopenharmony_ci if (netdev == NULL) { 233562306a36Sopenharmony_ci err = -ENOMEM; 233662306a36Sopenharmony_ci goto err_alloc_etherdev; 233762306a36Sopenharmony_ci } 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci err = atl1e_init_netdev(netdev, pdev); 234062306a36Sopenharmony_ci if (err) { 234162306a36Sopenharmony_ci netdev_err(netdev, "init netdevice failed\n"); 234262306a36Sopenharmony_ci goto err_init_netdev; 234362306a36Sopenharmony_ci } 234462306a36Sopenharmony_ci adapter = netdev_priv(netdev); 234562306a36Sopenharmony_ci adapter->bd_number = cards_found; 234662306a36Sopenharmony_ci adapter->netdev = netdev; 234762306a36Sopenharmony_ci adapter->pdev = pdev; 234862306a36Sopenharmony_ci adapter->hw.adapter = adapter; 234962306a36Sopenharmony_ci adapter->hw.hw_addr = pci_iomap(pdev, BAR_0, 0); 235062306a36Sopenharmony_ci if (!adapter->hw.hw_addr) { 235162306a36Sopenharmony_ci err = -EIO; 235262306a36Sopenharmony_ci netdev_err(netdev, "cannot map device registers\n"); 235362306a36Sopenharmony_ci goto err_ioremap; 235462306a36Sopenharmony_ci } 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci /* init mii data */ 235762306a36Sopenharmony_ci adapter->mii.dev = netdev; 235862306a36Sopenharmony_ci adapter->mii.mdio_read = atl1e_mdio_read; 235962306a36Sopenharmony_ci adapter->mii.mdio_write = atl1e_mdio_write; 236062306a36Sopenharmony_ci adapter->mii.phy_id_mask = 0x1f; 236162306a36Sopenharmony_ci adapter->mii.reg_num_mask = MDIO_REG_ADDR_MASK; 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci netif_napi_add(netdev, &adapter->napi, atl1e_clean); 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci timer_setup(&adapter->phy_config_timer, atl1e_phy_config, 0); 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci /* get user settings */ 236862306a36Sopenharmony_ci atl1e_check_options(adapter); 236962306a36Sopenharmony_ci /* 237062306a36Sopenharmony_ci * Mark all PCI regions associated with PCI device 237162306a36Sopenharmony_ci * pdev as being reserved by owner atl1e_driver_name 237262306a36Sopenharmony_ci * Enables bus-mastering on the device and calls 237362306a36Sopenharmony_ci * pcibios_set_master to do the needed arch specific settings 237462306a36Sopenharmony_ci */ 237562306a36Sopenharmony_ci atl1e_setup_pcicmd(pdev); 237662306a36Sopenharmony_ci /* setup the private structure */ 237762306a36Sopenharmony_ci err = atl1e_sw_init(adapter); 237862306a36Sopenharmony_ci if (err) { 237962306a36Sopenharmony_ci netdev_err(netdev, "net device private data init failed\n"); 238062306a36Sopenharmony_ci goto err_sw_init; 238162306a36Sopenharmony_ci } 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_ci /* Init GPHY as early as possible due to power saving issue */ 238462306a36Sopenharmony_ci atl1e_phy_init(&adapter->hw); 238562306a36Sopenharmony_ci /* reset the controller to 238662306a36Sopenharmony_ci * put the device in a known good starting state */ 238762306a36Sopenharmony_ci err = atl1e_reset_hw(&adapter->hw); 238862306a36Sopenharmony_ci if (err) { 238962306a36Sopenharmony_ci err = -EIO; 239062306a36Sopenharmony_ci goto err_reset; 239162306a36Sopenharmony_ci } 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci if (atl1e_read_mac_addr(&adapter->hw) != 0) { 239462306a36Sopenharmony_ci err = -EIO; 239562306a36Sopenharmony_ci netdev_err(netdev, "get mac address failed\n"); 239662306a36Sopenharmony_ci goto err_eeprom; 239762306a36Sopenharmony_ci } 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci eth_hw_addr_set(netdev, adapter->hw.mac_addr); 240062306a36Sopenharmony_ci netdev_dbg(netdev, "mac address : %pM\n", adapter->hw.mac_addr); 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci INIT_WORK(&adapter->reset_task, atl1e_reset_task); 240362306a36Sopenharmony_ci INIT_WORK(&adapter->link_chg_task, atl1e_link_chg_task); 240462306a36Sopenharmony_ci netif_set_tso_max_size(netdev, MAX_TSO_SEG_SIZE); 240562306a36Sopenharmony_ci err = register_netdev(netdev); 240662306a36Sopenharmony_ci if (err) { 240762306a36Sopenharmony_ci netdev_err(netdev, "register netdevice failed\n"); 240862306a36Sopenharmony_ci goto err_register; 240962306a36Sopenharmony_ci } 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci /* assume we have no link for now */ 241262306a36Sopenharmony_ci netif_stop_queue(netdev); 241362306a36Sopenharmony_ci netif_carrier_off(netdev); 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci cards_found++; 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci return 0; 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_cierr_reset: 242062306a36Sopenharmony_cierr_register: 242162306a36Sopenharmony_cierr_sw_init: 242262306a36Sopenharmony_cierr_eeprom: 242362306a36Sopenharmony_ci pci_iounmap(pdev, adapter->hw.hw_addr); 242462306a36Sopenharmony_cierr_init_netdev: 242562306a36Sopenharmony_cierr_ioremap: 242662306a36Sopenharmony_ci free_netdev(netdev); 242762306a36Sopenharmony_cierr_alloc_etherdev: 242862306a36Sopenharmony_ci pci_release_regions(pdev); 242962306a36Sopenharmony_cierr_pci_reg: 243062306a36Sopenharmony_cierr_dma: 243162306a36Sopenharmony_ci pci_disable_device(pdev); 243262306a36Sopenharmony_ci return err; 243362306a36Sopenharmony_ci} 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_ci/** 243662306a36Sopenharmony_ci * atl1e_remove - Device Removal Routine 243762306a36Sopenharmony_ci * @pdev: PCI device information struct 243862306a36Sopenharmony_ci * 243962306a36Sopenharmony_ci * atl1e_remove is called by the PCI subsystem to alert the driver 244062306a36Sopenharmony_ci * that it should release a PCI device. The could be caused by a 244162306a36Sopenharmony_ci * Hot-Plug event, or because the driver is going to be removed from 244262306a36Sopenharmony_ci * memory. 244362306a36Sopenharmony_ci */ 244462306a36Sopenharmony_cistatic void atl1e_remove(struct pci_dev *pdev) 244562306a36Sopenharmony_ci{ 244662306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 244762306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_ci /* 245062306a36Sopenharmony_ci * flush_scheduled work may reschedule our watchdog task, so 245162306a36Sopenharmony_ci * explicitly disable watchdog tasks from being rescheduled 245262306a36Sopenharmony_ci */ 245362306a36Sopenharmony_ci set_bit(__AT_DOWN, &adapter->flags); 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci atl1e_del_timer(adapter); 245662306a36Sopenharmony_ci atl1e_cancel_work(adapter); 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci unregister_netdev(netdev); 245962306a36Sopenharmony_ci atl1e_free_ring_resources(adapter); 246062306a36Sopenharmony_ci atl1e_force_ps(&adapter->hw); 246162306a36Sopenharmony_ci pci_iounmap(pdev, adapter->hw.hw_addr); 246262306a36Sopenharmony_ci pci_release_regions(pdev); 246362306a36Sopenharmony_ci free_netdev(netdev); 246462306a36Sopenharmony_ci pci_disable_device(pdev); 246562306a36Sopenharmony_ci} 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ci/** 246862306a36Sopenharmony_ci * atl1e_io_error_detected - called when PCI error is detected 246962306a36Sopenharmony_ci * @pdev: Pointer to PCI device 247062306a36Sopenharmony_ci * @state: The current pci connection state 247162306a36Sopenharmony_ci * 247262306a36Sopenharmony_ci * This function is called after a PCI bus error affecting 247362306a36Sopenharmony_ci * this device has been detected. 247462306a36Sopenharmony_ci */ 247562306a36Sopenharmony_cistatic pci_ers_result_t 247662306a36Sopenharmony_ciatl1e_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) 247762306a36Sopenharmony_ci{ 247862306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 247962306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci netif_device_detach(netdev); 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci if (state == pci_channel_io_perm_failure) 248462306a36Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci if (netif_running(netdev)) 248762306a36Sopenharmony_ci atl1e_down(adapter); 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci pci_disable_device(pdev); 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci /* Request a slot reset. */ 249262306a36Sopenharmony_ci return PCI_ERS_RESULT_NEED_RESET; 249362306a36Sopenharmony_ci} 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci/** 249662306a36Sopenharmony_ci * atl1e_io_slot_reset - called after the pci bus has been reset. 249762306a36Sopenharmony_ci * @pdev: Pointer to PCI device 249862306a36Sopenharmony_ci * 249962306a36Sopenharmony_ci * Restart the card from scratch, as if from a cold-boot. Implementation 250062306a36Sopenharmony_ci * resembles the first-half of the e1000_resume routine. 250162306a36Sopenharmony_ci */ 250262306a36Sopenharmony_cistatic pci_ers_result_t atl1e_io_slot_reset(struct pci_dev *pdev) 250362306a36Sopenharmony_ci{ 250462306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 250562306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci if (pci_enable_device(pdev)) { 250862306a36Sopenharmony_ci netdev_err(adapter->netdev, 250962306a36Sopenharmony_ci "Cannot re-enable PCI device after reset\n"); 251062306a36Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 251162306a36Sopenharmony_ci } 251262306a36Sopenharmony_ci pci_set_master(pdev); 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci pci_enable_wake(pdev, PCI_D3hot, 0); 251562306a36Sopenharmony_ci pci_enable_wake(pdev, PCI_D3cold, 0); 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci atl1e_reset_hw(&adapter->hw); 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 252062306a36Sopenharmony_ci} 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci/** 252362306a36Sopenharmony_ci * atl1e_io_resume - called when traffic can start flowing again. 252462306a36Sopenharmony_ci * @pdev: Pointer to PCI device 252562306a36Sopenharmony_ci * 252662306a36Sopenharmony_ci * This callback is called when the error recovery driver tells us that 252762306a36Sopenharmony_ci * its OK to resume normal operation. Implementation resembles the 252862306a36Sopenharmony_ci * second-half of the atl1e_resume routine. 252962306a36Sopenharmony_ci */ 253062306a36Sopenharmony_cistatic void atl1e_io_resume(struct pci_dev *pdev) 253162306a36Sopenharmony_ci{ 253262306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 253362306a36Sopenharmony_ci struct atl1e_adapter *adapter = netdev_priv(netdev); 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci if (netif_running(netdev)) { 253662306a36Sopenharmony_ci if (atl1e_up(adapter)) { 253762306a36Sopenharmony_ci netdev_err(adapter->netdev, 253862306a36Sopenharmony_ci "can't bring device back up after reset\n"); 253962306a36Sopenharmony_ci return; 254062306a36Sopenharmony_ci } 254162306a36Sopenharmony_ci } 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci netif_device_attach(netdev); 254462306a36Sopenharmony_ci} 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_cistatic const struct pci_error_handlers atl1e_err_handler = { 254762306a36Sopenharmony_ci .error_detected = atl1e_io_error_detected, 254862306a36Sopenharmony_ci .slot_reset = atl1e_io_slot_reset, 254962306a36Sopenharmony_ci .resume = atl1e_io_resume, 255062306a36Sopenharmony_ci}; 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_cistatic struct pci_driver atl1e_driver = { 255362306a36Sopenharmony_ci .name = atl1e_driver_name, 255462306a36Sopenharmony_ci .id_table = atl1e_pci_tbl, 255562306a36Sopenharmony_ci .probe = atl1e_probe, 255662306a36Sopenharmony_ci .remove = atl1e_remove, 255762306a36Sopenharmony_ci /* Power Management Hooks */ 255862306a36Sopenharmony_ci#ifdef CONFIG_PM 255962306a36Sopenharmony_ci .suspend = atl1e_suspend, 256062306a36Sopenharmony_ci .resume = atl1e_resume, 256162306a36Sopenharmony_ci#endif 256262306a36Sopenharmony_ci .shutdown = atl1e_shutdown, 256362306a36Sopenharmony_ci .err_handler = &atl1e_err_handler 256462306a36Sopenharmony_ci}; 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_cimodule_pci_driver(atl1e_driver); 2567