162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * JMicron JMC2x0 series PCIe Ethernet Linux Device Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2008 JMicron Technology Corporation 662306a36Sopenharmony_ci * https://www.jmicron.com/ 762306a36Sopenharmony_ci * Copyright (c) 2009 - 2010 Guo-Fu Tseng <cooldavid@cooldavid.org> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Author: Guo-Fu Tseng <cooldavid@cooldavid.org> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/pci.h> 1762306a36Sopenharmony_ci#include <linux/netdevice.h> 1862306a36Sopenharmony_ci#include <linux/etherdevice.h> 1962306a36Sopenharmony_ci#include <linux/ethtool.h> 2062306a36Sopenharmony_ci#include <linux/mii.h> 2162306a36Sopenharmony_ci#include <linux/crc32.h> 2262306a36Sopenharmony_ci#include <linux/delay.h> 2362306a36Sopenharmony_ci#include <linux/spinlock.h> 2462306a36Sopenharmony_ci#include <linux/in.h> 2562306a36Sopenharmony_ci#include <linux/ip.h> 2662306a36Sopenharmony_ci#include <linux/ipv6.h> 2762306a36Sopenharmony_ci#include <linux/tcp.h> 2862306a36Sopenharmony_ci#include <linux/udp.h> 2962306a36Sopenharmony_ci#include <linux/if_vlan.h> 3062306a36Sopenharmony_ci#include <linux/slab.h> 3162306a36Sopenharmony_ci#include <linux/jiffies.h> 3262306a36Sopenharmony_ci#include <net/ip6_checksum.h> 3362306a36Sopenharmony_ci#include "jme.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int force_pseudohp = -1; 3662306a36Sopenharmony_cistatic int no_pseudohp = -1; 3762306a36Sopenharmony_cistatic int no_extplug = -1; 3862306a36Sopenharmony_cimodule_param(force_pseudohp, int, 0); 3962306a36Sopenharmony_ciMODULE_PARM_DESC(force_pseudohp, 4062306a36Sopenharmony_ci "Enable pseudo hot-plug feature manually by driver instead of BIOS."); 4162306a36Sopenharmony_cimodule_param(no_pseudohp, int, 0); 4262306a36Sopenharmony_ciMODULE_PARM_DESC(no_pseudohp, "Disable pseudo hot-plug feature."); 4362306a36Sopenharmony_cimodule_param(no_extplug, int, 0); 4462306a36Sopenharmony_ciMODULE_PARM_DESC(no_extplug, 4562306a36Sopenharmony_ci "Do not use external plug signal for pseudo hot-plug."); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic int 4862306a36Sopenharmony_cijme_mdio_read(struct net_device *netdev, int phy, int reg) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 5162306a36Sopenharmony_ci int i, val, again = (reg == MII_BMSR) ? 1 : 0; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciread_again: 5462306a36Sopenharmony_ci jwrite32(jme, JME_SMI, SMI_OP_REQ | 5562306a36Sopenharmony_ci smi_phy_addr(phy) | 5662306a36Sopenharmony_ci smi_reg_addr(reg)); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci wmb(); 5962306a36Sopenharmony_ci for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) { 6062306a36Sopenharmony_ci udelay(20); 6162306a36Sopenharmony_ci val = jread32(jme, JME_SMI); 6262306a36Sopenharmony_ci if ((val & SMI_OP_REQ) == 0) 6362306a36Sopenharmony_ci break; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (i == 0) { 6762306a36Sopenharmony_ci pr_err("phy(%d) read timeout : %d\n", phy, reg); 6862306a36Sopenharmony_ci return 0; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (again--) 7262306a36Sopenharmony_ci goto read_again; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return (val & SMI_DATA_MASK) >> SMI_DATA_SHIFT; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic void 7862306a36Sopenharmony_cijme_mdio_write(struct net_device *netdev, 7962306a36Sopenharmony_ci int phy, int reg, int val) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 8262306a36Sopenharmony_ci int i; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci jwrite32(jme, JME_SMI, SMI_OP_WRITE | SMI_OP_REQ | 8562306a36Sopenharmony_ci ((val << SMI_DATA_SHIFT) & SMI_DATA_MASK) | 8662306a36Sopenharmony_ci smi_phy_addr(phy) | smi_reg_addr(reg)); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci wmb(); 8962306a36Sopenharmony_ci for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) { 9062306a36Sopenharmony_ci udelay(20); 9162306a36Sopenharmony_ci if ((jread32(jme, JME_SMI) & SMI_OP_REQ) == 0) 9262306a36Sopenharmony_ci break; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (i == 0) 9662306a36Sopenharmony_ci pr_err("phy(%d) write timeout : %d\n", phy, reg); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic inline void 10062306a36Sopenharmony_cijme_reset_phy_processor(struct jme_adapter *jme) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci u32 val; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci jme_mdio_write(jme->dev, 10562306a36Sopenharmony_ci jme->mii_if.phy_id, 10662306a36Sopenharmony_ci MII_ADVERTISE, ADVERTISE_ALL | 10762306a36Sopenharmony_ci ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) 11062306a36Sopenharmony_ci jme_mdio_write(jme->dev, 11162306a36Sopenharmony_ci jme->mii_if.phy_id, 11262306a36Sopenharmony_ci MII_CTRL1000, 11362306a36Sopenharmony_ci ADVERTISE_1000FULL | ADVERTISE_1000HALF); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci val = jme_mdio_read(jme->dev, 11662306a36Sopenharmony_ci jme->mii_if.phy_id, 11762306a36Sopenharmony_ci MII_BMCR); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci jme_mdio_write(jme->dev, 12062306a36Sopenharmony_ci jme->mii_if.phy_id, 12162306a36Sopenharmony_ci MII_BMCR, val | BMCR_RESET); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void 12562306a36Sopenharmony_cijme_setup_wakeup_frame(struct jme_adapter *jme, 12662306a36Sopenharmony_ci const u32 *mask, u32 crc, int fnr) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci int i; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* 13162306a36Sopenharmony_ci * Setup CRC pattern 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci jwrite32(jme, JME_WFOI, WFOI_CRC_SEL | (fnr & WFOI_FRAME_SEL)); 13462306a36Sopenharmony_ci wmb(); 13562306a36Sopenharmony_ci jwrite32(jme, JME_WFODP, crc); 13662306a36Sopenharmony_ci wmb(); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* 13962306a36Sopenharmony_ci * Setup Mask 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci for (i = 0 ; i < WAKEUP_FRAME_MASK_DWNR ; ++i) { 14262306a36Sopenharmony_ci jwrite32(jme, JME_WFOI, 14362306a36Sopenharmony_ci ((i << WFOI_MASK_SHIFT) & WFOI_MASK_SEL) | 14462306a36Sopenharmony_ci (fnr & WFOI_FRAME_SEL)); 14562306a36Sopenharmony_ci wmb(); 14662306a36Sopenharmony_ci jwrite32(jme, JME_WFODP, mask[i]); 14762306a36Sopenharmony_ci wmb(); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic inline void 15262306a36Sopenharmony_cijme_mac_rxclk_off(struct jme_adapter *jme) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci jme->reg_gpreg1 |= GPREG1_RXCLKOFF; 15562306a36Sopenharmony_ci jwrite32f(jme, JME_GPREG1, jme->reg_gpreg1); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic inline void 15962306a36Sopenharmony_cijme_mac_rxclk_on(struct jme_adapter *jme) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci jme->reg_gpreg1 &= ~GPREG1_RXCLKOFF; 16262306a36Sopenharmony_ci jwrite32f(jme, JME_GPREG1, jme->reg_gpreg1); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic inline void 16662306a36Sopenharmony_cijme_mac_txclk_off(struct jme_adapter *jme) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci jme->reg_ghc &= ~(GHC_TO_CLK_SRC | GHC_TXMAC_CLK_SRC); 16962306a36Sopenharmony_ci jwrite32f(jme, JME_GHC, jme->reg_ghc); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic inline void 17362306a36Sopenharmony_cijme_mac_txclk_on(struct jme_adapter *jme) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci u32 speed = jme->reg_ghc & GHC_SPEED; 17662306a36Sopenharmony_ci if (speed == GHC_SPEED_1000M) 17762306a36Sopenharmony_ci jme->reg_ghc |= GHC_TO_CLK_GPHY | GHC_TXMAC_CLK_GPHY; 17862306a36Sopenharmony_ci else 17962306a36Sopenharmony_ci jme->reg_ghc |= GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE; 18062306a36Sopenharmony_ci jwrite32f(jme, JME_GHC, jme->reg_ghc); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic inline void 18462306a36Sopenharmony_cijme_reset_ghc_speed(struct jme_adapter *jme) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci jme->reg_ghc &= ~(GHC_SPEED | GHC_DPX); 18762306a36Sopenharmony_ci jwrite32f(jme, JME_GHC, jme->reg_ghc); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic inline void 19162306a36Sopenharmony_cijme_reset_250A2_workaround(struct jme_adapter *jme) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci jme->reg_gpreg1 &= ~(GPREG1_HALFMODEPATCH | 19462306a36Sopenharmony_ci GPREG1_RSSPATCH); 19562306a36Sopenharmony_ci jwrite32(jme, JME_GPREG1, jme->reg_gpreg1); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic inline void 19962306a36Sopenharmony_cijme_assert_ghc_reset(struct jme_adapter *jme) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci jme->reg_ghc |= GHC_SWRST; 20262306a36Sopenharmony_ci jwrite32f(jme, JME_GHC, jme->reg_ghc); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic inline void 20662306a36Sopenharmony_cijme_clear_ghc_reset(struct jme_adapter *jme) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci jme->reg_ghc &= ~GHC_SWRST; 20962306a36Sopenharmony_ci jwrite32f(jme, JME_GHC, jme->reg_ghc); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic void 21362306a36Sopenharmony_cijme_reset_mac_processor(struct jme_adapter *jme) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci static const u32 mask[WAKEUP_FRAME_MASK_DWNR] = {0, 0, 0, 0}; 21662306a36Sopenharmony_ci u32 crc = 0xCDCDCDCD; 21762306a36Sopenharmony_ci u32 gpreg0; 21862306a36Sopenharmony_ci int i; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci jme_reset_ghc_speed(jme); 22162306a36Sopenharmony_ci jme_reset_250A2_workaround(jme); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci jme_mac_rxclk_on(jme); 22462306a36Sopenharmony_ci jme_mac_txclk_on(jme); 22562306a36Sopenharmony_ci udelay(1); 22662306a36Sopenharmony_ci jme_assert_ghc_reset(jme); 22762306a36Sopenharmony_ci udelay(1); 22862306a36Sopenharmony_ci jme_mac_rxclk_off(jme); 22962306a36Sopenharmony_ci jme_mac_txclk_off(jme); 23062306a36Sopenharmony_ci udelay(1); 23162306a36Sopenharmony_ci jme_clear_ghc_reset(jme); 23262306a36Sopenharmony_ci udelay(1); 23362306a36Sopenharmony_ci jme_mac_rxclk_on(jme); 23462306a36Sopenharmony_ci jme_mac_txclk_on(jme); 23562306a36Sopenharmony_ci udelay(1); 23662306a36Sopenharmony_ci jme_mac_rxclk_off(jme); 23762306a36Sopenharmony_ci jme_mac_txclk_off(jme); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci jwrite32(jme, JME_RXDBA_LO, 0x00000000); 24062306a36Sopenharmony_ci jwrite32(jme, JME_RXDBA_HI, 0x00000000); 24162306a36Sopenharmony_ci jwrite32(jme, JME_RXQDC, 0x00000000); 24262306a36Sopenharmony_ci jwrite32(jme, JME_RXNDA, 0x00000000); 24362306a36Sopenharmony_ci jwrite32(jme, JME_TXDBA_LO, 0x00000000); 24462306a36Sopenharmony_ci jwrite32(jme, JME_TXDBA_HI, 0x00000000); 24562306a36Sopenharmony_ci jwrite32(jme, JME_TXQDC, 0x00000000); 24662306a36Sopenharmony_ci jwrite32(jme, JME_TXNDA, 0x00000000); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci jwrite32(jme, JME_RXMCHT_LO, 0x00000000); 24962306a36Sopenharmony_ci jwrite32(jme, JME_RXMCHT_HI, 0x00000000); 25062306a36Sopenharmony_ci for (i = 0 ; i < WAKEUP_FRAME_NR ; ++i) 25162306a36Sopenharmony_ci jme_setup_wakeup_frame(jme, mask, crc, i); 25262306a36Sopenharmony_ci if (jme->fpgaver) 25362306a36Sopenharmony_ci gpreg0 = GPREG0_DEFAULT | GPREG0_LNKINTPOLL; 25462306a36Sopenharmony_ci else 25562306a36Sopenharmony_ci gpreg0 = GPREG0_DEFAULT; 25662306a36Sopenharmony_ci jwrite32(jme, JME_GPREG0, gpreg0); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic inline void 26062306a36Sopenharmony_cijme_clear_pm_enable_wol(struct jme_adapter *jme) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci jwrite32(jme, JME_PMCS, PMCS_STMASK | jme->reg_pmcs); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic inline void 26662306a36Sopenharmony_cijme_clear_pm_disable_wol(struct jme_adapter *jme) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci jwrite32(jme, JME_PMCS, PMCS_STMASK); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int 27262306a36Sopenharmony_cijme_reload_eeprom(struct jme_adapter *jme) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci u32 val; 27562306a36Sopenharmony_ci int i; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci val = jread32(jme, JME_SMBCSR); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (val & SMBCSR_EEPROMD) { 28062306a36Sopenharmony_ci val |= SMBCSR_CNACK; 28162306a36Sopenharmony_ci jwrite32(jme, JME_SMBCSR, val); 28262306a36Sopenharmony_ci val |= SMBCSR_RELOAD; 28362306a36Sopenharmony_ci jwrite32(jme, JME_SMBCSR, val); 28462306a36Sopenharmony_ci mdelay(12); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci for (i = JME_EEPROM_RELOAD_TIMEOUT; i > 0; --i) { 28762306a36Sopenharmony_ci mdelay(1); 28862306a36Sopenharmony_ci if ((jread32(jme, JME_SMBCSR) & SMBCSR_RELOAD) == 0) 28962306a36Sopenharmony_ci break; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (i == 0) { 29362306a36Sopenharmony_ci pr_err("eeprom reload timeout\n"); 29462306a36Sopenharmony_ci return -EIO; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return 0; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic void 30262306a36Sopenharmony_cijme_load_macaddr(struct net_device *netdev) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 30562306a36Sopenharmony_ci unsigned char macaddr[ETH_ALEN]; 30662306a36Sopenharmony_ci u32 val; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci spin_lock_bh(&jme->macaddr_lock); 30962306a36Sopenharmony_ci val = jread32(jme, JME_RXUMA_LO); 31062306a36Sopenharmony_ci macaddr[0] = (val >> 0) & 0xFF; 31162306a36Sopenharmony_ci macaddr[1] = (val >> 8) & 0xFF; 31262306a36Sopenharmony_ci macaddr[2] = (val >> 16) & 0xFF; 31362306a36Sopenharmony_ci macaddr[3] = (val >> 24) & 0xFF; 31462306a36Sopenharmony_ci val = jread32(jme, JME_RXUMA_HI); 31562306a36Sopenharmony_ci macaddr[4] = (val >> 0) & 0xFF; 31662306a36Sopenharmony_ci macaddr[5] = (val >> 8) & 0xFF; 31762306a36Sopenharmony_ci eth_hw_addr_set(netdev, macaddr); 31862306a36Sopenharmony_ci spin_unlock_bh(&jme->macaddr_lock); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic inline void 32262306a36Sopenharmony_cijme_set_rx_pcc(struct jme_adapter *jme, int p) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci switch (p) { 32562306a36Sopenharmony_ci case PCC_OFF: 32662306a36Sopenharmony_ci jwrite32(jme, JME_PCCRX0, 32762306a36Sopenharmony_ci ((PCC_OFF_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) | 32862306a36Sopenharmony_ci ((PCC_OFF_CNT << PCCRX_SHIFT) & PCCRX_MASK)); 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci case PCC_P1: 33162306a36Sopenharmony_ci jwrite32(jme, JME_PCCRX0, 33262306a36Sopenharmony_ci ((PCC_P1_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) | 33362306a36Sopenharmony_ci ((PCC_P1_CNT << PCCRX_SHIFT) & PCCRX_MASK)); 33462306a36Sopenharmony_ci break; 33562306a36Sopenharmony_ci case PCC_P2: 33662306a36Sopenharmony_ci jwrite32(jme, JME_PCCRX0, 33762306a36Sopenharmony_ci ((PCC_P2_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) | 33862306a36Sopenharmony_ci ((PCC_P2_CNT << PCCRX_SHIFT) & PCCRX_MASK)); 33962306a36Sopenharmony_ci break; 34062306a36Sopenharmony_ci case PCC_P3: 34162306a36Sopenharmony_ci jwrite32(jme, JME_PCCRX0, 34262306a36Sopenharmony_ci ((PCC_P3_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) | 34362306a36Sopenharmony_ci ((PCC_P3_CNT << PCCRX_SHIFT) & PCCRX_MASK)); 34462306a36Sopenharmony_ci break; 34562306a36Sopenharmony_ci default: 34662306a36Sopenharmony_ci break; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci wmb(); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (!(test_bit(JME_FLAG_POLL, &jme->flags))) 35162306a36Sopenharmony_ci netif_info(jme, rx_status, jme->dev, "Switched to PCC_P%d\n", p); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic void 35562306a36Sopenharmony_cijme_start_irq(struct jme_adapter *jme) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci register struct dynpcc_info *dpi = &(jme->dpi); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci jme_set_rx_pcc(jme, PCC_P1); 36062306a36Sopenharmony_ci dpi->cur = PCC_P1; 36162306a36Sopenharmony_ci dpi->attempt = PCC_P1; 36262306a36Sopenharmony_ci dpi->cnt = 0; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci jwrite32(jme, JME_PCCTX, 36562306a36Sopenharmony_ci ((PCC_TX_TO << PCCTXTO_SHIFT) & PCCTXTO_MASK) | 36662306a36Sopenharmony_ci ((PCC_TX_CNT << PCCTX_SHIFT) & PCCTX_MASK) | 36762306a36Sopenharmony_ci PCCTXQ0_EN 36862306a36Sopenharmony_ci ); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* 37162306a36Sopenharmony_ci * Enable Interrupts 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_ci jwrite32(jme, JME_IENS, INTR_ENABLE); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic inline void 37762306a36Sopenharmony_cijme_stop_irq(struct jme_adapter *jme) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci /* 38062306a36Sopenharmony_ci * Disable Interrupts 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci jwrite32f(jme, JME_IENC, INTR_ENABLE); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic u32 38662306a36Sopenharmony_cijme_linkstat_from_phy(struct jme_adapter *jme) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci u32 phylink, bmsr; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci phylink = jme_mdio_read(jme->dev, jme->mii_if.phy_id, 17); 39162306a36Sopenharmony_ci bmsr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMSR); 39262306a36Sopenharmony_ci if (bmsr & BMSR_ANCOMP) 39362306a36Sopenharmony_ci phylink |= PHY_LINK_AUTONEG_COMPLETE; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci return phylink; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic inline void 39962306a36Sopenharmony_cijme_set_phyfifo_5level(struct jme_adapter *jme) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0004); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic inline void 40562306a36Sopenharmony_cijme_set_phyfifo_8level(struct jme_adapter *jme) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0000); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic int 41162306a36Sopenharmony_cijme_check_link(struct net_device *netdev, int testonly) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 41462306a36Sopenharmony_ci u32 phylink, cnt = JME_SPDRSV_TIMEOUT, bmcr; 41562306a36Sopenharmony_ci char linkmsg[64]; 41662306a36Sopenharmony_ci int rc = 0; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci linkmsg[0] = '\0'; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (jme->fpgaver) 42162306a36Sopenharmony_ci phylink = jme_linkstat_from_phy(jme); 42262306a36Sopenharmony_ci else 42362306a36Sopenharmony_ci phylink = jread32(jme, JME_PHY_LINK); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (phylink & PHY_LINK_UP) { 42662306a36Sopenharmony_ci if (!(phylink & PHY_LINK_AUTONEG_COMPLETE)) { 42762306a36Sopenharmony_ci /* 42862306a36Sopenharmony_ci * If we did not enable AN 42962306a36Sopenharmony_ci * Speed/Duplex Info should be obtained from SMI 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_ci phylink = PHY_LINK_UP; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci bmcr = jme_mdio_read(jme->dev, 43462306a36Sopenharmony_ci jme->mii_if.phy_id, 43562306a36Sopenharmony_ci MII_BMCR); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci phylink |= ((bmcr & BMCR_SPEED1000) && 43862306a36Sopenharmony_ci (bmcr & BMCR_SPEED100) == 0) ? 43962306a36Sopenharmony_ci PHY_LINK_SPEED_1000M : 44062306a36Sopenharmony_ci (bmcr & BMCR_SPEED100) ? 44162306a36Sopenharmony_ci PHY_LINK_SPEED_100M : 44262306a36Sopenharmony_ci PHY_LINK_SPEED_10M; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci phylink |= (bmcr & BMCR_FULLDPLX) ? 44562306a36Sopenharmony_ci PHY_LINK_DUPLEX : 0; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci strcat(linkmsg, "Forced: "); 44862306a36Sopenharmony_ci } else { 44962306a36Sopenharmony_ci /* 45062306a36Sopenharmony_ci * Keep polling for speed/duplex resolve complete 45162306a36Sopenharmony_ci */ 45262306a36Sopenharmony_ci while (!(phylink & PHY_LINK_SPEEDDPU_RESOLVED) && 45362306a36Sopenharmony_ci --cnt) { 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci udelay(1); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (jme->fpgaver) 45862306a36Sopenharmony_ci phylink = jme_linkstat_from_phy(jme); 45962306a36Sopenharmony_ci else 46062306a36Sopenharmony_ci phylink = jread32(jme, JME_PHY_LINK); 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci if (!cnt) 46362306a36Sopenharmony_ci pr_err("Waiting speed resolve timeout\n"); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci strcat(linkmsg, "ANed: "); 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (jme->phylink == phylink) { 46962306a36Sopenharmony_ci rc = 1; 47062306a36Sopenharmony_ci goto out; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci if (testonly) 47362306a36Sopenharmony_ci goto out; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci jme->phylink = phylink; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* 47862306a36Sopenharmony_ci * The speed/duplex setting of jme->reg_ghc already cleared 47962306a36Sopenharmony_ci * by jme_reset_mac_processor() 48062306a36Sopenharmony_ci */ 48162306a36Sopenharmony_ci switch (phylink & PHY_LINK_SPEED_MASK) { 48262306a36Sopenharmony_ci case PHY_LINK_SPEED_10M: 48362306a36Sopenharmony_ci jme->reg_ghc |= GHC_SPEED_10M; 48462306a36Sopenharmony_ci strcat(linkmsg, "10 Mbps, "); 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci case PHY_LINK_SPEED_100M: 48762306a36Sopenharmony_ci jme->reg_ghc |= GHC_SPEED_100M; 48862306a36Sopenharmony_ci strcat(linkmsg, "100 Mbps, "); 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci case PHY_LINK_SPEED_1000M: 49162306a36Sopenharmony_ci jme->reg_ghc |= GHC_SPEED_1000M; 49262306a36Sopenharmony_ci strcat(linkmsg, "1000 Mbps, "); 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci default: 49562306a36Sopenharmony_ci break; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (phylink & PHY_LINK_DUPLEX) { 49962306a36Sopenharmony_ci jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT); 50062306a36Sopenharmony_ci jwrite32(jme, JME_TXTRHD, TXTRHD_FULLDUPLEX); 50162306a36Sopenharmony_ci jme->reg_ghc |= GHC_DPX; 50262306a36Sopenharmony_ci } else { 50362306a36Sopenharmony_ci jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT | 50462306a36Sopenharmony_ci TXMCS_BACKOFF | 50562306a36Sopenharmony_ci TXMCS_CARRIERSENSE | 50662306a36Sopenharmony_ci TXMCS_COLLISION); 50762306a36Sopenharmony_ci jwrite32(jme, JME_TXTRHD, TXTRHD_HALFDUPLEX); 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci jwrite32(jme, JME_GHC, jme->reg_ghc); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (is_buggy250(jme->pdev->device, jme->chiprev)) { 51362306a36Sopenharmony_ci jme->reg_gpreg1 &= ~(GPREG1_HALFMODEPATCH | 51462306a36Sopenharmony_ci GPREG1_RSSPATCH); 51562306a36Sopenharmony_ci if (!(phylink & PHY_LINK_DUPLEX)) 51662306a36Sopenharmony_ci jme->reg_gpreg1 |= GPREG1_HALFMODEPATCH; 51762306a36Sopenharmony_ci switch (phylink & PHY_LINK_SPEED_MASK) { 51862306a36Sopenharmony_ci case PHY_LINK_SPEED_10M: 51962306a36Sopenharmony_ci jme_set_phyfifo_8level(jme); 52062306a36Sopenharmony_ci jme->reg_gpreg1 |= GPREG1_RSSPATCH; 52162306a36Sopenharmony_ci break; 52262306a36Sopenharmony_ci case PHY_LINK_SPEED_100M: 52362306a36Sopenharmony_ci jme_set_phyfifo_5level(jme); 52462306a36Sopenharmony_ci jme->reg_gpreg1 |= GPREG1_RSSPATCH; 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci case PHY_LINK_SPEED_1000M: 52762306a36Sopenharmony_ci jme_set_phyfifo_8level(jme); 52862306a36Sopenharmony_ci break; 52962306a36Sopenharmony_ci default: 53062306a36Sopenharmony_ci break; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci jwrite32(jme, JME_GPREG1, jme->reg_gpreg1); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci strcat(linkmsg, (phylink & PHY_LINK_DUPLEX) ? 53662306a36Sopenharmony_ci "Full-Duplex, " : 53762306a36Sopenharmony_ci "Half-Duplex, "); 53862306a36Sopenharmony_ci strcat(linkmsg, (phylink & PHY_LINK_MDI_STAT) ? 53962306a36Sopenharmony_ci "MDI-X" : 54062306a36Sopenharmony_ci "MDI"); 54162306a36Sopenharmony_ci netif_info(jme, link, jme->dev, "Link is up at %s\n", linkmsg); 54262306a36Sopenharmony_ci netif_carrier_on(netdev); 54362306a36Sopenharmony_ci } else { 54462306a36Sopenharmony_ci if (testonly) 54562306a36Sopenharmony_ci goto out; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci netif_info(jme, link, jme->dev, "Link is down\n"); 54862306a36Sopenharmony_ci jme->phylink = 0; 54962306a36Sopenharmony_ci netif_carrier_off(netdev); 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ciout: 55362306a36Sopenharmony_ci return rc; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic int 55762306a36Sopenharmony_cijme_setup_tx_resources(struct jme_adapter *jme) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct jme_ring *txring = &(jme->txring[0]); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci txring->alloc = dma_alloc_coherent(&(jme->pdev->dev), 56262306a36Sopenharmony_ci TX_RING_ALLOC_SIZE(jme->tx_ring_size), 56362306a36Sopenharmony_ci &(txring->dmaalloc), 56462306a36Sopenharmony_ci GFP_ATOMIC); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (!txring->alloc) 56762306a36Sopenharmony_ci goto err_set_null; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* 57062306a36Sopenharmony_ci * 16 Bytes align 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci txring->desc = (void *)ALIGN((unsigned long)(txring->alloc), 57362306a36Sopenharmony_ci RING_DESC_ALIGN); 57462306a36Sopenharmony_ci txring->dma = ALIGN(txring->dmaalloc, RING_DESC_ALIGN); 57562306a36Sopenharmony_ci txring->next_to_use = 0; 57662306a36Sopenharmony_ci atomic_set(&txring->next_to_clean, 0); 57762306a36Sopenharmony_ci atomic_set(&txring->nr_free, jme->tx_ring_size); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci txring->bufinf = kcalloc(jme->tx_ring_size, 58062306a36Sopenharmony_ci sizeof(struct jme_buffer_info), 58162306a36Sopenharmony_ci GFP_ATOMIC); 58262306a36Sopenharmony_ci if (unlikely(!(txring->bufinf))) 58362306a36Sopenharmony_ci goto err_free_txring; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci return 0; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cierr_free_txring: 58862306a36Sopenharmony_ci dma_free_coherent(&(jme->pdev->dev), 58962306a36Sopenharmony_ci TX_RING_ALLOC_SIZE(jme->tx_ring_size), 59062306a36Sopenharmony_ci txring->alloc, 59162306a36Sopenharmony_ci txring->dmaalloc); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cierr_set_null: 59462306a36Sopenharmony_ci txring->desc = NULL; 59562306a36Sopenharmony_ci txring->dmaalloc = 0; 59662306a36Sopenharmony_ci txring->dma = 0; 59762306a36Sopenharmony_ci txring->bufinf = NULL; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return -ENOMEM; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic void 60362306a36Sopenharmony_cijme_free_tx_resources(struct jme_adapter *jme) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci int i; 60662306a36Sopenharmony_ci struct jme_ring *txring = &(jme->txring[0]); 60762306a36Sopenharmony_ci struct jme_buffer_info *txbi; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if (txring->alloc) { 61062306a36Sopenharmony_ci if (txring->bufinf) { 61162306a36Sopenharmony_ci for (i = 0 ; i < jme->tx_ring_size ; ++i) { 61262306a36Sopenharmony_ci txbi = txring->bufinf + i; 61362306a36Sopenharmony_ci if (txbi->skb) { 61462306a36Sopenharmony_ci dev_kfree_skb(txbi->skb); 61562306a36Sopenharmony_ci txbi->skb = NULL; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci txbi->mapping = 0; 61862306a36Sopenharmony_ci txbi->len = 0; 61962306a36Sopenharmony_ci txbi->nr_desc = 0; 62062306a36Sopenharmony_ci txbi->start_xmit = 0; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci kfree(txring->bufinf); 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci dma_free_coherent(&(jme->pdev->dev), 62662306a36Sopenharmony_ci TX_RING_ALLOC_SIZE(jme->tx_ring_size), 62762306a36Sopenharmony_ci txring->alloc, 62862306a36Sopenharmony_ci txring->dmaalloc); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci txring->alloc = NULL; 63162306a36Sopenharmony_ci txring->desc = NULL; 63262306a36Sopenharmony_ci txring->dmaalloc = 0; 63362306a36Sopenharmony_ci txring->dma = 0; 63462306a36Sopenharmony_ci txring->bufinf = NULL; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci txring->next_to_use = 0; 63762306a36Sopenharmony_ci atomic_set(&txring->next_to_clean, 0); 63862306a36Sopenharmony_ci atomic_set(&txring->nr_free, 0); 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic inline void 64262306a36Sopenharmony_cijme_enable_tx_engine(struct jme_adapter *jme) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci /* 64562306a36Sopenharmony_ci * Select Queue 0 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_ci jwrite32(jme, JME_TXCS, TXCS_DEFAULT | TXCS_SELECT_QUEUE0); 64862306a36Sopenharmony_ci wmb(); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci /* 65162306a36Sopenharmony_ci * Setup TX Queue 0 DMA Bass Address 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_ci jwrite32(jme, JME_TXDBA_LO, (__u64)jme->txring[0].dma & 0xFFFFFFFFUL); 65462306a36Sopenharmony_ci jwrite32(jme, JME_TXDBA_HI, (__u64)(jme->txring[0].dma) >> 32); 65562306a36Sopenharmony_ci jwrite32(jme, JME_TXNDA, (__u64)jme->txring[0].dma & 0xFFFFFFFFUL); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* 65862306a36Sopenharmony_ci * Setup TX Descptor Count 65962306a36Sopenharmony_ci */ 66062306a36Sopenharmony_ci jwrite32(jme, JME_TXQDC, jme->tx_ring_size); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* 66362306a36Sopenharmony_ci * Enable TX Engine 66462306a36Sopenharmony_ci */ 66562306a36Sopenharmony_ci wmb(); 66662306a36Sopenharmony_ci jwrite32f(jme, JME_TXCS, jme->reg_txcs | 66762306a36Sopenharmony_ci TXCS_SELECT_QUEUE0 | 66862306a36Sopenharmony_ci TXCS_ENABLE); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* 67162306a36Sopenharmony_ci * Start clock for TX MAC Processor 67262306a36Sopenharmony_ci */ 67362306a36Sopenharmony_ci jme_mac_txclk_on(jme); 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic inline void 67762306a36Sopenharmony_cijme_disable_tx_engine(struct jme_adapter *jme) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci int i; 68062306a36Sopenharmony_ci u32 val; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci /* 68362306a36Sopenharmony_ci * Disable TX Engine 68462306a36Sopenharmony_ci */ 68562306a36Sopenharmony_ci jwrite32(jme, JME_TXCS, jme->reg_txcs | TXCS_SELECT_QUEUE0); 68662306a36Sopenharmony_ci wmb(); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci val = jread32(jme, JME_TXCS); 68962306a36Sopenharmony_ci for (i = JME_TX_DISABLE_TIMEOUT ; (val & TXCS_ENABLE) && i > 0 ; --i) { 69062306a36Sopenharmony_ci mdelay(1); 69162306a36Sopenharmony_ci val = jread32(jme, JME_TXCS); 69262306a36Sopenharmony_ci rmb(); 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci if (!i) 69662306a36Sopenharmony_ci pr_err("Disable TX engine timeout\n"); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* 69962306a36Sopenharmony_ci * Stop clock for TX MAC Processor 70062306a36Sopenharmony_ci */ 70162306a36Sopenharmony_ci jme_mac_txclk_off(jme); 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic void 70562306a36Sopenharmony_cijme_set_clean_rxdesc(struct jme_adapter *jme, int i) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci struct jme_ring *rxring = &(jme->rxring[0]); 70862306a36Sopenharmony_ci register struct rxdesc *rxdesc = rxring->desc; 70962306a36Sopenharmony_ci struct jme_buffer_info *rxbi = rxring->bufinf; 71062306a36Sopenharmony_ci rxdesc += i; 71162306a36Sopenharmony_ci rxbi += i; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci rxdesc->dw[0] = 0; 71462306a36Sopenharmony_ci rxdesc->dw[1] = 0; 71562306a36Sopenharmony_ci rxdesc->desc1.bufaddrh = cpu_to_le32((__u64)rxbi->mapping >> 32); 71662306a36Sopenharmony_ci rxdesc->desc1.bufaddrl = cpu_to_le32( 71762306a36Sopenharmony_ci (__u64)rxbi->mapping & 0xFFFFFFFFUL); 71862306a36Sopenharmony_ci rxdesc->desc1.datalen = cpu_to_le16(rxbi->len); 71962306a36Sopenharmony_ci if (jme->dev->features & NETIF_F_HIGHDMA) 72062306a36Sopenharmony_ci rxdesc->desc1.flags = RXFLAG_64BIT; 72162306a36Sopenharmony_ci wmb(); 72262306a36Sopenharmony_ci rxdesc->desc1.flags |= RXFLAG_OWN | RXFLAG_INT; 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_cistatic int 72662306a36Sopenharmony_cijme_make_new_rx_buf(struct jme_adapter *jme, int i) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci struct jme_ring *rxring = &(jme->rxring[0]); 72962306a36Sopenharmony_ci struct jme_buffer_info *rxbi = rxring->bufinf + i; 73062306a36Sopenharmony_ci struct sk_buff *skb; 73162306a36Sopenharmony_ci dma_addr_t mapping; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci skb = netdev_alloc_skb(jme->dev, 73462306a36Sopenharmony_ci jme->dev->mtu + RX_EXTRA_LEN); 73562306a36Sopenharmony_ci if (unlikely(!skb)) 73662306a36Sopenharmony_ci return -ENOMEM; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci mapping = dma_map_page(&jme->pdev->dev, virt_to_page(skb->data), 73962306a36Sopenharmony_ci offset_in_page(skb->data), skb_tailroom(skb), 74062306a36Sopenharmony_ci DMA_FROM_DEVICE); 74162306a36Sopenharmony_ci if (unlikely(dma_mapping_error(&jme->pdev->dev, mapping))) { 74262306a36Sopenharmony_ci dev_kfree_skb(skb); 74362306a36Sopenharmony_ci return -ENOMEM; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci if (likely(rxbi->mapping)) 74762306a36Sopenharmony_ci dma_unmap_page(&jme->pdev->dev, rxbi->mapping, rxbi->len, 74862306a36Sopenharmony_ci DMA_FROM_DEVICE); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci rxbi->skb = skb; 75162306a36Sopenharmony_ci rxbi->len = skb_tailroom(skb); 75262306a36Sopenharmony_ci rxbi->mapping = mapping; 75362306a36Sopenharmony_ci return 0; 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic void 75762306a36Sopenharmony_cijme_free_rx_buf(struct jme_adapter *jme, int i) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci struct jme_ring *rxring = &(jme->rxring[0]); 76062306a36Sopenharmony_ci struct jme_buffer_info *rxbi = rxring->bufinf; 76162306a36Sopenharmony_ci rxbi += i; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (rxbi->skb) { 76462306a36Sopenharmony_ci dma_unmap_page(&jme->pdev->dev, rxbi->mapping, rxbi->len, 76562306a36Sopenharmony_ci DMA_FROM_DEVICE); 76662306a36Sopenharmony_ci dev_kfree_skb(rxbi->skb); 76762306a36Sopenharmony_ci rxbi->skb = NULL; 76862306a36Sopenharmony_ci rxbi->mapping = 0; 76962306a36Sopenharmony_ci rxbi->len = 0; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic void 77462306a36Sopenharmony_cijme_free_rx_resources(struct jme_adapter *jme) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci int i; 77762306a36Sopenharmony_ci struct jme_ring *rxring = &(jme->rxring[0]); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (rxring->alloc) { 78062306a36Sopenharmony_ci if (rxring->bufinf) { 78162306a36Sopenharmony_ci for (i = 0 ; i < jme->rx_ring_size ; ++i) 78262306a36Sopenharmony_ci jme_free_rx_buf(jme, i); 78362306a36Sopenharmony_ci kfree(rxring->bufinf); 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci dma_free_coherent(&(jme->pdev->dev), 78762306a36Sopenharmony_ci RX_RING_ALLOC_SIZE(jme->rx_ring_size), 78862306a36Sopenharmony_ci rxring->alloc, 78962306a36Sopenharmony_ci rxring->dmaalloc); 79062306a36Sopenharmony_ci rxring->alloc = NULL; 79162306a36Sopenharmony_ci rxring->desc = NULL; 79262306a36Sopenharmony_ci rxring->dmaalloc = 0; 79362306a36Sopenharmony_ci rxring->dma = 0; 79462306a36Sopenharmony_ci rxring->bufinf = NULL; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci rxring->next_to_use = 0; 79762306a36Sopenharmony_ci atomic_set(&rxring->next_to_clean, 0); 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_cistatic int 80162306a36Sopenharmony_cijme_setup_rx_resources(struct jme_adapter *jme) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci int i; 80462306a36Sopenharmony_ci struct jme_ring *rxring = &(jme->rxring[0]); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci rxring->alloc = dma_alloc_coherent(&(jme->pdev->dev), 80762306a36Sopenharmony_ci RX_RING_ALLOC_SIZE(jme->rx_ring_size), 80862306a36Sopenharmony_ci &(rxring->dmaalloc), 80962306a36Sopenharmony_ci GFP_ATOMIC); 81062306a36Sopenharmony_ci if (!rxring->alloc) 81162306a36Sopenharmony_ci goto err_set_null; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci /* 81462306a36Sopenharmony_ci * 16 Bytes align 81562306a36Sopenharmony_ci */ 81662306a36Sopenharmony_ci rxring->desc = (void *)ALIGN((unsigned long)(rxring->alloc), 81762306a36Sopenharmony_ci RING_DESC_ALIGN); 81862306a36Sopenharmony_ci rxring->dma = ALIGN(rxring->dmaalloc, RING_DESC_ALIGN); 81962306a36Sopenharmony_ci rxring->next_to_use = 0; 82062306a36Sopenharmony_ci atomic_set(&rxring->next_to_clean, 0); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci rxring->bufinf = kcalloc(jme->rx_ring_size, 82362306a36Sopenharmony_ci sizeof(struct jme_buffer_info), 82462306a36Sopenharmony_ci GFP_ATOMIC); 82562306a36Sopenharmony_ci if (unlikely(!(rxring->bufinf))) 82662306a36Sopenharmony_ci goto err_free_rxring; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci /* 82962306a36Sopenharmony_ci * Initiallize Receive Descriptors 83062306a36Sopenharmony_ci */ 83162306a36Sopenharmony_ci for (i = 0 ; i < jme->rx_ring_size ; ++i) { 83262306a36Sopenharmony_ci if (unlikely(jme_make_new_rx_buf(jme, i))) { 83362306a36Sopenharmony_ci jme_free_rx_resources(jme); 83462306a36Sopenharmony_ci return -ENOMEM; 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci jme_set_clean_rxdesc(jme, i); 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci return 0; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_cierr_free_rxring: 84362306a36Sopenharmony_ci dma_free_coherent(&(jme->pdev->dev), 84462306a36Sopenharmony_ci RX_RING_ALLOC_SIZE(jme->rx_ring_size), 84562306a36Sopenharmony_ci rxring->alloc, 84662306a36Sopenharmony_ci rxring->dmaalloc); 84762306a36Sopenharmony_cierr_set_null: 84862306a36Sopenharmony_ci rxring->desc = NULL; 84962306a36Sopenharmony_ci rxring->dmaalloc = 0; 85062306a36Sopenharmony_ci rxring->dma = 0; 85162306a36Sopenharmony_ci rxring->bufinf = NULL; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci return -ENOMEM; 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_cistatic inline void 85762306a36Sopenharmony_cijme_enable_rx_engine(struct jme_adapter *jme) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci /* 86062306a36Sopenharmony_ci * Select Queue 0 86162306a36Sopenharmony_ci */ 86262306a36Sopenharmony_ci jwrite32(jme, JME_RXCS, jme->reg_rxcs | 86362306a36Sopenharmony_ci RXCS_QUEUESEL_Q0); 86462306a36Sopenharmony_ci wmb(); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci /* 86762306a36Sopenharmony_ci * Setup RX DMA Bass Address 86862306a36Sopenharmony_ci */ 86962306a36Sopenharmony_ci jwrite32(jme, JME_RXDBA_LO, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL); 87062306a36Sopenharmony_ci jwrite32(jme, JME_RXDBA_HI, (__u64)(jme->rxring[0].dma) >> 32); 87162306a36Sopenharmony_ci jwrite32(jme, JME_RXNDA, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci /* 87462306a36Sopenharmony_ci * Setup RX Descriptor Count 87562306a36Sopenharmony_ci */ 87662306a36Sopenharmony_ci jwrite32(jme, JME_RXQDC, jme->rx_ring_size); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci /* 87962306a36Sopenharmony_ci * Setup Unicast Filter 88062306a36Sopenharmony_ci */ 88162306a36Sopenharmony_ci jme_set_unicastaddr(jme->dev); 88262306a36Sopenharmony_ci jme_set_multi(jme->dev); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci /* 88562306a36Sopenharmony_ci * Enable RX Engine 88662306a36Sopenharmony_ci */ 88762306a36Sopenharmony_ci wmb(); 88862306a36Sopenharmony_ci jwrite32f(jme, JME_RXCS, jme->reg_rxcs | 88962306a36Sopenharmony_ci RXCS_QUEUESEL_Q0 | 89062306a36Sopenharmony_ci RXCS_ENABLE | 89162306a36Sopenharmony_ci RXCS_QST); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* 89462306a36Sopenharmony_ci * Start clock for RX MAC Processor 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_ci jme_mac_rxclk_on(jme); 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cistatic inline void 90062306a36Sopenharmony_cijme_restart_rx_engine(struct jme_adapter *jme) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci /* 90362306a36Sopenharmony_ci * Start RX Engine 90462306a36Sopenharmony_ci */ 90562306a36Sopenharmony_ci jwrite32(jme, JME_RXCS, jme->reg_rxcs | 90662306a36Sopenharmony_ci RXCS_QUEUESEL_Q0 | 90762306a36Sopenharmony_ci RXCS_ENABLE | 90862306a36Sopenharmony_ci RXCS_QST); 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_cistatic inline void 91262306a36Sopenharmony_cijme_disable_rx_engine(struct jme_adapter *jme) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci int i; 91562306a36Sopenharmony_ci u32 val; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci /* 91862306a36Sopenharmony_ci * Disable RX Engine 91962306a36Sopenharmony_ci */ 92062306a36Sopenharmony_ci jwrite32(jme, JME_RXCS, jme->reg_rxcs); 92162306a36Sopenharmony_ci wmb(); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci val = jread32(jme, JME_RXCS); 92462306a36Sopenharmony_ci for (i = JME_RX_DISABLE_TIMEOUT ; (val & RXCS_ENABLE) && i > 0 ; --i) { 92562306a36Sopenharmony_ci mdelay(1); 92662306a36Sopenharmony_ci val = jread32(jme, JME_RXCS); 92762306a36Sopenharmony_ci rmb(); 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (!i) 93162306a36Sopenharmony_ci pr_err("Disable RX engine timeout\n"); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* 93462306a36Sopenharmony_ci * Stop clock for RX MAC Processor 93562306a36Sopenharmony_ci */ 93662306a36Sopenharmony_ci jme_mac_rxclk_off(jme); 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cistatic u16 94062306a36Sopenharmony_cijme_udpsum(struct sk_buff *skb) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci u16 csum = 0xFFFFu; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (skb->len < (ETH_HLEN + sizeof(struct iphdr))) 94562306a36Sopenharmony_ci return csum; 94662306a36Sopenharmony_ci if (skb->protocol != htons(ETH_P_IP)) 94762306a36Sopenharmony_ci return csum; 94862306a36Sopenharmony_ci skb_set_network_header(skb, ETH_HLEN); 94962306a36Sopenharmony_ci if ((ip_hdr(skb)->protocol != IPPROTO_UDP) || 95062306a36Sopenharmony_ci (skb->len < (ETH_HLEN + 95162306a36Sopenharmony_ci (ip_hdr(skb)->ihl << 2) + 95262306a36Sopenharmony_ci sizeof(struct udphdr)))) { 95362306a36Sopenharmony_ci skb_reset_network_header(skb); 95462306a36Sopenharmony_ci return csum; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci skb_set_transport_header(skb, 95762306a36Sopenharmony_ci ETH_HLEN + (ip_hdr(skb)->ihl << 2)); 95862306a36Sopenharmony_ci csum = udp_hdr(skb)->check; 95962306a36Sopenharmony_ci skb_reset_transport_header(skb); 96062306a36Sopenharmony_ci skb_reset_network_header(skb); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci return csum; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic int 96662306a36Sopenharmony_cijme_rxsum_ok(struct jme_adapter *jme, u16 flags, struct sk_buff *skb) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci if (!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4))) 96962306a36Sopenharmony_ci return false; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_TCPON | RXWBFLAG_TCPCS)) 97262306a36Sopenharmony_ci == RXWBFLAG_TCPON)) { 97362306a36Sopenharmony_ci if (flags & RXWBFLAG_IPV4) 97462306a36Sopenharmony_ci netif_err(jme, rx_err, jme->dev, "TCP Checksum error\n"); 97562306a36Sopenharmony_ci return false; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS)) 97962306a36Sopenharmony_ci == RXWBFLAG_UDPON) && jme_udpsum(skb)) { 98062306a36Sopenharmony_ci if (flags & RXWBFLAG_IPV4) 98162306a36Sopenharmony_ci netif_err(jme, rx_err, jme->dev, "UDP Checksum error\n"); 98262306a36Sopenharmony_ci return false; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci if (unlikely((flags & (RXWBFLAG_IPV4 | RXWBFLAG_IPCS)) 98662306a36Sopenharmony_ci == RXWBFLAG_IPV4)) { 98762306a36Sopenharmony_ci netif_err(jme, rx_err, jme->dev, "IPv4 Checksum error\n"); 98862306a36Sopenharmony_ci return false; 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci return true; 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cistatic void 99562306a36Sopenharmony_cijme_alloc_and_feed_skb(struct jme_adapter *jme, int idx) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci struct jme_ring *rxring = &(jme->rxring[0]); 99862306a36Sopenharmony_ci struct rxdesc *rxdesc = rxring->desc; 99962306a36Sopenharmony_ci struct jme_buffer_info *rxbi = rxring->bufinf; 100062306a36Sopenharmony_ci struct sk_buff *skb; 100162306a36Sopenharmony_ci int framesize; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci rxdesc += idx; 100462306a36Sopenharmony_ci rxbi += idx; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci skb = rxbi->skb; 100762306a36Sopenharmony_ci dma_sync_single_for_cpu(&jme->pdev->dev, rxbi->mapping, rxbi->len, 100862306a36Sopenharmony_ci DMA_FROM_DEVICE); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci if (unlikely(jme_make_new_rx_buf(jme, idx))) { 101162306a36Sopenharmony_ci dma_sync_single_for_device(&jme->pdev->dev, rxbi->mapping, 101262306a36Sopenharmony_ci rxbi->len, DMA_FROM_DEVICE); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci ++(NET_STAT(jme).rx_dropped); 101562306a36Sopenharmony_ci } else { 101662306a36Sopenharmony_ci framesize = le16_to_cpu(rxdesc->descwb.framesize) 101762306a36Sopenharmony_ci - RX_PREPAD_SIZE; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci skb_reserve(skb, RX_PREPAD_SIZE); 102062306a36Sopenharmony_ci skb_put(skb, framesize); 102162306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, jme->dev); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (jme_rxsum_ok(jme, le16_to_cpu(rxdesc->descwb.flags), skb)) 102462306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 102562306a36Sopenharmony_ci else 102662306a36Sopenharmony_ci skb_checksum_none_assert(skb); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (rxdesc->descwb.flags & cpu_to_le16(RXWBFLAG_TAGON)) { 102962306a36Sopenharmony_ci u16 vid = le16_to_cpu(rxdesc->descwb.vlan); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); 103262306a36Sopenharmony_ci NET_STAT(jme).rx_bytes += 4; 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci jme->jme_rx(skb); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci if ((rxdesc->descwb.flags & cpu_to_le16(RXWBFLAG_DEST)) == 103762306a36Sopenharmony_ci cpu_to_le16(RXWBFLAG_DEST_MUL)) 103862306a36Sopenharmony_ci ++(NET_STAT(jme).multicast); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci NET_STAT(jme).rx_bytes += framesize; 104162306a36Sopenharmony_ci ++(NET_STAT(jme).rx_packets); 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci jme_set_clean_rxdesc(jme, idx); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cistatic int 104962306a36Sopenharmony_cijme_process_receive(struct jme_adapter *jme, int limit) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci struct jme_ring *rxring = &(jme->rxring[0]); 105262306a36Sopenharmony_ci struct rxdesc *rxdesc; 105362306a36Sopenharmony_ci int i, j, ccnt, desccnt, mask = jme->rx_ring_mask; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci if (unlikely(!atomic_dec_and_test(&jme->rx_cleaning))) 105662306a36Sopenharmony_ci goto out_inc; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci if (unlikely(atomic_read(&jme->link_changing) != 1)) 105962306a36Sopenharmony_ci goto out_inc; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (unlikely(!netif_carrier_ok(jme->dev))) 106262306a36Sopenharmony_ci goto out_inc; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci i = atomic_read(&rxring->next_to_clean); 106562306a36Sopenharmony_ci while (limit > 0) { 106662306a36Sopenharmony_ci rxdesc = rxring->desc; 106762306a36Sopenharmony_ci rxdesc += i; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if ((rxdesc->descwb.flags & cpu_to_le16(RXWBFLAG_OWN)) || 107062306a36Sopenharmony_ci !(rxdesc->descwb.desccnt & RXWBDCNT_WBCPL)) 107162306a36Sopenharmony_ci goto out; 107262306a36Sopenharmony_ci --limit; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci rmb(); 107562306a36Sopenharmony_ci desccnt = rxdesc->descwb.desccnt & RXWBDCNT_DCNT; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci if (unlikely(desccnt > 1 || 107862306a36Sopenharmony_ci rxdesc->descwb.errstat & RXWBERR_ALLERR)) { 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (rxdesc->descwb.errstat & RXWBERR_CRCERR) 108162306a36Sopenharmony_ci ++(NET_STAT(jme).rx_crc_errors); 108262306a36Sopenharmony_ci else if (rxdesc->descwb.errstat & RXWBERR_OVERUN) 108362306a36Sopenharmony_ci ++(NET_STAT(jme).rx_fifo_errors); 108462306a36Sopenharmony_ci else 108562306a36Sopenharmony_ci ++(NET_STAT(jme).rx_errors); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (desccnt > 1) 108862306a36Sopenharmony_ci limit -= desccnt - 1; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci for (j = i, ccnt = desccnt ; ccnt-- ; ) { 109162306a36Sopenharmony_ci jme_set_clean_rxdesc(jme, j); 109262306a36Sopenharmony_ci j = (j + 1) & (mask); 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci } else { 109662306a36Sopenharmony_ci jme_alloc_and_feed_skb(jme, i); 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci i = (i + desccnt) & (mask); 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ciout: 110362306a36Sopenharmony_ci atomic_set(&rxring->next_to_clean, i); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ciout_inc: 110662306a36Sopenharmony_ci atomic_inc(&jme->rx_cleaning); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci return limit > 0 ? limit : 0; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci} 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_cistatic void 111362306a36Sopenharmony_cijme_attempt_pcc(struct dynpcc_info *dpi, int atmp) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci if (likely(atmp == dpi->cur)) { 111662306a36Sopenharmony_ci dpi->cnt = 0; 111762306a36Sopenharmony_ci return; 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci if (dpi->attempt == atmp) { 112162306a36Sopenharmony_ci ++(dpi->cnt); 112262306a36Sopenharmony_ci } else { 112362306a36Sopenharmony_ci dpi->attempt = atmp; 112462306a36Sopenharmony_ci dpi->cnt = 0; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic void 113062306a36Sopenharmony_cijme_dynamic_pcc(struct jme_adapter *jme) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci register struct dynpcc_info *dpi = &(jme->dpi); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if ((NET_STAT(jme).rx_bytes - dpi->last_bytes) > PCC_P3_THRESHOLD) 113562306a36Sopenharmony_ci jme_attempt_pcc(dpi, PCC_P3); 113662306a36Sopenharmony_ci else if ((NET_STAT(jme).rx_packets - dpi->last_pkts) > PCC_P2_THRESHOLD || 113762306a36Sopenharmony_ci dpi->intr_cnt > PCC_INTR_THRESHOLD) 113862306a36Sopenharmony_ci jme_attempt_pcc(dpi, PCC_P2); 113962306a36Sopenharmony_ci else 114062306a36Sopenharmony_ci jme_attempt_pcc(dpi, PCC_P1); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci if (unlikely(dpi->attempt != dpi->cur && dpi->cnt > 5)) { 114362306a36Sopenharmony_ci if (dpi->attempt < dpi->cur) 114462306a36Sopenharmony_ci tasklet_schedule(&jme->rxclean_task); 114562306a36Sopenharmony_ci jme_set_rx_pcc(jme, dpi->attempt); 114662306a36Sopenharmony_ci dpi->cur = dpi->attempt; 114762306a36Sopenharmony_ci dpi->cnt = 0; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci} 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_cistatic void 115262306a36Sopenharmony_cijme_start_pcc_timer(struct jme_adapter *jme) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci struct dynpcc_info *dpi = &(jme->dpi); 115562306a36Sopenharmony_ci dpi->last_bytes = NET_STAT(jme).rx_bytes; 115662306a36Sopenharmony_ci dpi->last_pkts = NET_STAT(jme).rx_packets; 115762306a36Sopenharmony_ci dpi->intr_cnt = 0; 115862306a36Sopenharmony_ci jwrite32(jme, JME_TMCSR, 115962306a36Sopenharmony_ci TMCSR_EN | ((0xFFFFFF - PCC_INTERVAL_US) & TMCSR_CNT)); 116062306a36Sopenharmony_ci} 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_cistatic inline void 116362306a36Sopenharmony_cijme_stop_pcc_timer(struct jme_adapter *jme) 116462306a36Sopenharmony_ci{ 116562306a36Sopenharmony_ci jwrite32(jme, JME_TMCSR, 0); 116662306a36Sopenharmony_ci} 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_cistatic void 116962306a36Sopenharmony_cijme_shutdown_nic(struct jme_adapter *jme) 117062306a36Sopenharmony_ci{ 117162306a36Sopenharmony_ci u32 phylink; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci phylink = jme_linkstat_from_phy(jme); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (!(phylink & PHY_LINK_UP)) { 117662306a36Sopenharmony_ci /* 117762306a36Sopenharmony_ci * Disable all interrupt before issue timer 117862306a36Sopenharmony_ci */ 117962306a36Sopenharmony_ci jme_stop_irq(jme); 118062306a36Sopenharmony_ci jwrite32(jme, JME_TIMER2, TMCSR_EN | 0xFFFFFE); 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_cistatic void 118562306a36Sopenharmony_cijme_pcc_tasklet(struct tasklet_struct *t) 118662306a36Sopenharmony_ci{ 118762306a36Sopenharmony_ci struct jme_adapter *jme = from_tasklet(jme, t, pcc_task); 118862306a36Sopenharmony_ci struct net_device *netdev = jme->dev; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci if (unlikely(test_bit(JME_FLAG_SHUTDOWN, &jme->flags))) { 119162306a36Sopenharmony_ci jme_shutdown_nic(jme); 119262306a36Sopenharmony_ci return; 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (unlikely(!netif_carrier_ok(netdev) || 119662306a36Sopenharmony_ci (atomic_read(&jme->link_changing) != 1) 119762306a36Sopenharmony_ci )) { 119862306a36Sopenharmony_ci jme_stop_pcc_timer(jme); 119962306a36Sopenharmony_ci return; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (!(test_bit(JME_FLAG_POLL, &jme->flags))) 120362306a36Sopenharmony_ci jme_dynamic_pcc(jme); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci jme_start_pcc_timer(jme); 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cistatic inline void 120962306a36Sopenharmony_cijme_polling_mode(struct jme_adapter *jme) 121062306a36Sopenharmony_ci{ 121162306a36Sopenharmony_ci jme_set_rx_pcc(jme, PCC_OFF); 121262306a36Sopenharmony_ci} 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_cistatic inline void 121562306a36Sopenharmony_cijme_interrupt_mode(struct jme_adapter *jme) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci jme_set_rx_pcc(jme, PCC_P1); 121862306a36Sopenharmony_ci} 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_cistatic inline int 122162306a36Sopenharmony_cijme_pseudo_hotplug_enabled(struct jme_adapter *jme) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci u32 apmc; 122462306a36Sopenharmony_ci apmc = jread32(jme, JME_APMC); 122562306a36Sopenharmony_ci return apmc & JME_APMC_PSEUDO_HP_EN; 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic void 122962306a36Sopenharmony_cijme_start_shutdown_timer(struct jme_adapter *jme) 123062306a36Sopenharmony_ci{ 123162306a36Sopenharmony_ci u32 apmc; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci apmc = jread32(jme, JME_APMC) | JME_APMC_PCIE_SD_EN; 123462306a36Sopenharmony_ci apmc &= ~JME_APMC_EPIEN_CTRL; 123562306a36Sopenharmony_ci if (!no_extplug) { 123662306a36Sopenharmony_ci jwrite32f(jme, JME_APMC, apmc | JME_APMC_EPIEN_CTRL_EN); 123762306a36Sopenharmony_ci wmb(); 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci jwrite32f(jme, JME_APMC, apmc); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci jwrite32f(jme, JME_TIMER2, 0); 124262306a36Sopenharmony_ci set_bit(JME_FLAG_SHUTDOWN, &jme->flags); 124362306a36Sopenharmony_ci jwrite32(jme, JME_TMCSR, 124462306a36Sopenharmony_ci TMCSR_EN | ((0xFFFFFF - APMC_PHP_SHUTDOWN_DELAY) & TMCSR_CNT)); 124562306a36Sopenharmony_ci} 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_cistatic void 124862306a36Sopenharmony_cijme_stop_shutdown_timer(struct jme_adapter *jme) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci u32 apmc; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci jwrite32f(jme, JME_TMCSR, 0); 125362306a36Sopenharmony_ci jwrite32f(jme, JME_TIMER2, 0); 125462306a36Sopenharmony_ci clear_bit(JME_FLAG_SHUTDOWN, &jme->flags); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci apmc = jread32(jme, JME_APMC); 125762306a36Sopenharmony_ci apmc &= ~(JME_APMC_PCIE_SD_EN | JME_APMC_EPIEN_CTRL); 125862306a36Sopenharmony_ci jwrite32f(jme, JME_APMC, apmc | JME_APMC_EPIEN_CTRL_DIS); 125962306a36Sopenharmony_ci wmb(); 126062306a36Sopenharmony_ci jwrite32f(jme, JME_APMC, apmc); 126162306a36Sopenharmony_ci} 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_cistatic void jme_link_change_work(struct work_struct *work) 126462306a36Sopenharmony_ci{ 126562306a36Sopenharmony_ci struct jme_adapter *jme = container_of(work, struct jme_adapter, linkch_task); 126662306a36Sopenharmony_ci struct net_device *netdev = jme->dev; 126762306a36Sopenharmony_ci int rc; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci while (!atomic_dec_and_test(&jme->link_changing)) { 127062306a36Sopenharmony_ci atomic_inc(&jme->link_changing); 127162306a36Sopenharmony_ci netif_info(jme, intr, jme->dev, "Get link change lock failed\n"); 127262306a36Sopenharmony_ci while (atomic_read(&jme->link_changing) != 1) 127362306a36Sopenharmony_ci netif_info(jme, intr, jme->dev, "Waiting link change lock\n"); 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci if (jme_check_link(netdev, 1) && jme->old_mtu == netdev->mtu) 127762306a36Sopenharmony_ci goto out; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci jme->old_mtu = netdev->mtu; 128062306a36Sopenharmony_ci netif_stop_queue(netdev); 128162306a36Sopenharmony_ci if (jme_pseudo_hotplug_enabled(jme)) 128262306a36Sopenharmony_ci jme_stop_shutdown_timer(jme); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci jme_stop_pcc_timer(jme); 128562306a36Sopenharmony_ci tasklet_disable(&jme->txclean_task); 128662306a36Sopenharmony_ci tasklet_disable(&jme->rxclean_task); 128762306a36Sopenharmony_ci tasklet_disable(&jme->rxempty_task); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci if (netif_carrier_ok(netdev)) { 129062306a36Sopenharmony_ci jme_disable_rx_engine(jme); 129162306a36Sopenharmony_ci jme_disable_tx_engine(jme); 129262306a36Sopenharmony_ci jme_reset_mac_processor(jme); 129362306a36Sopenharmony_ci jme_free_rx_resources(jme); 129462306a36Sopenharmony_ci jme_free_tx_resources(jme); 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci if (test_bit(JME_FLAG_POLL, &jme->flags)) 129762306a36Sopenharmony_ci jme_polling_mode(jme); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci netif_carrier_off(netdev); 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci jme_check_link(netdev, 0); 130362306a36Sopenharmony_ci if (netif_carrier_ok(netdev)) { 130462306a36Sopenharmony_ci rc = jme_setup_rx_resources(jme); 130562306a36Sopenharmony_ci if (rc) { 130662306a36Sopenharmony_ci pr_err("Allocating resources for RX error, Device STOPPED!\n"); 130762306a36Sopenharmony_ci goto out_enable_tasklet; 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci rc = jme_setup_tx_resources(jme); 131162306a36Sopenharmony_ci if (rc) { 131262306a36Sopenharmony_ci pr_err("Allocating resources for TX error, Device STOPPED!\n"); 131362306a36Sopenharmony_ci goto err_out_free_rx_resources; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci jme_enable_rx_engine(jme); 131762306a36Sopenharmony_ci jme_enable_tx_engine(jme); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci netif_start_queue(netdev); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci if (test_bit(JME_FLAG_POLL, &jme->flags)) 132262306a36Sopenharmony_ci jme_interrupt_mode(jme); 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci jme_start_pcc_timer(jme); 132562306a36Sopenharmony_ci } else if (jme_pseudo_hotplug_enabled(jme)) { 132662306a36Sopenharmony_ci jme_start_shutdown_timer(jme); 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci goto out_enable_tasklet; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_cierr_out_free_rx_resources: 133262306a36Sopenharmony_ci jme_free_rx_resources(jme); 133362306a36Sopenharmony_ciout_enable_tasklet: 133462306a36Sopenharmony_ci tasklet_enable(&jme->txclean_task); 133562306a36Sopenharmony_ci tasklet_enable(&jme->rxclean_task); 133662306a36Sopenharmony_ci tasklet_enable(&jme->rxempty_task); 133762306a36Sopenharmony_ciout: 133862306a36Sopenharmony_ci atomic_inc(&jme->link_changing); 133962306a36Sopenharmony_ci} 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_cistatic void 134262306a36Sopenharmony_cijme_rx_clean_tasklet(struct tasklet_struct *t) 134362306a36Sopenharmony_ci{ 134462306a36Sopenharmony_ci struct jme_adapter *jme = from_tasklet(jme, t, rxclean_task); 134562306a36Sopenharmony_ci struct dynpcc_info *dpi = &(jme->dpi); 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci jme_process_receive(jme, jme->rx_ring_size); 134862306a36Sopenharmony_ci ++(dpi->intr_cnt); 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci} 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_cistatic int 135362306a36Sopenharmony_cijme_poll(JME_NAPI_HOLDER(holder), JME_NAPI_WEIGHT(budget)) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci struct jme_adapter *jme = jme_napi_priv(holder); 135662306a36Sopenharmony_ci int rest; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci rest = jme_process_receive(jme, JME_NAPI_WEIGHT_VAL(budget)); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci while (atomic_read(&jme->rx_empty) > 0) { 136162306a36Sopenharmony_ci atomic_dec(&jme->rx_empty); 136262306a36Sopenharmony_ci ++(NET_STAT(jme).rx_dropped); 136362306a36Sopenharmony_ci jme_restart_rx_engine(jme); 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci atomic_inc(&jme->rx_empty); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci if (rest) { 136862306a36Sopenharmony_ci JME_RX_COMPLETE(netdev, holder); 136962306a36Sopenharmony_ci jme_interrupt_mode(jme); 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci JME_NAPI_WEIGHT_SET(budget, rest); 137362306a36Sopenharmony_ci return JME_NAPI_WEIGHT_VAL(budget) - rest; 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_cistatic void 137762306a36Sopenharmony_cijme_rx_empty_tasklet(struct tasklet_struct *t) 137862306a36Sopenharmony_ci{ 137962306a36Sopenharmony_ci struct jme_adapter *jme = from_tasklet(jme, t, rxempty_task); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci if (unlikely(atomic_read(&jme->link_changing) != 1)) 138262306a36Sopenharmony_ci return; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci if (unlikely(!netif_carrier_ok(jme->dev))) 138562306a36Sopenharmony_ci return; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci netif_info(jme, rx_status, jme->dev, "RX Queue Full!\n"); 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci jme_rx_clean_tasklet(&jme->rxclean_task); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci while (atomic_read(&jme->rx_empty) > 0) { 139262306a36Sopenharmony_ci atomic_dec(&jme->rx_empty); 139362306a36Sopenharmony_ci ++(NET_STAT(jme).rx_dropped); 139462306a36Sopenharmony_ci jme_restart_rx_engine(jme); 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci atomic_inc(&jme->rx_empty); 139762306a36Sopenharmony_ci} 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_cistatic void 140062306a36Sopenharmony_cijme_wake_queue_if_stopped(struct jme_adapter *jme) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci struct jme_ring *txring = &(jme->txring[0]); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci smp_wmb(); 140562306a36Sopenharmony_ci if (unlikely(netif_queue_stopped(jme->dev) && 140662306a36Sopenharmony_ci atomic_read(&txring->nr_free) >= (jme->tx_wake_threshold))) { 140762306a36Sopenharmony_ci netif_info(jme, tx_done, jme->dev, "TX Queue Waked\n"); 140862306a36Sopenharmony_ci netif_wake_queue(jme->dev); 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_cistatic void jme_tx_clean_tasklet(struct tasklet_struct *t) 141462306a36Sopenharmony_ci{ 141562306a36Sopenharmony_ci struct jme_adapter *jme = from_tasklet(jme, t, txclean_task); 141662306a36Sopenharmony_ci struct jme_ring *txring = &(jme->txring[0]); 141762306a36Sopenharmony_ci struct txdesc *txdesc = txring->desc; 141862306a36Sopenharmony_ci struct jme_buffer_info *txbi = txring->bufinf, *ctxbi, *ttxbi; 141962306a36Sopenharmony_ci int i, j, cnt = 0, max, err, mask; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci tx_dbg(jme, "Into txclean\n"); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci if (unlikely(!atomic_dec_and_test(&jme->tx_cleaning))) 142462306a36Sopenharmony_ci goto out; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if (unlikely(atomic_read(&jme->link_changing) != 1)) 142762306a36Sopenharmony_ci goto out; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci if (unlikely(!netif_carrier_ok(jme->dev))) 143062306a36Sopenharmony_ci goto out; 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci max = jme->tx_ring_size - atomic_read(&txring->nr_free); 143362306a36Sopenharmony_ci mask = jme->tx_ring_mask; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci for (i = atomic_read(&txring->next_to_clean) ; cnt < max ; ) { 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci ctxbi = txbi + i; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (likely(ctxbi->skb && 144062306a36Sopenharmony_ci !(txdesc[i].descwb.flags & TXWBFLAG_OWN))) { 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci tx_dbg(jme, "txclean: %d+%d@%lu\n", 144362306a36Sopenharmony_ci i, ctxbi->nr_desc, jiffies); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci err = txdesc[i].descwb.flags & TXWBFLAG_ALLERR; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci for (j = 1 ; j < ctxbi->nr_desc ; ++j) { 144862306a36Sopenharmony_ci ttxbi = txbi + ((i + j) & (mask)); 144962306a36Sopenharmony_ci txdesc[(i + j) & (mask)].dw[0] = 0; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci dma_unmap_page(&jme->pdev->dev, 145262306a36Sopenharmony_ci ttxbi->mapping, ttxbi->len, 145362306a36Sopenharmony_ci DMA_TO_DEVICE); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci ttxbi->mapping = 0; 145662306a36Sopenharmony_ci ttxbi->len = 0; 145762306a36Sopenharmony_ci } 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci dev_kfree_skb(ctxbi->skb); 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci cnt += ctxbi->nr_desc; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci if (unlikely(err)) { 146462306a36Sopenharmony_ci ++(NET_STAT(jme).tx_carrier_errors); 146562306a36Sopenharmony_ci } else { 146662306a36Sopenharmony_ci ++(NET_STAT(jme).tx_packets); 146762306a36Sopenharmony_ci NET_STAT(jme).tx_bytes += ctxbi->len; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci ctxbi->skb = NULL; 147162306a36Sopenharmony_ci ctxbi->len = 0; 147262306a36Sopenharmony_ci ctxbi->start_xmit = 0; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci } else { 147562306a36Sopenharmony_ci break; 147662306a36Sopenharmony_ci } 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci i = (i + ctxbi->nr_desc) & mask; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci ctxbi->nr_desc = 0; 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci tx_dbg(jme, "txclean: done %d@%lu\n", i, jiffies); 148462306a36Sopenharmony_ci atomic_set(&txring->next_to_clean, i); 148562306a36Sopenharmony_ci atomic_add(cnt, &txring->nr_free); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci jme_wake_queue_if_stopped(jme); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ciout: 149062306a36Sopenharmony_ci atomic_inc(&jme->tx_cleaning); 149162306a36Sopenharmony_ci} 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_cistatic void 149462306a36Sopenharmony_cijme_intr_msi(struct jme_adapter *jme, u32 intrstat) 149562306a36Sopenharmony_ci{ 149662306a36Sopenharmony_ci /* 149762306a36Sopenharmony_ci * Disable interrupt 149862306a36Sopenharmony_ci */ 149962306a36Sopenharmony_ci jwrite32f(jme, JME_IENC, INTR_ENABLE); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci if (intrstat & (INTR_LINKCH | INTR_SWINTR)) { 150262306a36Sopenharmony_ci /* 150362306a36Sopenharmony_ci * Link change event is critical 150462306a36Sopenharmony_ci * all other events are ignored 150562306a36Sopenharmony_ci */ 150662306a36Sopenharmony_ci jwrite32(jme, JME_IEVE, intrstat); 150762306a36Sopenharmony_ci schedule_work(&jme->linkch_task); 150862306a36Sopenharmony_ci goto out_reenable; 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci if (intrstat & INTR_TMINTR) { 151262306a36Sopenharmony_ci jwrite32(jme, JME_IEVE, INTR_TMINTR); 151362306a36Sopenharmony_ci tasklet_schedule(&jme->pcc_task); 151462306a36Sopenharmony_ci } 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci if (intrstat & (INTR_PCCTXTO | INTR_PCCTX)) { 151762306a36Sopenharmony_ci jwrite32(jme, JME_IEVE, INTR_PCCTXTO | INTR_PCCTX | INTR_TX0); 151862306a36Sopenharmony_ci tasklet_schedule(&jme->txclean_task); 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci if ((intrstat & (INTR_PCCRX0TO | INTR_PCCRX0 | INTR_RX0EMP))) { 152262306a36Sopenharmony_ci jwrite32(jme, JME_IEVE, (intrstat & (INTR_PCCRX0TO | 152362306a36Sopenharmony_ci INTR_PCCRX0 | 152462306a36Sopenharmony_ci INTR_RX0EMP)) | 152562306a36Sopenharmony_ci INTR_RX0); 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci if (test_bit(JME_FLAG_POLL, &jme->flags)) { 152962306a36Sopenharmony_ci if (intrstat & INTR_RX0EMP) 153062306a36Sopenharmony_ci atomic_inc(&jme->rx_empty); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci if ((intrstat & (INTR_PCCRX0TO | INTR_PCCRX0 | INTR_RX0EMP))) { 153362306a36Sopenharmony_ci if (likely(JME_RX_SCHEDULE_PREP(jme))) { 153462306a36Sopenharmony_ci jme_polling_mode(jme); 153562306a36Sopenharmony_ci JME_RX_SCHEDULE(jme); 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci } else { 153962306a36Sopenharmony_ci if (intrstat & INTR_RX0EMP) { 154062306a36Sopenharmony_ci atomic_inc(&jme->rx_empty); 154162306a36Sopenharmony_ci tasklet_hi_schedule(&jme->rxempty_task); 154262306a36Sopenharmony_ci } else if (intrstat & (INTR_PCCRX0TO | INTR_PCCRX0)) { 154362306a36Sopenharmony_ci tasklet_hi_schedule(&jme->rxclean_task); 154462306a36Sopenharmony_ci } 154562306a36Sopenharmony_ci } 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ciout_reenable: 154862306a36Sopenharmony_ci /* 154962306a36Sopenharmony_ci * Re-enable interrupt 155062306a36Sopenharmony_ci */ 155162306a36Sopenharmony_ci jwrite32f(jme, JME_IENS, INTR_ENABLE); 155262306a36Sopenharmony_ci} 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_cistatic irqreturn_t 155562306a36Sopenharmony_cijme_intr(int irq, void *dev_id) 155662306a36Sopenharmony_ci{ 155762306a36Sopenharmony_ci struct net_device *netdev = dev_id; 155862306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 155962306a36Sopenharmony_ci u32 intrstat; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci intrstat = jread32(jme, JME_IEVE); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci /* 156462306a36Sopenharmony_ci * Check if it's really an interrupt for us 156562306a36Sopenharmony_ci */ 156662306a36Sopenharmony_ci if (unlikely((intrstat & INTR_ENABLE) == 0)) 156762306a36Sopenharmony_ci return IRQ_NONE; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci /* 157062306a36Sopenharmony_ci * Check if the device still exist 157162306a36Sopenharmony_ci */ 157262306a36Sopenharmony_ci if (unlikely(intrstat == ~((typeof(intrstat))0))) 157362306a36Sopenharmony_ci return IRQ_NONE; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci jme_intr_msi(jme, intrstat); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci return IRQ_HANDLED; 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_cistatic irqreturn_t 158162306a36Sopenharmony_cijme_msi(int irq, void *dev_id) 158262306a36Sopenharmony_ci{ 158362306a36Sopenharmony_ci struct net_device *netdev = dev_id; 158462306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 158562306a36Sopenharmony_ci u32 intrstat; 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci intrstat = jread32(jme, JME_IEVE); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci jme_intr_msi(jme, intrstat); 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci return IRQ_HANDLED; 159262306a36Sopenharmony_ci} 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_cistatic void 159562306a36Sopenharmony_cijme_reset_link(struct jme_adapter *jme) 159662306a36Sopenharmony_ci{ 159762306a36Sopenharmony_ci jwrite32(jme, JME_TMCSR, TMCSR_SWIT); 159862306a36Sopenharmony_ci} 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_cistatic void 160162306a36Sopenharmony_cijme_restart_an(struct jme_adapter *jme) 160262306a36Sopenharmony_ci{ 160362306a36Sopenharmony_ci u32 bmcr; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci spin_lock_bh(&jme->phy_lock); 160662306a36Sopenharmony_ci bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR); 160762306a36Sopenharmony_ci bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); 160862306a36Sopenharmony_ci jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr); 160962306a36Sopenharmony_ci spin_unlock_bh(&jme->phy_lock); 161062306a36Sopenharmony_ci} 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_cistatic int 161362306a36Sopenharmony_cijme_request_irq(struct jme_adapter *jme) 161462306a36Sopenharmony_ci{ 161562306a36Sopenharmony_ci int rc; 161662306a36Sopenharmony_ci struct net_device *netdev = jme->dev; 161762306a36Sopenharmony_ci irq_handler_t handler = jme_intr; 161862306a36Sopenharmony_ci int irq_flags = IRQF_SHARED; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci if (!pci_enable_msi(jme->pdev)) { 162162306a36Sopenharmony_ci set_bit(JME_FLAG_MSI, &jme->flags); 162262306a36Sopenharmony_ci handler = jme_msi; 162362306a36Sopenharmony_ci irq_flags = 0; 162462306a36Sopenharmony_ci } 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci rc = request_irq(jme->pdev->irq, handler, irq_flags, netdev->name, 162762306a36Sopenharmony_ci netdev); 162862306a36Sopenharmony_ci if (rc) { 162962306a36Sopenharmony_ci netdev_err(netdev, 163062306a36Sopenharmony_ci "Unable to request %s interrupt (return: %d)\n", 163162306a36Sopenharmony_ci test_bit(JME_FLAG_MSI, &jme->flags) ? "MSI" : "INTx", 163262306a36Sopenharmony_ci rc); 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci if (test_bit(JME_FLAG_MSI, &jme->flags)) { 163562306a36Sopenharmony_ci pci_disable_msi(jme->pdev); 163662306a36Sopenharmony_ci clear_bit(JME_FLAG_MSI, &jme->flags); 163762306a36Sopenharmony_ci } 163862306a36Sopenharmony_ci } else { 163962306a36Sopenharmony_ci netdev->irq = jme->pdev->irq; 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci return rc; 164362306a36Sopenharmony_ci} 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_cistatic void 164662306a36Sopenharmony_cijme_free_irq(struct jme_adapter *jme) 164762306a36Sopenharmony_ci{ 164862306a36Sopenharmony_ci free_irq(jme->pdev->irq, jme->dev); 164962306a36Sopenharmony_ci if (test_bit(JME_FLAG_MSI, &jme->flags)) { 165062306a36Sopenharmony_ci pci_disable_msi(jme->pdev); 165162306a36Sopenharmony_ci clear_bit(JME_FLAG_MSI, &jme->flags); 165262306a36Sopenharmony_ci jme->dev->irq = jme->pdev->irq; 165362306a36Sopenharmony_ci } 165462306a36Sopenharmony_ci} 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_cistatic inline void 165762306a36Sopenharmony_cijme_new_phy_on(struct jme_adapter *jme) 165862306a36Sopenharmony_ci{ 165962306a36Sopenharmony_ci u32 reg; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci reg = jread32(jme, JME_PHY_PWR); 166262306a36Sopenharmony_ci reg &= ~(PHY_PWR_DWN1SEL | PHY_PWR_DWN1SW | 166362306a36Sopenharmony_ci PHY_PWR_DWN2 | PHY_PWR_CLKSEL); 166462306a36Sopenharmony_ci jwrite32(jme, JME_PHY_PWR, reg); 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci pci_read_config_dword(jme->pdev, PCI_PRIV_PE1, ®); 166762306a36Sopenharmony_ci reg &= ~PE1_GPREG0_PBG; 166862306a36Sopenharmony_ci reg |= PE1_GPREG0_ENBG; 166962306a36Sopenharmony_ci pci_write_config_dword(jme->pdev, PCI_PRIV_PE1, reg); 167062306a36Sopenharmony_ci} 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_cistatic inline void 167362306a36Sopenharmony_cijme_new_phy_off(struct jme_adapter *jme) 167462306a36Sopenharmony_ci{ 167562306a36Sopenharmony_ci u32 reg; 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci reg = jread32(jme, JME_PHY_PWR); 167862306a36Sopenharmony_ci reg |= PHY_PWR_DWN1SEL | PHY_PWR_DWN1SW | 167962306a36Sopenharmony_ci PHY_PWR_DWN2 | PHY_PWR_CLKSEL; 168062306a36Sopenharmony_ci jwrite32(jme, JME_PHY_PWR, reg); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci pci_read_config_dword(jme->pdev, PCI_PRIV_PE1, ®); 168362306a36Sopenharmony_ci reg &= ~PE1_GPREG0_PBG; 168462306a36Sopenharmony_ci reg |= PE1_GPREG0_PDD3COLD; 168562306a36Sopenharmony_ci pci_write_config_dword(jme->pdev, PCI_PRIV_PE1, reg); 168662306a36Sopenharmony_ci} 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_cistatic inline void 168962306a36Sopenharmony_cijme_phy_on(struct jme_adapter *jme) 169062306a36Sopenharmony_ci{ 169162306a36Sopenharmony_ci u32 bmcr; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR); 169462306a36Sopenharmony_ci bmcr &= ~BMCR_PDOWN; 169562306a36Sopenharmony_ci jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr); 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci if (new_phy_power_ctrl(jme->chip_main_rev)) 169862306a36Sopenharmony_ci jme_new_phy_on(jme); 169962306a36Sopenharmony_ci} 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_cistatic inline void 170262306a36Sopenharmony_cijme_phy_off(struct jme_adapter *jme) 170362306a36Sopenharmony_ci{ 170462306a36Sopenharmony_ci u32 bmcr; 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR); 170762306a36Sopenharmony_ci bmcr |= BMCR_PDOWN; 170862306a36Sopenharmony_ci jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr); 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci if (new_phy_power_ctrl(jme->chip_main_rev)) 171162306a36Sopenharmony_ci jme_new_phy_off(jme); 171262306a36Sopenharmony_ci} 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_cistatic int 171562306a36Sopenharmony_cijme_phy_specreg_read(struct jme_adapter *jme, u32 specreg) 171662306a36Sopenharmony_ci{ 171762306a36Sopenharmony_ci u32 phy_addr; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci phy_addr = JM_PHY_SPEC_REG_READ | specreg; 172062306a36Sopenharmony_ci jme_mdio_write(jme->dev, jme->mii_if.phy_id, JM_PHY_SPEC_ADDR_REG, 172162306a36Sopenharmony_ci phy_addr); 172262306a36Sopenharmony_ci return jme_mdio_read(jme->dev, jme->mii_if.phy_id, 172362306a36Sopenharmony_ci JM_PHY_SPEC_DATA_REG); 172462306a36Sopenharmony_ci} 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_cistatic void 172762306a36Sopenharmony_cijme_phy_specreg_write(struct jme_adapter *jme, u32 ext_reg, u32 phy_data) 172862306a36Sopenharmony_ci{ 172962306a36Sopenharmony_ci u32 phy_addr; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci phy_addr = JM_PHY_SPEC_REG_WRITE | ext_reg; 173262306a36Sopenharmony_ci jme_mdio_write(jme->dev, jme->mii_if.phy_id, JM_PHY_SPEC_DATA_REG, 173362306a36Sopenharmony_ci phy_data); 173462306a36Sopenharmony_ci jme_mdio_write(jme->dev, jme->mii_if.phy_id, JM_PHY_SPEC_ADDR_REG, 173562306a36Sopenharmony_ci phy_addr); 173662306a36Sopenharmony_ci} 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_cistatic int 173962306a36Sopenharmony_cijme_phy_calibration(struct jme_adapter *jme) 174062306a36Sopenharmony_ci{ 174162306a36Sopenharmony_ci u32 ctrl1000, phy_data; 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci jme_phy_off(jme); 174462306a36Sopenharmony_ci jme_phy_on(jme); 174562306a36Sopenharmony_ci /* Enabel PHY test mode 1 */ 174662306a36Sopenharmony_ci ctrl1000 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_CTRL1000); 174762306a36Sopenharmony_ci ctrl1000 &= ~PHY_GAD_TEST_MODE_MSK; 174862306a36Sopenharmony_ci ctrl1000 |= PHY_GAD_TEST_MODE_1; 174962306a36Sopenharmony_ci jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_CTRL1000, ctrl1000); 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci phy_data = jme_phy_specreg_read(jme, JM_PHY_EXT_COMM_2_REG); 175262306a36Sopenharmony_ci phy_data &= ~JM_PHY_EXT_COMM_2_CALI_MODE_0; 175362306a36Sopenharmony_ci phy_data |= JM_PHY_EXT_COMM_2_CALI_LATCH | 175462306a36Sopenharmony_ci JM_PHY_EXT_COMM_2_CALI_ENABLE; 175562306a36Sopenharmony_ci jme_phy_specreg_write(jme, JM_PHY_EXT_COMM_2_REG, phy_data); 175662306a36Sopenharmony_ci msleep(20); 175762306a36Sopenharmony_ci phy_data = jme_phy_specreg_read(jme, JM_PHY_EXT_COMM_2_REG); 175862306a36Sopenharmony_ci phy_data &= ~(JM_PHY_EXT_COMM_2_CALI_ENABLE | 175962306a36Sopenharmony_ci JM_PHY_EXT_COMM_2_CALI_MODE_0 | 176062306a36Sopenharmony_ci JM_PHY_EXT_COMM_2_CALI_LATCH); 176162306a36Sopenharmony_ci jme_phy_specreg_write(jme, JM_PHY_EXT_COMM_2_REG, phy_data); 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci /* Disable PHY test mode */ 176462306a36Sopenharmony_ci ctrl1000 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_CTRL1000); 176562306a36Sopenharmony_ci ctrl1000 &= ~PHY_GAD_TEST_MODE_MSK; 176662306a36Sopenharmony_ci jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_CTRL1000, ctrl1000); 176762306a36Sopenharmony_ci return 0; 176862306a36Sopenharmony_ci} 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_cistatic int 177162306a36Sopenharmony_cijme_phy_setEA(struct jme_adapter *jme) 177262306a36Sopenharmony_ci{ 177362306a36Sopenharmony_ci u32 phy_comm0 = 0, phy_comm1 = 0; 177462306a36Sopenharmony_ci u8 nic_ctrl; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci pci_read_config_byte(jme->pdev, PCI_PRIV_SHARE_NICCTRL, &nic_ctrl); 177762306a36Sopenharmony_ci if ((nic_ctrl & 0x3) == JME_FLAG_PHYEA_ENABLE) 177862306a36Sopenharmony_ci return 0; 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci switch (jme->pdev->device) { 178162306a36Sopenharmony_ci case PCI_DEVICE_ID_JMICRON_JMC250: 178262306a36Sopenharmony_ci if (((jme->chip_main_rev == 5) && 178362306a36Sopenharmony_ci ((jme->chip_sub_rev == 0) || (jme->chip_sub_rev == 1) || 178462306a36Sopenharmony_ci (jme->chip_sub_rev == 3))) || 178562306a36Sopenharmony_ci (jme->chip_main_rev >= 6)) { 178662306a36Sopenharmony_ci phy_comm0 = 0x008A; 178762306a36Sopenharmony_ci phy_comm1 = 0x4109; 178862306a36Sopenharmony_ci } 178962306a36Sopenharmony_ci if ((jme->chip_main_rev == 3) && 179062306a36Sopenharmony_ci ((jme->chip_sub_rev == 1) || (jme->chip_sub_rev == 2))) 179162306a36Sopenharmony_ci phy_comm0 = 0xE088; 179262306a36Sopenharmony_ci break; 179362306a36Sopenharmony_ci case PCI_DEVICE_ID_JMICRON_JMC260: 179462306a36Sopenharmony_ci if (((jme->chip_main_rev == 5) && 179562306a36Sopenharmony_ci ((jme->chip_sub_rev == 0) || (jme->chip_sub_rev == 1) || 179662306a36Sopenharmony_ci (jme->chip_sub_rev == 3))) || 179762306a36Sopenharmony_ci (jme->chip_main_rev >= 6)) { 179862306a36Sopenharmony_ci phy_comm0 = 0x008A; 179962306a36Sopenharmony_ci phy_comm1 = 0x4109; 180062306a36Sopenharmony_ci } 180162306a36Sopenharmony_ci if ((jme->chip_main_rev == 3) && 180262306a36Sopenharmony_ci ((jme->chip_sub_rev == 1) || (jme->chip_sub_rev == 2))) 180362306a36Sopenharmony_ci phy_comm0 = 0xE088; 180462306a36Sopenharmony_ci if ((jme->chip_main_rev == 2) && (jme->chip_sub_rev == 0)) 180562306a36Sopenharmony_ci phy_comm0 = 0x608A; 180662306a36Sopenharmony_ci if ((jme->chip_main_rev == 2) && (jme->chip_sub_rev == 2)) 180762306a36Sopenharmony_ci phy_comm0 = 0x408A; 180862306a36Sopenharmony_ci break; 180962306a36Sopenharmony_ci default: 181062306a36Sopenharmony_ci return -ENODEV; 181162306a36Sopenharmony_ci } 181262306a36Sopenharmony_ci if (phy_comm0) 181362306a36Sopenharmony_ci jme_phy_specreg_write(jme, JM_PHY_EXT_COMM_0_REG, phy_comm0); 181462306a36Sopenharmony_ci if (phy_comm1) 181562306a36Sopenharmony_ci jme_phy_specreg_write(jme, JM_PHY_EXT_COMM_1_REG, phy_comm1); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci return 0; 181862306a36Sopenharmony_ci} 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_cistatic int 182162306a36Sopenharmony_cijme_open(struct net_device *netdev) 182262306a36Sopenharmony_ci{ 182362306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 182462306a36Sopenharmony_ci int rc; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci jme_clear_pm_disable_wol(jme); 182762306a36Sopenharmony_ci JME_NAPI_ENABLE(jme); 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci tasklet_setup(&jme->txclean_task, jme_tx_clean_tasklet); 183062306a36Sopenharmony_ci tasklet_setup(&jme->rxclean_task, jme_rx_clean_tasklet); 183162306a36Sopenharmony_ci tasklet_setup(&jme->rxempty_task, jme_rx_empty_tasklet); 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci rc = jme_request_irq(jme); 183462306a36Sopenharmony_ci if (rc) 183562306a36Sopenharmony_ci goto err_out; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci jme_start_irq(jme); 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci jme_phy_on(jme); 184062306a36Sopenharmony_ci if (test_bit(JME_FLAG_SSET, &jme->flags)) 184162306a36Sopenharmony_ci jme_set_link_ksettings(netdev, &jme->old_cmd); 184262306a36Sopenharmony_ci else 184362306a36Sopenharmony_ci jme_reset_phy_processor(jme); 184462306a36Sopenharmony_ci jme_phy_calibration(jme); 184562306a36Sopenharmony_ci jme_phy_setEA(jme); 184662306a36Sopenharmony_ci jme_reset_link(jme); 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci return 0; 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_cierr_out: 185162306a36Sopenharmony_ci netif_stop_queue(netdev); 185262306a36Sopenharmony_ci netif_carrier_off(netdev); 185362306a36Sopenharmony_ci return rc; 185462306a36Sopenharmony_ci} 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_cistatic void 185762306a36Sopenharmony_cijme_set_100m_half(struct jme_adapter *jme) 185862306a36Sopenharmony_ci{ 185962306a36Sopenharmony_ci u32 bmcr, tmp; 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci jme_phy_on(jme); 186262306a36Sopenharmony_ci bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR); 186362306a36Sopenharmony_ci tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | 186462306a36Sopenharmony_ci BMCR_SPEED1000 | BMCR_FULLDPLX); 186562306a36Sopenharmony_ci tmp |= BMCR_SPEED100; 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci if (bmcr != tmp) 186862306a36Sopenharmony_ci jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, tmp); 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci if (jme->fpgaver) 187162306a36Sopenharmony_ci jwrite32(jme, JME_GHC, GHC_SPEED_100M | GHC_LINK_POLL); 187262306a36Sopenharmony_ci else 187362306a36Sopenharmony_ci jwrite32(jme, JME_GHC, GHC_SPEED_100M); 187462306a36Sopenharmony_ci} 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci#define JME_WAIT_LINK_TIME 2000 /* 2000ms */ 187762306a36Sopenharmony_cistatic void 187862306a36Sopenharmony_cijme_wait_link(struct jme_adapter *jme) 187962306a36Sopenharmony_ci{ 188062306a36Sopenharmony_ci u32 phylink, to = JME_WAIT_LINK_TIME; 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci msleep(1000); 188362306a36Sopenharmony_ci phylink = jme_linkstat_from_phy(jme); 188462306a36Sopenharmony_ci while (!(phylink & PHY_LINK_UP) && (to -= 10) > 0) { 188562306a36Sopenharmony_ci usleep_range(10000, 11000); 188662306a36Sopenharmony_ci phylink = jme_linkstat_from_phy(jme); 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci} 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_cistatic void 189162306a36Sopenharmony_cijme_powersave_phy(struct jme_adapter *jme) 189262306a36Sopenharmony_ci{ 189362306a36Sopenharmony_ci if (jme->reg_pmcs && device_may_wakeup(&jme->pdev->dev)) { 189462306a36Sopenharmony_ci jme_set_100m_half(jme); 189562306a36Sopenharmony_ci if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN)) 189662306a36Sopenharmony_ci jme_wait_link(jme); 189762306a36Sopenharmony_ci jme_clear_pm_enable_wol(jme); 189862306a36Sopenharmony_ci } else { 189962306a36Sopenharmony_ci jme_phy_off(jme); 190062306a36Sopenharmony_ci } 190162306a36Sopenharmony_ci} 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_cistatic int 190462306a36Sopenharmony_cijme_close(struct net_device *netdev) 190562306a36Sopenharmony_ci{ 190662306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci netif_stop_queue(netdev); 190962306a36Sopenharmony_ci netif_carrier_off(netdev); 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci jme_stop_irq(jme); 191262306a36Sopenharmony_ci jme_free_irq(jme); 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci JME_NAPI_DISABLE(jme); 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci cancel_work_sync(&jme->linkch_task); 191762306a36Sopenharmony_ci tasklet_kill(&jme->txclean_task); 191862306a36Sopenharmony_ci tasklet_kill(&jme->rxclean_task); 191962306a36Sopenharmony_ci tasklet_kill(&jme->rxempty_task); 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci jme_disable_rx_engine(jme); 192262306a36Sopenharmony_ci jme_disable_tx_engine(jme); 192362306a36Sopenharmony_ci jme_reset_mac_processor(jme); 192462306a36Sopenharmony_ci jme_free_rx_resources(jme); 192562306a36Sopenharmony_ci jme_free_tx_resources(jme); 192662306a36Sopenharmony_ci jme->phylink = 0; 192762306a36Sopenharmony_ci jme_phy_off(jme); 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci return 0; 193062306a36Sopenharmony_ci} 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_cistatic int 193362306a36Sopenharmony_cijme_alloc_txdesc(struct jme_adapter *jme, 193462306a36Sopenharmony_ci struct sk_buff *skb) 193562306a36Sopenharmony_ci{ 193662306a36Sopenharmony_ci struct jme_ring *txring = &(jme->txring[0]); 193762306a36Sopenharmony_ci int idx, nr_alloc, mask = jme->tx_ring_mask; 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci idx = txring->next_to_use; 194062306a36Sopenharmony_ci nr_alloc = skb_shinfo(skb)->nr_frags + 2; 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci if (unlikely(atomic_read(&txring->nr_free) < nr_alloc)) 194362306a36Sopenharmony_ci return -1; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci atomic_sub(nr_alloc, &txring->nr_free); 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci txring->next_to_use = (txring->next_to_use + nr_alloc) & mask; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci return idx; 195062306a36Sopenharmony_ci} 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_cistatic int 195362306a36Sopenharmony_cijme_fill_tx_map(struct pci_dev *pdev, 195462306a36Sopenharmony_ci struct txdesc *txdesc, 195562306a36Sopenharmony_ci struct jme_buffer_info *txbi, 195662306a36Sopenharmony_ci struct page *page, 195762306a36Sopenharmony_ci u32 page_offset, 195862306a36Sopenharmony_ci u32 len, 195962306a36Sopenharmony_ci bool hidma) 196062306a36Sopenharmony_ci{ 196162306a36Sopenharmony_ci dma_addr_t dmaaddr; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci dmaaddr = dma_map_page(&pdev->dev, page, page_offset, len, 196462306a36Sopenharmony_ci DMA_TO_DEVICE); 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci if (unlikely(dma_mapping_error(&pdev->dev, dmaaddr))) 196762306a36Sopenharmony_ci return -EINVAL; 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci dma_sync_single_for_device(&pdev->dev, dmaaddr, len, DMA_TO_DEVICE); 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci txdesc->dw[0] = 0; 197262306a36Sopenharmony_ci txdesc->dw[1] = 0; 197362306a36Sopenharmony_ci txdesc->desc2.flags = TXFLAG_OWN; 197462306a36Sopenharmony_ci txdesc->desc2.flags |= (hidma) ? TXFLAG_64BIT : 0; 197562306a36Sopenharmony_ci txdesc->desc2.datalen = cpu_to_le16(len); 197662306a36Sopenharmony_ci txdesc->desc2.bufaddrh = cpu_to_le32((__u64)dmaaddr >> 32); 197762306a36Sopenharmony_ci txdesc->desc2.bufaddrl = cpu_to_le32( 197862306a36Sopenharmony_ci (__u64)dmaaddr & 0xFFFFFFFFUL); 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci txbi->mapping = dmaaddr; 198162306a36Sopenharmony_ci txbi->len = len; 198262306a36Sopenharmony_ci return 0; 198362306a36Sopenharmony_ci} 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_cistatic void jme_drop_tx_map(struct jme_adapter *jme, int startidx, int count) 198662306a36Sopenharmony_ci{ 198762306a36Sopenharmony_ci struct jme_ring *txring = &(jme->txring[0]); 198862306a36Sopenharmony_ci struct jme_buffer_info *txbi = txring->bufinf, *ctxbi; 198962306a36Sopenharmony_ci int mask = jme->tx_ring_mask; 199062306a36Sopenharmony_ci int j; 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci for (j = 0 ; j < count ; j++) { 199362306a36Sopenharmony_ci ctxbi = txbi + ((startidx + j + 2) & (mask)); 199462306a36Sopenharmony_ci dma_unmap_page(&jme->pdev->dev, ctxbi->mapping, ctxbi->len, 199562306a36Sopenharmony_ci DMA_TO_DEVICE); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci ctxbi->mapping = 0; 199862306a36Sopenharmony_ci ctxbi->len = 0; 199962306a36Sopenharmony_ci } 200062306a36Sopenharmony_ci} 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_cistatic int 200362306a36Sopenharmony_cijme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx) 200462306a36Sopenharmony_ci{ 200562306a36Sopenharmony_ci struct jme_ring *txring = &(jme->txring[0]); 200662306a36Sopenharmony_ci struct txdesc *txdesc = txring->desc, *ctxdesc; 200762306a36Sopenharmony_ci struct jme_buffer_info *txbi = txring->bufinf, *ctxbi; 200862306a36Sopenharmony_ci bool hidma = jme->dev->features & NETIF_F_HIGHDMA; 200962306a36Sopenharmony_ci int i, nr_frags = skb_shinfo(skb)->nr_frags; 201062306a36Sopenharmony_ci int mask = jme->tx_ring_mask; 201162306a36Sopenharmony_ci u32 len; 201262306a36Sopenharmony_ci int ret = 0; 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci for (i = 0 ; i < nr_frags ; ++i) { 201562306a36Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci ctxdesc = txdesc + ((idx + i + 2) & (mask)); 201862306a36Sopenharmony_ci ctxbi = txbi + ((idx + i + 2) & (mask)); 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci ret = jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, 202162306a36Sopenharmony_ci skb_frag_page(frag), skb_frag_off(frag), 202262306a36Sopenharmony_ci skb_frag_size(frag), hidma); 202362306a36Sopenharmony_ci if (ret) { 202462306a36Sopenharmony_ci jme_drop_tx_map(jme, idx, i); 202562306a36Sopenharmony_ci goto out; 202662306a36Sopenharmony_ci } 202762306a36Sopenharmony_ci } 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci len = skb_is_nonlinear(skb) ? skb_headlen(skb) : skb->len; 203062306a36Sopenharmony_ci ctxdesc = txdesc + ((idx + 1) & (mask)); 203162306a36Sopenharmony_ci ctxbi = txbi + ((idx + 1) & (mask)); 203262306a36Sopenharmony_ci ret = jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, virt_to_page(skb->data), 203362306a36Sopenharmony_ci offset_in_page(skb->data), len, hidma); 203462306a36Sopenharmony_ci if (ret) 203562306a36Sopenharmony_ci jme_drop_tx_map(jme, idx, i); 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ciout: 203862306a36Sopenharmony_ci return ret; 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci} 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_cistatic int 204462306a36Sopenharmony_cijme_tx_tso(struct sk_buff *skb, __le16 *mss, u8 *flags) 204562306a36Sopenharmony_ci{ 204662306a36Sopenharmony_ci *mss = cpu_to_le16(skb_shinfo(skb)->gso_size << TXDESC_MSS_SHIFT); 204762306a36Sopenharmony_ci if (*mss) { 204862306a36Sopenharmony_ci *flags |= TXFLAG_LSEN; 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP)) { 205162306a36Sopenharmony_ci struct iphdr *iph = ip_hdr(skb); 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci iph->check = 0; 205462306a36Sopenharmony_ci tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, 205562306a36Sopenharmony_ci iph->daddr, 0, 205662306a36Sopenharmony_ci IPPROTO_TCP, 205762306a36Sopenharmony_ci 0); 205862306a36Sopenharmony_ci } else { 205962306a36Sopenharmony_ci tcp_v6_gso_csum_prep(skb); 206062306a36Sopenharmony_ci } 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci return 0; 206362306a36Sopenharmony_ci } 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci return 1; 206662306a36Sopenharmony_ci} 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_cistatic void 206962306a36Sopenharmony_cijme_tx_csum(struct jme_adapter *jme, struct sk_buff *skb, u8 *flags) 207062306a36Sopenharmony_ci{ 207162306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) { 207262306a36Sopenharmony_ci u8 ip_proto; 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci switch (skb->protocol) { 207562306a36Sopenharmony_ci case htons(ETH_P_IP): 207662306a36Sopenharmony_ci ip_proto = ip_hdr(skb)->protocol; 207762306a36Sopenharmony_ci break; 207862306a36Sopenharmony_ci case htons(ETH_P_IPV6): 207962306a36Sopenharmony_ci ip_proto = ipv6_hdr(skb)->nexthdr; 208062306a36Sopenharmony_ci break; 208162306a36Sopenharmony_ci default: 208262306a36Sopenharmony_ci ip_proto = 0; 208362306a36Sopenharmony_ci break; 208462306a36Sopenharmony_ci } 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci switch (ip_proto) { 208762306a36Sopenharmony_ci case IPPROTO_TCP: 208862306a36Sopenharmony_ci *flags |= TXFLAG_TCPCS; 208962306a36Sopenharmony_ci break; 209062306a36Sopenharmony_ci case IPPROTO_UDP: 209162306a36Sopenharmony_ci *flags |= TXFLAG_UDPCS; 209262306a36Sopenharmony_ci break; 209362306a36Sopenharmony_ci default: 209462306a36Sopenharmony_ci netif_err(jme, tx_err, jme->dev, "Error upper layer protocol\n"); 209562306a36Sopenharmony_ci break; 209662306a36Sopenharmony_ci } 209762306a36Sopenharmony_ci } 209862306a36Sopenharmony_ci} 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_cistatic inline void 210162306a36Sopenharmony_cijme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags) 210262306a36Sopenharmony_ci{ 210362306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 210462306a36Sopenharmony_ci *flags |= TXFLAG_TAGON; 210562306a36Sopenharmony_ci *vlan = cpu_to_le16(skb_vlan_tag_get(skb)); 210662306a36Sopenharmony_ci } 210762306a36Sopenharmony_ci} 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_cistatic int 211062306a36Sopenharmony_cijme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx) 211162306a36Sopenharmony_ci{ 211262306a36Sopenharmony_ci struct jme_ring *txring = &(jme->txring[0]); 211362306a36Sopenharmony_ci struct txdesc *txdesc; 211462306a36Sopenharmony_ci struct jme_buffer_info *txbi; 211562306a36Sopenharmony_ci u8 flags; 211662306a36Sopenharmony_ci int ret = 0; 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci txdesc = (struct txdesc *)txring->desc + idx; 211962306a36Sopenharmony_ci txbi = txring->bufinf + idx; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci txdesc->dw[0] = 0; 212262306a36Sopenharmony_ci txdesc->dw[1] = 0; 212362306a36Sopenharmony_ci txdesc->dw[2] = 0; 212462306a36Sopenharmony_ci txdesc->dw[3] = 0; 212562306a36Sopenharmony_ci txdesc->desc1.pktsize = cpu_to_le16(skb->len); 212662306a36Sopenharmony_ci /* 212762306a36Sopenharmony_ci * Set OWN bit at final. 212862306a36Sopenharmony_ci * When kernel transmit faster than NIC. 212962306a36Sopenharmony_ci * And NIC trying to send this descriptor before we tell 213062306a36Sopenharmony_ci * it to start sending this TX queue. 213162306a36Sopenharmony_ci * Other fields are already filled correctly. 213262306a36Sopenharmony_ci */ 213362306a36Sopenharmony_ci wmb(); 213462306a36Sopenharmony_ci flags = TXFLAG_OWN | TXFLAG_INT; 213562306a36Sopenharmony_ci /* 213662306a36Sopenharmony_ci * Set checksum flags while not tso 213762306a36Sopenharmony_ci */ 213862306a36Sopenharmony_ci if (jme_tx_tso(skb, &txdesc->desc1.mss, &flags)) 213962306a36Sopenharmony_ci jme_tx_csum(jme, skb, &flags); 214062306a36Sopenharmony_ci jme_tx_vlan(skb, &txdesc->desc1.vlan, &flags); 214162306a36Sopenharmony_ci ret = jme_map_tx_skb(jme, skb, idx); 214262306a36Sopenharmony_ci if (ret) 214362306a36Sopenharmony_ci return ret; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci txdesc->desc1.flags = flags; 214662306a36Sopenharmony_ci /* 214762306a36Sopenharmony_ci * Set tx buffer info after telling NIC to send 214862306a36Sopenharmony_ci * For better tx_clean timing 214962306a36Sopenharmony_ci */ 215062306a36Sopenharmony_ci wmb(); 215162306a36Sopenharmony_ci txbi->nr_desc = skb_shinfo(skb)->nr_frags + 2; 215262306a36Sopenharmony_ci txbi->skb = skb; 215362306a36Sopenharmony_ci txbi->len = skb->len; 215462306a36Sopenharmony_ci txbi->start_xmit = jiffies; 215562306a36Sopenharmony_ci if (!txbi->start_xmit) 215662306a36Sopenharmony_ci txbi->start_xmit = (0UL-1); 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci return 0; 215962306a36Sopenharmony_ci} 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_cistatic void 216262306a36Sopenharmony_cijme_stop_queue_if_full(struct jme_adapter *jme) 216362306a36Sopenharmony_ci{ 216462306a36Sopenharmony_ci struct jme_ring *txring = &(jme->txring[0]); 216562306a36Sopenharmony_ci struct jme_buffer_info *txbi = txring->bufinf; 216662306a36Sopenharmony_ci int idx = atomic_read(&txring->next_to_clean); 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci txbi += idx; 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci smp_wmb(); 217162306a36Sopenharmony_ci if (unlikely(atomic_read(&txring->nr_free) < (MAX_SKB_FRAGS+2))) { 217262306a36Sopenharmony_ci netif_stop_queue(jme->dev); 217362306a36Sopenharmony_ci netif_info(jme, tx_queued, jme->dev, "TX Queue Paused\n"); 217462306a36Sopenharmony_ci smp_wmb(); 217562306a36Sopenharmony_ci if (atomic_read(&txring->nr_free) 217662306a36Sopenharmony_ci >= (jme->tx_wake_threshold)) { 217762306a36Sopenharmony_ci netif_wake_queue(jme->dev); 217862306a36Sopenharmony_ci netif_info(jme, tx_queued, jme->dev, "TX Queue Fast Waked\n"); 217962306a36Sopenharmony_ci } 218062306a36Sopenharmony_ci } 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci if (unlikely(txbi->start_xmit && 218362306a36Sopenharmony_ci time_is_before_eq_jiffies(txbi->start_xmit + TX_TIMEOUT) && 218462306a36Sopenharmony_ci txbi->skb)) { 218562306a36Sopenharmony_ci netif_stop_queue(jme->dev); 218662306a36Sopenharmony_ci netif_info(jme, tx_queued, jme->dev, 218762306a36Sopenharmony_ci "TX Queue Stopped %d@%lu\n", idx, jiffies); 218862306a36Sopenharmony_ci } 218962306a36Sopenharmony_ci} 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci/* 219262306a36Sopenharmony_ci * This function is already protected by netif_tx_lock() 219362306a36Sopenharmony_ci */ 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_cistatic netdev_tx_t 219662306a36Sopenharmony_cijme_start_xmit(struct sk_buff *skb, struct net_device *netdev) 219762306a36Sopenharmony_ci{ 219862306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 219962306a36Sopenharmony_ci int idx; 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci if (unlikely(skb_is_gso(skb) && skb_cow_head(skb, 0))) { 220262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 220362306a36Sopenharmony_ci ++(NET_STAT(jme).tx_dropped); 220462306a36Sopenharmony_ci return NETDEV_TX_OK; 220562306a36Sopenharmony_ci } 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci idx = jme_alloc_txdesc(jme, skb); 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci if (unlikely(idx < 0)) { 221062306a36Sopenharmony_ci netif_stop_queue(netdev); 221162306a36Sopenharmony_ci netif_err(jme, tx_err, jme->dev, 221262306a36Sopenharmony_ci "BUG! Tx ring full when queue awake!\n"); 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci return NETDEV_TX_BUSY; 221562306a36Sopenharmony_ci } 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci if (jme_fill_tx_desc(jme, skb, idx)) 221862306a36Sopenharmony_ci return NETDEV_TX_OK; 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci jwrite32(jme, JME_TXCS, jme->reg_txcs | 222162306a36Sopenharmony_ci TXCS_SELECT_QUEUE0 | 222262306a36Sopenharmony_ci TXCS_QUEUE0S | 222362306a36Sopenharmony_ci TXCS_ENABLE); 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci tx_dbg(jme, "xmit: %d+%d@%lu\n", 222662306a36Sopenharmony_ci idx, skb_shinfo(skb)->nr_frags + 2, jiffies); 222762306a36Sopenharmony_ci jme_stop_queue_if_full(jme); 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci return NETDEV_TX_OK; 223062306a36Sopenharmony_ci} 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_cistatic void 223362306a36Sopenharmony_cijme_set_unicastaddr(struct net_device *netdev) 223462306a36Sopenharmony_ci{ 223562306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 223662306a36Sopenharmony_ci u32 val; 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci val = (netdev->dev_addr[3] & 0xff) << 24 | 223962306a36Sopenharmony_ci (netdev->dev_addr[2] & 0xff) << 16 | 224062306a36Sopenharmony_ci (netdev->dev_addr[1] & 0xff) << 8 | 224162306a36Sopenharmony_ci (netdev->dev_addr[0] & 0xff); 224262306a36Sopenharmony_ci jwrite32(jme, JME_RXUMA_LO, val); 224362306a36Sopenharmony_ci val = (netdev->dev_addr[5] & 0xff) << 8 | 224462306a36Sopenharmony_ci (netdev->dev_addr[4] & 0xff); 224562306a36Sopenharmony_ci jwrite32(jme, JME_RXUMA_HI, val); 224662306a36Sopenharmony_ci} 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_cistatic int 224962306a36Sopenharmony_cijme_set_macaddr(struct net_device *netdev, void *p) 225062306a36Sopenharmony_ci{ 225162306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 225262306a36Sopenharmony_ci struct sockaddr *addr = p; 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci if (netif_running(netdev)) 225562306a36Sopenharmony_ci return -EBUSY; 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci spin_lock_bh(&jme->macaddr_lock); 225862306a36Sopenharmony_ci eth_hw_addr_set(netdev, addr->sa_data); 225962306a36Sopenharmony_ci jme_set_unicastaddr(netdev); 226062306a36Sopenharmony_ci spin_unlock_bh(&jme->macaddr_lock); 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci return 0; 226362306a36Sopenharmony_ci} 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_cistatic void 226662306a36Sopenharmony_cijme_set_multi(struct net_device *netdev) 226762306a36Sopenharmony_ci{ 226862306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 226962306a36Sopenharmony_ci u32 mc_hash[2] = {}; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci spin_lock_bh(&jme->rxmcs_lock); 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci jme->reg_rxmcs |= RXMCS_BRDFRAME | RXMCS_UNIFRAME; 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci if (netdev->flags & IFF_PROMISC) { 227662306a36Sopenharmony_ci jme->reg_rxmcs |= RXMCS_ALLFRAME; 227762306a36Sopenharmony_ci } else if (netdev->flags & IFF_ALLMULTI) { 227862306a36Sopenharmony_ci jme->reg_rxmcs |= RXMCS_ALLMULFRAME; 227962306a36Sopenharmony_ci } else if (netdev->flags & IFF_MULTICAST) { 228062306a36Sopenharmony_ci struct netdev_hw_addr *ha; 228162306a36Sopenharmony_ci int bit_nr; 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci jme->reg_rxmcs |= RXMCS_MULFRAME | RXMCS_MULFILTERED; 228462306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, netdev) { 228562306a36Sopenharmony_ci bit_nr = ether_crc(ETH_ALEN, ha->addr) & 0x3F; 228662306a36Sopenharmony_ci mc_hash[bit_nr >> 5] |= 1 << (bit_nr & 0x1F); 228762306a36Sopenharmony_ci } 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci jwrite32(jme, JME_RXMCHT_LO, mc_hash[0]); 229062306a36Sopenharmony_ci jwrite32(jme, JME_RXMCHT_HI, mc_hash[1]); 229162306a36Sopenharmony_ci } 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci wmb(); 229462306a36Sopenharmony_ci jwrite32(jme, JME_RXMCS, jme->reg_rxmcs); 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci spin_unlock_bh(&jme->rxmcs_lock); 229762306a36Sopenharmony_ci} 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_cistatic int 230062306a36Sopenharmony_cijme_change_mtu(struct net_device *netdev, int new_mtu) 230162306a36Sopenharmony_ci{ 230262306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci netdev->mtu = new_mtu; 230562306a36Sopenharmony_ci netdev_update_features(netdev); 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci jme_restart_rx_engine(jme); 230862306a36Sopenharmony_ci jme_reset_link(jme); 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci return 0; 231162306a36Sopenharmony_ci} 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_cistatic void 231462306a36Sopenharmony_cijme_tx_timeout(struct net_device *netdev, unsigned int txqueue) 231562306a36Sopenharmony_ci{ 231662306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci jme->phylink = 0; 231962306a36Sopenharmony_ci jme_reset_phy_processor(jme); 232062306a36Sopenharmony_ci if (test_bit(JME_FLAG_SSET, &jme->flags)) 232162306a36Sopenharmony_ci jme_set_link_ksettings(netdev, &jme->old_cmd); 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_ci /* 232462306a36Sopenharmony_ci * Force to Reset the link again 232562306a36Sopenharmony_ci */ 232662306a36Sopenharmony_ci jme_reset_link(jme); 232762306a36Sopenharmony_ci} 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_cistatic void 233062306a36Sopenharmony_cijme_get_drvinfo(struct net_device *netdev, 233162306a36Sopenharmony_ci struct ethtool_drvinfo *info) 233262306a36Sopenharmony_ci{ 233362306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci strscpy(info->driver, DRV_NAME, sizeof(info->driver)); 233662306a36Sopenharmony_ci strscpy(info->version, DRV_VERSION, sizeof(info->version)); 233762306a36Sopenharmony_ci strscpy(info->bus_info, pci_name(jme->pdev), sizeof(info->bus_info)); 233862306a36Sopenharmony_ci} 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_cistatic int 234162306a36Sopenharmony_cijme_get_regs_len(struct net_device *netdev) 234262306a36Sopenharmony_ci{ 234362306a36Sopenharmony_ci return JME_REG_LEN; 234462306a36Sopenharmony_ci} 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_cistatic void 234762306a36Sopenharmony_cimmapio_memcpy(struct jme_adapter *jme, u32 *p, u32 reg, int len) 234862306a36Sopenharmony_ci{ 234962306a36Sopenharmony_ci int i; 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci for (i = 0 ; i < len ; i += 4) 235262306a36Sopenharmony_ci p[i >> 2] = jread32(jme, reg + i); 235362306a36Sopenharmony_ci} 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_cistatic void 235662306a36Sopenharmony_cimdio_memcpy(struct jme_adapter *jme, u32 *p, int reg_nr) 235762306a36Sopenharmony_ci{ 235862306a36Sopenharmony_ci int i; 235962306a36Sopenharmony_ci u16 *p16 = (u16 *)p; 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci for (i = 0 ; i < reg_nr ; ++i) 236262306a36Sopenharmony_ci p16[i] = jme_mdio_read(jme->dev, jme->mii_if.phy_id, i); 236362306a36Sopenharmony_ci} 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_cistatic void 236662306a36Sopenharmony_cijme_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) 236762306a36Sopenharmony_ci{ 236862306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 236962306a36Sopenharmony_ci u32 *p32 = (u32 *)p; 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci memset(p, 0xFF, JME_REG_LEN); 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci regs->version = 1; 237462306a36Sopenharmony_ci mmapio_memcpy(jme, p32, JME_MAC, JME_MAC_LEN); 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci p32 += 0x100 >> 2; 237762306a36Sopenharmony_ci mmapio_memcpy(jme, p32, JME_PHY, JME_PHY_LEN); 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci p32 += 0x100 >> 2; 238062306a36Sopenharmony_ci mmapio_memcpy(jme, p32, JME_MISC, JME_MISC_LEN); 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci p32 += 0x100 >> 2; 238362306a36Sopenharmony_ci mmapio_memcpy(jme, p32, JME_RSS, JME_RSS_LEN); 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci p32 += 0x100 >> 2; 238662306a36Sopenharmony_ci mdio_memcpy(jme, p32, JME_PHY_REG_NR); 238762306a36Sopenharmony_ci} 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_cistatic int jme_get_coalesce(struct net_device *netdev, 239062306a36Sopenharmony_ci struct ethtool_coalesce *ecmd, 239162306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 239262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 239362306a36Sopenharmony_ci{ 239462306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci ecmd->tx_coalesce_usecs = PCC_TX_TO; 239762306a36Sopenharmony_ci ecmd->tx_max_coalesced_frames = PCC_TX_CNT; 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci if (test_bit(JME_FLAG_POLL, &jme->flags)) { 240062306a36Sopenharmony_ci ecmd->use_adaptive_rx_coalesce = false; 240162306a36Sopenharmony_ci ecmd->rx_coalesce_usecs = 0; 240262306a36Sopenharmony_ci ecmd->rx_max_coalesced_frames = 0; 240362306a36Sopenharmony_ci return 0; 240462306a36Sopenharmony_ci } 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci ecmd->use_adaptive_rx_coalesce = true; 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci switch (jme->dpi.cur) { 240962306a36Sopenharmony_ci case PCC_P1: 241062306a36Sopenharmony_ci ecmd->rx_coalesce_usecs = PCC_P1_TO; 241162306a36Sopenharmony_ci ecmd->rx_max_coalesced_frames = PCC_P1_CNT; 241262306a36Sopenharmony_ci break; 241362306a36Sopenharmony_ci case PCC_P2: 241462306a36Sopenharmony_ci ecmd->rx_coalesce_usecs = PCC_P2_TO; 241562306a36Sopenharmony_ci ecmd->rx_max_coalesced_frames = PCC_P2_CNT; 241662306a36Sopenharmony_ci break; 241762306a36Sopenharmony_ci case PCC_P3: 241862306a36Sopenharmony_ci ecmd->rx_coalesce_usecs = PCC_P3_TO; 241962306a36Sopenharmony_ci ecmd->rx_max_coalesced_frames = PCC_P3_CNT; 242062306a36Sopenharmony_ci break; 242162306a36Sopenharmony_ci default: 242262306a36Sopenharmony_ci break; 242362306a36Sopenharmony_ci } 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci return 0; 242662306a36Sopenharmony_ci} 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_cistatic int jme_set_coalesce(struct net_device *netdev, 242962306a36Sopenharmony_ci struct ethtool_coalesce *ecmd, 243062306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 243162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 243262306a36Sopenharmony_ci{ 243362306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 243462306a36Sopenharmony_ci struct dynpcc_info *dpi = &(jme->dpi); 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_ci if (netif_running(netdev)) 243762306a36Sopenharmony_ci return -EBUSY; 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci if (ecmd->use_adaptive_rx_coalesce && 244062306a36Sopenharmony_ci test_bit(JME_FLAG_POLL, &jme->flags)) { 244162306a36Sopenharmony_ci clear_bit(JME_FLAG_POLL, &jme->flags); 244262306a36Sopenharmony_ci jme->jme_rx = netif_rx; 244362306a36Sopenharmony_ci dpi->cur = PCC_P1; 244462306a36Sopenharmony_ci dpi->attempt = PCC_P1; 244562306a36Sopenharmony_ci dpi->cnt = 0; 244662306a36Sopenharmony_ci jme_set_rx_pcc(jme, PCC_P1); 244762306a36Sopenharmony_ci jme_interrupt_mode(jme); 244862306a36Sopenharmony_ci } else if (!(ecmd->use_adaptive_rx_coalesce) && 244962306a36Sopenharmony_ci !(test_bit(JME_FLAG_POLL, &jme->flags))) { 245062306a36Sopenharmony_ci set_bit(JME_FLAG_POLL, &jme->flags); 245162306a36Sopenharmony_ci jme->jme_rx = netif_receive_skb; 245262306a36Sopenharmony_ci jme_interrupt_mode(jme); 245362306a36Sopenharmony_ci } 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci return 0; 245662306a36Sopenharmony_ci} 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_cistatic void 245962306a36Sopenharmony_cijme_get_pauseparam(struct net_device *netdev, 246062306a36Sopenharmony_ci struct ethtool_pauseparam *ecmd) 246162306a36Sopenharmony_ci{ 246262306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 246362306a36Sopenharmony_ci u32 val; 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci ecmd->tx_pause = (jme->reg_txpfc & TXPFC_PF_EN) != 0; 246662306a36Sopenharmony_ci ecmd->rx_pause = (jme->reg_rxmcs & RXMCS_FLOWCTRL) != 0; 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ci spin_lock_bh(&jme->phy_lock); 246962306a36Sopenharmony_ci val = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE); 247062306a36Sopenharmony_ci spin_unlock_bh(&jme->phy_lock); 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci ecmd->autoneg = 247362306a36Sopenharmony_ci (val & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) != 0; 247462306a36Sopenharmony_ci} 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_cistatic int 247762306a36Sopenharmony_cijme_set_pauseparam(struct net_device *netdev, 247862306a36Sopenharmony_ci struct ethtool_pauseparam *ecmd) 247962306a36Sopenharmony_ci{ 248062306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 248162306a36Sopenharmony_ci u32 val; 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci if (((jme->reg_txpfc & TXPFC_PF_EN) != 0) ^ 248462306a36Sopenharmony_ci (ecmd->tx_pause != 0)) { 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci if (ecmd->tx_pause) 248762306a36Sopenharmony_ci jme->reg_txpfc |= TXPFC_PF_EN; 248862306a36Sopenharmony_ci else 248962306a36Sopenharmony_ci jme->reg_txpfc &= ~TXPFC_PF_EN; 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci jwrite32(jme, JME_TXPFC, jme->reg_txpfc); 249262306a36Sopenharmony_ci } 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci spin_lock_bh(&jme->rxmcs_lock); 249562306a36Sopenharmony_ci if (((jme->reg_rxmcs & RXMCS_FLOWCTRL) != 0) ^ 249662306a36Sopenharmony_ci (ecmd->rx_pause != 0)) { 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci if (ecmd->rx_pause) 249962306a36Sopenharmony_ci jme->reg_rxmcs |= RXMCS_FLOWCTRL; 250062306a36Sopenharmony_ci else 250162306a36Sopenharmony_ci jme->reg_rxmcs &= ~RXMCS_FLOWCTRL; 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci jwrite32(jme, JME_RXMCS, jme->reg_rxmcs); 250462306a36Sopenharmony_ci } 250562306a36Sopenharmony_ci spin_unlock_bh(&jme->rxmcs_lock); 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci spin_lock_bh(&jme->phy_lock); 250862306a36Sopenharmony_ci val = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE); 250962306a36Sopenharmony_ci if (((val & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) != 0) ^ 251062306a36Sopenharmony_ci (ecmd->autoneg != 0)) { 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci if (ecmd->autoneg) 251362306a36Sopenharmony_ci val |= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); 251462306a36Sopenharmony_ci else 251562306a36Sopenharmony_ci val &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci jme_mdio_write(jme->dev, jme->mii_if.phy_id, 251862306a36Sopenharmony_ci MII_ADVERTISE, val); 251962306a36Sopenharmony_ci } 252062306a36Sopenharmony_ci spin_unlock_bh(&jme->phy_lock); 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci return 0; 252362306a36Sopenharmony_ci} 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_cistatic void 252662306a36Sopenharmony_cijme_get_wol(struct net_device *netdev, 252762306a36Sopenharmony_ci struct ethtool_wolinfo *wol) 252862306a36Sopenharmony_ci{ 252962306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci wol->supported = WAKE_MAGIC | WAKE_PHY; 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ci wol->wolopts = 0; 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN)) 253662306a36Sopenharmony_ci wol->wolopts |= WAKE_PHY; 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci if (jme->reg_pmcs & PMCS_MFEN) 253962306a36Sopenharmony_ci wol->wolopts |= WAKE_MAGIC; 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci} 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_cistatic int 254462306a36Sopenharmony_cijme_set_wol(struct net_device *netdev, 254562306a36Sopenharmony_ci struct ethtool_wolinfo *wol) 254662306a36Sopenharmony_ci{ 254762306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_ci if (wol->wolopts & (WAKE_MAGICSECURE | 255062306a36Sopenharmony_ci WAKE_UCAST | 255162306a36Sopenharmony_ci WAKE_MCAST | 255262306a36Sopenharmony_ci WAKE_BCAST | 255362306a36Sopenharmony_ci WAKE_ARP)) 255462306a36Sopenharmony_ci return -EOPNOTSUPP; 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci jme->reg_pmcs = 0; 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci if (wol->wolopts & WAKE_PHY) 255962306a36Sopenharmony_ci jme->reg_pmcs |= PMCS_LFEN | PMCS_LREN; 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci if (wol->wolopts & WAKE_MAGIC) 256262306a36Sopenharmony_ci jme->reg_pmcs |= PMCS_MFEN; 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci return 0; 256562306a36Sopenharmony_ci} 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_cistatic int 256862306a36Sopenharmony_cijme_get_link_ksettings(struct net_device *netdev, 256962306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 257062306a36Sopenharmony_ci{ 257162306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci spin_lock_bh(&jme->phy_lock); 257462306a36Sopenharmony_ci mii_ethtool_get_link_ksettings(&jme->mii_if, cmd); 257562306a36Sopenharmony_ci spin_unlock_bh(&jme->phy_lock); 257662306a36Sopenharmony_ci return 0; 257762306a36Sopenharmony_ci} 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_cistatic int 258062306a36Sopenharmony_cijme_set_link_ksettings(struct net_device *netdev, 258162306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 258262306a36Sopenharmony_ci{ 258362306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 258462306a36Sopenharmony_ci int rc, fdc = 0; 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci if (cmd->base.speed == SPEED_1000 && 258762306a36Sopenharmony_ci cmd->base.autoneg != AUTONEG_ENABLE) 258862306a36Sopenharmony_ci return -EINVAL; 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci /* 259162306a36Sopenharmony_ci * Check If user changed duplex only while force_media. 259262306a36Sopenharmony_ci * Hardware would not generate link change interrupt. 259362306a36Sopenharmony_ci */ 259462306a36Sopenharmony_ci if (jme->mii_if.force_media && 259562306a36Sopenharmony_ci cmd->base.autoneg != AUTONEG_ENABLE && 259662306a36Sopenharmony_ci (jme->mii_if.full_duplex != cmd->base.duplex)) 259762306a36Sopenharmony_ci fdc = 1; 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci spin_lock_bh(&jme->phy_lock); 260062306a36Sopenharmony_ci rc = mii_ethtool_set_link_ksettings(&jme->mii_if, cmd); 260162306a36Sopenharmony_ci spin_unlock_bh(&jme->phy_lock); 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci if (!rc) { 260462306a36Sopenharmony_ci if (fdc) 260562306a36Sopenharmony_ci jme_reset_link(jme); 260662306a36Sopenharmony_ci jme->old_cmd = *cmd; 260762306a36Sopenharmony_ci set_bit(JME_FLAG_SSET, &jme->flags); 260862306a36Sopenharmony_ci } 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci return rc; 261162306a36Sopenharmony_ci} 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_cistatic int 261462306a36Sopenharmony_cijme_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) 261562306a36Sopenharmony_ci{ 261662306a36Sopenharmony_ci int rc; 261762306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 261862306a36Sopenharmony_ci struct mii_ioctl_data *mii_data = if_mii(rq); 261962306a36Sopenharmony_ci unsigned int duplex_chg; 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci if (cmd == SIOCSMIIREG) { 262262306a36Sopenharmony_ci u16 val = mii_data->val_in; 262362306a36Sopenharmony_ci if (!(val & (BMCR_RESET|BMCR_ANENABLE)) && 262462306a36Sopenharmony_ci (val & BMCR_SPEED1000)) 262562306a36Sopenharmony_ci return -EINVAL; 262662306a36Sopenharmony_ci } 262762306a36Sopenharmony_ci 262862306a36Sopenharmony_ci spin_lock_bh(&jme->phy_lock); 262962306a36Sopenharmony_ci rc = generic_mii_ioctl(&jme->mii_if, mii_data, cmd, &duplex_chg); 263062306a36Sopenharmony_ci spin_unlock_bh(&jme->phy_lock); 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci if (!rc && (cmd == SIOCSMIIREG)) { 263362306a36Sopenharmony_ci if (duplex_chg) 263462306a36Sopenharmony_ci jme_reset_link(jme); 263562306a36Sopenharmony_ci jme_get_link_ksettings(netdev, &jme->old_cmd); 263662306a36Sopenharmony_ci set_bit(JME_FLAG_SSET, &jme->flags); 263762306a36Sopenharmony_ci } 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci return rc; 264062306a36Sopenharmony_ci} 264162306a36Sopenharmony_ci 264262306a36Sopenharmony_cistatic u32 264362306a36Sopenharmony_cijme_get_link(struct net_device *netdev) 264462306a36Sopenharmony_ci{ 264562306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 264662306a36Sopenharmony_ci return jread32(jme, JME_PHY_LINK) & PHY_LINK_UP; 264762306a36Sopenharmony_ci} 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_cistatic u32 265062306a36Sopenharmony_cijme_get_msglevel(struct net_device *netdev) 265162306a36Sopenharmony_ci{ 265262306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 265362306a36Sopenharmony_ci return jme->msg_enable; 265462306a36Sopenharmony_ci} 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_cistatic void 265762306a36Sopenharmony_cijme_set_msglevel(struct net_device *netdev, u32 value) 265862306a36Sopenharmony_ci{ 265962306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 266062306a36Sopenharmony_ci jme->msg_enable = value; 266162306a36Sopenharmony_ci} 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_cistatic netdev_features_t 266462306a36Sopenharmony_cijme_fix_features(struct net_device *netdev, netdev_features_t features) 266562306a36Sopenharmony_ci{ 266662306a36Sopenharmony_ci if (netdev->mtu > 1900) 266762306a36Sopenharmony_ci features &= ~(NETIF_F_ALL_TSO | NETIF_F_CSUM_MASK); 266862306a36Sopenharmony_ci return features; 266962306a36Sopenharmony_ci} 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_cistatic int 267262306a36Sopenharmony_cijme_set_features(struct net_device *netdev, netdev_features_t features) 267362306a36Sopenharmony_ci{ 267462306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci spin_lock_bh(&jme->rxmcs_lock); 267762306a36Sopenharmony_ci if (features & NETIF_F_RXCSUM) 267862306a36Sopenharmony_ci jme->reg_rxmcs |= RXMCS_CHECKSUM; 267962306a36Sopenharmony_ci else 268062306a36Sopenharmony_ci jme->reg_rxmcs &= ~RXMCS_CHECKSUM; 268162306a36Sopenharmony_ci jwrite32(jme, JME_RXMCS, jme->reg_rxmcs); 268262306a36Sopenharmony_ci spin_unlock_bh(&jme->rxmcs_lock); 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci return 0; 268562306a36Sopenharmony_ci} 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 268862306a36Sopenharmony_cistatic void jme_netpoll(struct net_device *dev) 268962306a36Sopenharmony_ci{ 269062306a36Sopenharmony_ci unsigned long flags; 269162306a36Sopenharmony_ci 269262306a36Sopenharmony_ci local_irq_save(flags); 269362306a36Sopenharmony_ci jme_intr(dev->irq, dev); 269462306a36Sopenharmony_ci local_irq_restore(flags); 269562306a36Sopenharmony_ci} 269662306a36Sopenharmony_ci#endif 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_cistatic int 269962306a36Sopenharmony_cijme_nway_reset(struct net_device *netdev) 270062306a36Sopenharmony_ci{ 270162306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 270262306a36Sopenharmony_ci jme_restart_an(jme); 270362306a36Sopenharmony_ci return 0; 270462306a36Sopenharmony_ci} 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_cistatic u8 270762306a36Sopenharmony_cijme_smb_read(struct jme_adapter *jme, unsigned int addr) 270862306a36Sopenharmony_ci{ 270962306a36Sopenharmony_ci u32 val; 271062306a36Sopenharmony_ci int to; 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_ci val = jread32(jme, JME_SMBCSR); 271362306a36Sopenharmony_ci to = JME_SMB_BUSY_TIMEOUT; 271462306a36Sopenharmony_ci while ((val & SMBCSR_BUSY) && --to) { 271562306a36Sopenharmony_ci msleep(1); 271662306a36Sopenharmony_ci val = jread32(jme, JME_SMBCSR); 271762306a36Sopenharmony_ci } 271862306a36Sopenharmony_ci if (!to) { 271962306a36Sopenharmony_ci netif_err(jme, hw, jme->dev, "SMB Bus Busy\n"); 272062306a36Sopenharmony_ci return 0xFF; 272162306a36Sopenharmony_ci } 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_ci jwrite32(jme, JME_SMBINTF, 272462306a36Sopenharmony_ci ((addr << SMBINTF_HWADDR_SHIFT) & SMBINTF_HWADDR) | 272562306a36Sopenharmony_ci SMBINTF_HWRWN_READ | 272662306a36Sopenharmony_ci SMBINTF_HWCMD); 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_ci val = jread32(jme, JME_SMBINTF); 272962306a36Sopenharmony_ci to = JME_SMB_BUSY_TIMEOUT; 273062306a36Sopenharmony_ci while ((val & SMBINTF_HWCMD) && --to) { 273162306a36Sopenharmony_ci msleep(1); 273262306a36Sopenharmony_ci val = jread32(jme, JME_SMBINTF); 273362306a36Sopenharmony_ci } 273462306a36Sopenharmony_ci if (!to) { 273562306a36Sopenharmony_ci netif_err(jme, hw, jme->dev, "SMB Bus Busy\n"); 273662306a36Sopenharmony_ci return 0xFF; 273762306a36Sopenharmony_ci } 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci return (val & SMBINTF_HWDATR) >> SMBINTF_HWDATR_SHIFT; 274062306a36Sopenharmony_ci} 274162306a36Sopenharmony_ci 274262306a36Sopenharmony_cistatic void 274362306a36Sopenharmony_cijme_smb_write(struct jme_adapter *jme, unsigned int addr, u8 data) 274462306a36Sopenharmony_ci{ 274562306a36Sopenharmony_ci u32 val; 274662306a36Sopenharmony_ci int to; 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci val = jread32(jme, JME_SMBCSR); 274962306a36Sopenharmony_ci to = JME_SMB_BUSY_TIMEOUT; 275062306a36Sopenharmony_ci while ((val & SMBCSR_BUSY) && --to) { 275162306a36Sopenharmony_ci msleep(1); 275262306a36Sopenharmony_ci val = jread32(jme, JME_SMBCSR); 275362306a36Sopenharmony_ci } 275462306a36Sopenharmony_ci if (!to) { 275562306a36Sopenharmony_ci netif_err(jme, hw, jme->dev, "SMB Bus Busy\n"); 275662306a36Sopenharmony_ci return; 275762306a36Sopenharmony_ci } 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci jwrite32(jme, JME_SMBINTF, 276062306a36Sopenharmony_ci ((data << SMBINTF_HWDATW_SHIFT) & SMBINTF_HWDATW) | 276162306a36Sopenharmony_ci ((addr << SMBINTF_HWADDR_SHIFT) & SMBINTF_HWADDR) | 276262306a36Sopenharmony_ci SMBINTF_HWRWN_WRITE | 276362306a36Sopenharmony_ci SMBINTF_HWCMD); 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci val = jread32(jme, JME_SMBINTF); 276662306a36Sopenharmony_ci to = JME_SMB_BUSY_TIMEOUT; 276762306a36Sopenharmony_ci while ((val & SMBINTF_HWCMD) && --to) { 276862306a36Sopenharmony_ci msleep(1); 276962306a36Sopenharmony_ci val = jread32(jme, JME_SMBINTF); 277062306a36Sopenharmony_ci } 277162306a36Sopenharmony_ci if (!to) { 277262306a36Sopenharmony_ci netif_err(jme, hw, jme->dev, "SMB Bus Busy\n"); 277362306a36Sopenharmony_ci return; 277462306a36Sopenharmony_ci } 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_ci mdelay(2); 277762306a36Sopenharmony_ci} 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_cistatic int 278062306a36Sopenharmony_cijme_get_eeprom_len(struct net_device *netdev) 278162306a36Sopenharmony_ci{ 278262306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 278362306a36Sopenharmony_ci u32 val; 278462306a36Sopenharmony_ci val = jread32(jme, JME_SMBCSR); 278562306a36Sopenharmony_ci return (val & SMBCSR_EEPROMD) ? JME_SMB_LEN : 0; 278662306a36Sopenharmony_ci} 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_cistatic int 278962306a36Sopenharmony_cijme_get_eeprom(struct net_device *netdev, 279062306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *data) 279162306a36Sopenharmony_ci{ 279262306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 279362306a36Sopenharmony_ci int i, offset = eeprom->offset, len = eeprom->len; 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci /* 279662306a36Sopenharmony_ci * ethtool will check the boundary for us 279762306a36Sopenharmony_ci */ 279862306a36Sopenharmony_ci eeprom->magic = JME_EEPROM_MAGIC; 279962306a36Sopenharmony_ci for (i = 0 ; i < len ; ++i) 280062306a36Sopenharmony_ci data[i] = jme_smb_read(jme, i + offset); 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci return 0; 280362306a36Sopenharmony_ci} 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_cistatic int 280662306a36Sopenharmony_cijme_set_eeprom(struct net_device *netdev, 280762306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *data) 280862306a36Sopenharmony_ci{ 280962306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 281062306a36Sopenharmony_ci int i, offset = eeprom->offset, len = eeprom->len; 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci if (eeprom->magic != JME_EEPROM_MAGIC) 281362306a36Sopenharmony_ci return -EINVAL; 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci /* 281662306a36Sopenharmony_ci * ethtool will check the boundary for us 281762306a36Sopenharmony_ci */ 281862306a36Sopenharmony_ci for (i = 0 ; i < len ; ++i) 281962306a36Sopenharmony_ci jme_smb_write(jme, i + offset, data[i]); 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_ci return 0; 282262306a36Sopenharmony_ci} 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_cistatic const struct ethtool_ops jme_ethtool_ops = { 282562306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 282662306a36Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES | 282762306a36Sopenharmony_ci ETHTOOL_COALESCE_USE_ADAPTIVE_RX, 282862306a36Sopenharmony_ci .get_drvinfo = jme_get_drvinfo, 282962306a36Sopenharmony_ci .get_regs_len = jme_get_regs_len, 283062306a36Sopenharmony_ci .get_regs = jme_get_regs, 283162306a36Sopenharmony_ci .get_coalesce = jme_get_coalesce, 283262306a36Sopenharmony_ci .set_coalesce = jme_set_coalesce, 283362306a36Sopenharmony_ci .get_pauseparam = jme_get_pauseparam, 283462306a36Sopenharmony_ci .set_pauseparam = jme_set_pauseparam, 283562306a36Sopenharmony_ci .get_wol = jme_get_wol, 283662306a36Sopenharmony_ci .set_wol = jme_set_wol, 283762306a36Sopenharmony_ci .get_link = jme_get_link, 283862306a36Sopenharmony_ci .get_msglevel = jme_get_msglevel, 283962306a36Sopenharmony_ci .set_msglevel = jme_set_msglevel, 284062306a36Sopenharmony_ci .nway_reset = jme_nway_reset, 284162306a36Sopenharmony_ci .get_eeprom_len = jme_get_eeprom_len, 284262306a36Sopenharmony_ci .get_eeprom = jme_get_eeprom, 284362306a36Sopenharmony_ci .set_eeprom = jme_set_eeprom, 284462306a36Sopenharmony_ci .get_link_ksettings = jme_get_link_ksettings, 284562306a36Sopenharmony_ci .set_link_ksettings = jme_set_link_ksettings, 284662306a36Sopenharmony_ci}; 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_cistatic int 284962306a36Sopenharmony_cijme_pci_dma64(struct pci_dev *pdev) 285062306a36Sopenharmony_ci{ 285162306a36Sopenharmony_ci if (pdev->device == PCI_DEVICE_ID_JMICRON_JMC250 && 285262306a36Sopenharmony_ci !dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) 285362306a36Sopenharmony_ci return 1; 285462306a36Sopenharmony_ci 285562306a36Sopenharmony_ci if (pdev->device == PCI_DEVICE_ID_JMICRON_JMC250 && 285662306a36Sopenharmony_ci !dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40))) 285762306a36Sopenharmony_ci return 1; 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) 286062306a36Sopenharmony_ci return 0; 286162306a36Sopenharmony_ci 286262306a36Sopenharmony_ci return -1; 286362306a36Sopenharmony_ci} 286462306a36Sopenharmony_ci 286562306a36Sopenharmony_cistatic inline void 286662306a36Sopenharmony_cijme_phy_init(struct jme_adapter *jme) 286762306a36Sopenharmony_ci{ 286862306a36Sopenharmony_ci u16 reg26; 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci reg26 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, 26); 287162306a36Sopenharmony_ci jme_mdio_write(jme->dev, jme->mii_if.phy_id, 26, reg26 | 0x1000); 287262306a36Sopenharmony_ci} 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_cistatic inline void 287562306a36Sopenharmony_cijme_check_hw_ver(struct jme_adapter *jme) 287662306a36Sopenharmony_ci{ 287762306a36Sopenharmony_ci u32 chipmode; 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_ci chipmode = jread32(jme, JME_CHIPMODE); 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci jme->fpgaver = (chipmode & CM_FPGAVER_MASK) >> CM_FPGAVER_SHIFT; 288262306a36Sopenharmony_ci jme->chiprev = (chipmode & CM_CHIPREV_MASK) >> CM_CHIPREV_SHIFT; 288362306a36Sopenharmony_ci jme->chip_main_rev = jme->chiprev & 0xF; 288462306a36Sopenharmony_ci jme->chip_sub_rev = (jme->chiprev >> 4) & 0xF; 288562306a36Sopenharmony_ci} 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_cistatic const struct net_device_ops jme_netdev_ops = { 288862306a36Sopenharmony_ci .ndo_open = jme_open, 288962306a36Sopenharmony_ci .ndo_stop = jme_close, 289062306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 289162306a36Sopenharmony_ci .ndo_eth_ioctl = jme_ioctl, 289262306a36Sopenharmony_ci .ndo_start_xmit = jme_start_xmit, 289362306a36Sopenharmony_ci .ndo_set_mac_address = jme_set_macaddr, 289462306a36Sopenharmony_ci .ndo_set_rx_mode = jme_set_multi, 289562306a36Sopenharmony_ci .ndo_change_mtu = jme_change_mtu, 289662306a36Sopenharmony_ci .ndo_tx_timeout = jme_tx_timeout, 289762306a36Sopenharmony_ci .ndo_fix_features = jme_fix_features, 289862306a36Sopenharmony_ci .ndo_set_features = jme_set_features, 289962306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 290062306a36Sopenharmony_ci .ndo_poll_controller = jme_netpoll, 290162306a36Sopenharmony_ci#endif 290262306a36Sopenharmony_ci}; 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_cistatic int 290562306a36Sopenharmony_cijme_init_one(struct pci_dev *pdev, 290662306a36Sopenharmony_ci const struct pci_device_id *ent) 290762306a36Sopenharmony_ci{ 290862306a36Sopenharmony_ci int rc = 0, using_dac, i; 290962306a36Sopenharmony_ci struct net_device *netdev; 291062306a36Sopenharmony_ci struct jme_adapter *jme; 291162306a36Sopenharmony_ci u16 bmcr, bmsr; 291262306a36Sopenharmony_ci u32 apmc; 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ci /* 291562306a36Sopenharmony_ci * set up PCI device basics 291662306a36Sopenharmony_ci */ 291762306a36Sopenharmony_ci pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | 291862306a36Sopenharmony_ci PCIE_LINK_STATE_CLKPM); 291962306a36Sopenharmony_ci 292062306a36Sopenharmony_ci rc = pci_enable_device(pdev); 292162306a36Sopenharmony_ci if (rc) { 292262306a36Sopenharmony_ci pr_err("Cannot enable PCI device\n"); 292362306a36Sopenharmony_ci goto err_out; 292462306a36Sopenharmony_ci } 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci using_dac = jme_pci_dma64(pdev); 292762306a36Sopenharmony_ci if (using_dac < 0) { 292862306a36Sopenharmony_ci pr_err("Cannot set PCI DMA Mask\n"); 292962306a36Sopenharmony_ci rc = -EIO; 293062306a36Sopenharmony_ci goto err_out_disable_pdev; 293162306a36Sopenharmony_ci } 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_ci if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { 293462306a36Sopenharmony_ci pr_err("No PCI resource region found\n"); 293562306a36Sopenharmony_ci rc = -ENOMEM; 293662306a36Sopenharmony_ci goto err_out_disable_pdev; 293762306a36Sopenharmony_ci } 293862306a36Sopenharmony_ci 293962306a36Sopenharmony_ci rc = pci_request_regions(pdev, DRV_NAME); 294062306a36Sopenharmony_ci if (rc) { 294162306a36Sopenharmony_ci pr_err("Cannot obtain PCI resource region\n"); 294262306a36Sopenharmony_ci goto err_out_disable_pdev; 294362306a36Sopenharmony_ci } 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci pci_set_master(pdev); 294662306a36Sopenharmony_ci 294762306a36Sopenharmony_ci /* 294862306a36Sopenharmony_ci * alloc and init net device 294962306a36Sopenharmony_ci */ 295062306a36Sopenharmony_ci netdev = alloc_etherdev(sizeof(*jme)); 295162306a36Sopenharmony_ci if (!netdev) { 295262306a36Sopenharmony_ci rc = -ENOMEM; 295362306a36Sopenharmony_ci goto err_out_release_regions; 295462306a36Sopenharmony_ci } 295562306a36Sopenharmony_ci netdev->netdev_ops = &jme_netdev_ops; 295662306a36Sopenharmony_ci netdev->ethtool_ops = &jme_ethtool_ops; 295762306a36Sopenharmony_ci netdev->watchdog_timeo = TX_TIMEOUT; 295862306a36Sopenharmony_ci netdev->hw_features = NETIF_F_IP_CSUM | 295962306a36Sopenharmony_ci NETIF_F_IPV6_CSUM | 296062306a36Sopenharmony_ci NETIF_F_SG | 296162306a36Sopenharmony_ci NETIF_F_TSO | 296262306a36Sopenharmony_ci NETIF_F_TSO6 | 296362306a36Sopenharmony_ci NETIF_F_RXCSUM; 296462306a36Sopenharmony_ci netdev->features = NETIF_F_IP_CSUM | 296562306a36Sopenharmony_ci NETIF_F_IPV6_CSUM | 296662306a36Sopenharmony_ci NETIF_F_SG | 296762306a36Sopenharmony_ci NETIF_F_TSO | 296862306a36Sopenharmony_ci NETIF_F_TSO6 | 296962306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | 297062306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX; 297162306a36Sopenharmony_ci if (using_dac) 297262306a36Sopenharmony_ci netdev->features |= NETIF_F_HIGHDMA; 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci /* MTU range: 1280 - 9202*/ 297562306a36Sopenharmony_ci netdev->min_mtu = IPV6_MIN_MTU; 297662306a36Sopenharmony_ci netdev->max_mtu = MAX_ETHERNET_JUMBO_PACKET_SIZE - ETH_HLEN; 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 297962306a36Sopenharmony_ci pci_set_drvdata(pdev, netdev); 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci /* 298262306a36Sopenharmony_ci * init adapter info 298362306a36Sopenharmony_ci */ 298462306a36Sopenharmony_ci jme = netdev_priv(netdev); 298562306a36Sopenharmony_ci jme->pdev = pdev; 298662306a36Sopenharmony_ci jme->dev = netdev; 298762306a36Sopenharmony_ci jme->jme_rx = netif_rx; 298862306a36Sopenharmony_ci jme->old_mtu = netdev->mtu = 1500; 298962306a36Sopenharmony_ci jme->phylink = 0; 299062306a36Sopenharmony_ci jme->tx_ring_size = 1 << 10; 299162306a36Sopenharmony_ci jme->tx_ring_mask = jme->tx_ring_size - 1; 299262306a36Sopenharmony_ci jme->tx_wake_threshold = 1 << 9; 299362306a36Sopenharmony_ci jme->rx_ring_size = 1 << 9; 299462306a36Sopenharmony_ci jme->rx_ring_mask = jme->rx_ring_size - 1; 299562306a36Sopenharmony_ci jme->msg_enable = JME_DEF_MSG_ENABLE; 299662306a36Sopenharmony_ci jme->regs = ioremap(pci_resource_start(pdev, 0), 299762306a36Sopenharmony_ci pci_resource_len(pdev, 0)); 299862306a36Sopenharmony_ci if (!(jme->regs)) { 299962306a36Sopenharmony_ci pr_err("Mapping PCI resource region error\n"); 300062306a36Sopenharmony_ci rc = -ENOMEM; 300162306a36Sopenharmony_ci goto err_out_free_netdev; 300262306a36Sopenharmony_ci } 300362306a36Sopenharmony_ci 300462306a36Sopenharmony_ci if (no_pseudohp) { 300562306a36Sopenharmony_ci apmc = jread32(jme, JME_APMC) & ~JME_APMC_PSEUDO_HP_EN; 300662306a36Sopenharmony_ci jwrite32(jme, JME_APMC, apmc); 300762306a36Sopenharmony_ci } else if (force_pseudohp) { 300862306a36Sopenharmony_ci apmc = jread32(jme, JME_APMC) | JME_APMC_PSEUDO_HP_EN; 300962306a36Sopenharmony_ci jwrite32(jme, JME_APMC, apmc); 301062306a36Sopenharmony_ci } 301162306a36Sopenharmony_ci 301262306a36Sopenharmony_ci netif_napi_add(netdev, &jme->napi, jme_poll); 301362306a36Sopenharmony_ci 301462306a36Sopenharmony_ci spin_lock_init(&jme->phy_lock); 301562306a36Sopenharmony_ci spin_lock_init(&jme->macaddr_lock); 301662306a36Sopenharmony_ci spin_lock_init(&jme->rxmcs_lock); 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci atomic_set(&jme->link_changing, 1); 301962306a36Sopenharmony_ci atomic_set(&jme->rx_cleaning, 1); 302062306a36Sopenharmony_ci atomic_set(&jme->tx_cleaning, 1); 302162306a36Sopenharmony_ci atomic_set(&jme->rx_empty, 1); 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci tasklet_setup(&jme->pcc_task, jme_pcc_tasklet); 302462306a36Sopenharmony_ci INIT_WORK(&jme->linkch_task, jme_link_change_work); 302562306a36Sopenharmony_ci jme->dpi.cur = PCC_P1; 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci jme->reg_ghc = 0; 302862306a36Sopenharmony_ci jme->reg_rxcs = RXCS_DEFAULT; 302962306a36Sopenharmony_ci jme->reg_rxmcs = RXMCS_DEFAULT; 303062306a36Sopenharmony_ci jme->reg_txpfc = 0; 303162306a36Sopenharmony_ci jme->reg_pmcs = PMCS_MFEN; 303262306a36Sopenharmony_ci jme->reg_gpreg1 = GPREG1_DEFAULT; 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci if (jme->reg_rxmcs & RXMCS_CHECKSUM) 303562306a36Sopenharmony_ci netdev->features |= NETIF_F_RXCSUM; 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci /* 303862306a36Sopenharmony_ci * Get Max Read Req Size from PCI Config Space 303962306a36Sopenharmony_ci */ 304062306a36Sopenharmony_ci pci_read_config_byte(pdev, PCI_DCSR_MRRS, &jme->mrrs); 304162306a36Sopenharmony_ci jme->mrrs &= PCI_DCSR_MRRS_MASK; 304262306a36Sopenharmony_ci switch (jme->mrrs) { 304362306a36Sopenharmony_ci case MRRS_128B: 304462306a36Sopenharmony_ci jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_128B; 304562306a36Sopenharmony_ci break; 304662306a36Sopenharmony_ci case MRRS_256B: 304762306a36Sopenharmony_ci jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_256B; 304862306a36Sopenharmony_ci break; 304962306a36Sopenharmony_ci default: 305062306a36Sopenharmony_ci jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_512B; 305162306a36Sopenharmony_ci break; 305262306a36Sopenharmony_ci } 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_ci /* 305562306a36Sopenharmony_ci * Must check before reset_mac_processor 305662306a36Sopenharmony_ci */ 305762306a36Sopenharmony_ci jme_check_hw_ver(jme); 305862306a36Sopenharmony_ci jme->mii_if.dev = netdev; 305962306a36Sopenharmony_ci if (jme->fpgaver) { 306062306a36Sopenharmony_ci jme->mii_if.phy_id = 0; 306162306a36Sopenharmony_ci for (i = 1 ; i < 32 ; ++i) { 306262306a36Sopenharmony_ci bmcr = jme_mdio_read(netdev, i, MII_BMCR); 306362306a36Sopenharmony_ci bmsr = jme_mdio_read(netdev, i, MII_BMSR); 306462306a36Sopenharmony_ci if (bmcr != 0xFFFFU && (bmcr != 0 || bmsr != 0)) { 306562306a36Sopenharmony_ci jme->mii_if.phy_id = i; 306662306a36Sopenharmony_ci break; 306762306a36Sopenharmony_ci } 306862306a36Sopenharmony_ci } 306962306a36Sopenharmony_ci 307062306a36Sopenharmony_ci if (!jme->mii_if.phy_id) { 307162306a36Sopenharmony_ci rc = -EIO; 307262306a36Sopenharmony_ci pr_err("Can not find phy_id\n"); 307362306a36Sopenharmony_ci goto err_out_unmap; 307462306a36Sopenharmony_ci } 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci jme->reg_ghc |= GHC_LINK_POLL; 307762306a36Sopenharmony_ci } else { 307862306a36Sopenharmony_ci jme->mii_if.phy_id = 1; 307962306a36Sopenharmony_ci } 308062306a36Sopenharmony_ci if (pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) 308162306a36Sopenharmony_ci jme->mii_if.supports_gmii = true; 308262306a36Sopenharmony_ci else 308362306a36Sopenharmony_ci jme->mii_if.supports_gmii = false; 308462306a36Sopenharmony_ci jme->mii_if.phy_id_mask = 0x1F; 308562306a36Sopenharmony_ci jme->mii_if.reg_num_mask = 0x1F; 308662306a36Sopenharmony_ci jme->mii_if.mdio_read = jme_mdio_read; 308762306a36Sopenharmony_ci jme->mii_if.mdio_write = jme_mdio_write; 308862306a36Sopenharmony_ci 308962306a36Sopenharmony_ci jme_clear_pm_disable_wol(jme); 309062306a36Sopenharmony_ci device_init_wakeup(&pdev->dev, true); 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci jme_set_phyfifo_5level(jme); 309362306a36Sopenharmony_ci jme->pcirev = pdev->revision; 309462306a36Sopenharmony_ci if (!jme->fpgaver) 309562306a36Sopenharmony_ci jme_phy_init(jme); 309662306a36Sopenharmony_ci jme_phy_off(jme); 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_ci /* 309962306a36Sopenharmony_ci * Reset MAC processor and reload EEPROM for MAC Address 310062306a36Sopenharmony_ci */ 310162306a36Sopenharmony_ci jme_reset_mac_processor(jme); 310262306a36Sopenharmony_ci rc = jme_reload_eeprom(jme); 310362306a36Sopenharmony_ci if (rc) { 310462306a36Sopenharmony_ci pr_err("Reload eeprom for reading MAC Address error\n"); 310562306a36Sopenharmony_ci goto err_out_unmap; 310662306a36Sopenharmony_ci } 310762306a36Sopenharmony_ci jme_load_macaddr(netdev); 310862306a36Sopenharmony_ci 310962306a36Sopenharmony_ci /* 311062306a36Sopenharmony_ci * Tell stack that we are not ready to work until open() 311162306a36Sopenharmony_ci */ 311262306a36Sopenharmony_ci netif_carrier_off(netdev); 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci rc = register_netdev(netdev); 311562306a36Sopenharmony_ci if (rc) { 311662306a36Sopenharmony_ci pr_err("Cannot register net device\n"); 311762306a36Sopenharmony_ci goto err_out_unmap; 311862306a36Sopenharmony_ci } 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci netif_info(jme, probe, jme->dev, "%s%s chiprev:%x pcirev:%x macaddr:%pM\n", 312162306a36Sopenharmony_ci (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) ? 312262306a36Sopenharmony_ci "JMC250 Gigabit Ethernet" : 312362306a36Sopenharmony_ci (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC260) ? 312462306a36Sopenharmony_ci "JMC260 Fast Ethernet" : "Unknown", 312562306a36Sopenharmony_ci (jme->fpgaver != 0) ? " (FPGA)" : "", 312662306a36Sopenharmony_ci (jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev, 312762306a36Sopenharmony_ci jme->pcirev, netdev->dev_addr); 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ci return 0; 313062306a36Sopenharmony_ci 313162306a36Sopenharmony_cierr_out_unmap: 313262306a36Sopenharmony_ci iounmap(jme->regs); 313362306a36Sopenharmony_cierr_out_free_netdev: 313462306a36Sopenharmony_ci free_netdev(netdev); 313562306a36Sopenharmony_cierr_out_release_regions: 313662306a36Sopenharmony_ci pci_release_regions(pdev); 313762306a36Sopenharmony_cierr_out_disable_pdev: 313862306a36Sopenharmony_ci pci_disable_device(pdev); 313962306a36Sopenharmony_cierr_out: 314062306a36Sopenharmony_ci return rc; 314162306a36Sopenharmony_ci} 314262306a36Sopenharmony_ci 314362306a36Sopenharmony_cistatic void 314462306a36Sopenharmony_cijme_remove_one(struct pci_dev *pdev) 314562306a36Sopenharmony_ci{ 314662306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 314762306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci unregister_netdev(netdev); 315062306a36Sopenharmony_ci iounmap(jme->regs); 315162306a36Sopenharmony_ci free_netdev(netdev); 315262306a36Sopenharmony_ci pci_release_regions(pdev); 315362306a36Sopenharmony_ci pci_disable_device(pdev); 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci} 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_cistatic void 315862306a36Sopenharmony_cijme_shutdown(struct pci_dev *pdev) 315962306a36Sopenharmony_ci{ 316062306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 316162306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_ci jme_powersave_phy(jme); 316462306a36Sopenharmony_ci pci_pme_active(pdev, true); 316562306a36Sopenharmony_ci} 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 316862306a36Sopenharmony_cistatic int 316962306a36Sopenharmony_cijme_suspend(struct device *dev) 317062306a36Sopenharmony_ci{ 317162306a36Sopenharmony_ci struct net_device *netdev = dev_get_drvdata(dev); 317262306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci if (!netif_running(netdev)) 317562306a36Sopenharmony_ci return 0; 317662306a36Sopenharmony_ci 317762306a36Sopenharmony_ci atomic_dec(&jme->link_changing); 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_ci netif_device_detach(netdev); 318062306a36Sopenharmony_ci netif_stop_queue(netdev); 318162306a36Sopenharmony_ci jme_stop_irq(jme); 318262306a36Sopenharmony_ci 318362306a36Sopenharmony_ci tasklet_disable(&jme->txclean_task); 318462306a36Sopenharmony_ci tasklet_disable(&jme->rxclean_task); 318562306a36Sopenharmony_ci tasklet_disable(&jme->rxempty_task); 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci if (netif_carrier_ok(netdev)) { 318862306a36Sopenharmony_ci if (test_bit(JME_FLAG_POLL, &jme->flags)) 318962306a36Sopenharmony_ci jme_polling_mode(jme); 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci jme_stop_pcc_timer(jme); 319262306a36Sopenharmony_ci jme_disable_rx_engine(jme); 319362306a36Sopenharmony_ci jme_disable_tx_engine(jme); 319462306a36Sopenharmony_ci jme_reset_mac_processor(jme); 319562306a36Sopenharmony_ci jme_free_rx_resources(jme); 319662306a36Sopenharmony_ci jme_free_tx_resources(jme); 319762306a36Sopenharmony_ci netif_carrier_off(netdev); 319862306a36Sopenharmony_ci jme->phylink = 0; 319962306a36Sopenharmony_ci } 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_ci tasklet_enable(&jme->txclean_task); 320262306a36Sopenharmony_ci tasklet_enable(&jme->rxclean_task); 320362306a36Sopenharmony_ci tasklet_enable(&jme->rxempty_task); 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_ci jme_powersave_phy(jme); 320662306a36Sopenharmony_ci 320762306a36Sopenharmony_ci return 0; 320862306a36Sopenharmony_ci} 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_cistatic int 321162306a36Sopenharmony_cijme_resume(struct device *dev) 321262306a36Sopenharmony_ci{ 321362306a36Sopenharmony_ci struct net_device *netdev = dev_get_drvdata(dev); 321462306a36Sopenharmony_ci struct jme_adapter *jme = netdev_priv(netdev); 321562306a36Sopenharmony_ci 321662306a36Sopenharmony_ci if (!netif_running(netdev)) 321762306a36Sopenharmony_ci return 0; 321862306a36Sopenharmony_ci 321962306a36Sopenharmony_ci jme_clear_pm_disable_wol(jme); 322062306a36Sopenharmony_ci jme_phy_on(jme); 322162306a36Sopenharmony_ci if (test_bit(JME_FLAG_SSET, &jme->flags)) 322262306a36Sopenharmony_ci jme_set_link_ksettings(netdev, &jme->old_cmd); 322362306a36Sopenharmony_ci else 322462306a36Sopenharmony_ci jme_reset_phy_processor(jme); 322562306a36Sopenharmony_ci jme_phy_calibration(jme); 322662306a36Sopenharmony_ci jme_phy_setEA(jme); 322762306a36Sopenharmony_ci netif_device_attach(netdev); 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_ci atomic_inc(&jme->link_changing); 323062306a36Sopenharmony_ci 323162306a36Sopenharmony_ci jme_reset_link(jme); 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci jme_start_irq(jme); 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci return 0; 323662306a36Sopenharmony_ci} 323762306a36Sopenharmony_ci 323862306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(jme_pm_ops, jme_suspend, jme_resume); 323962306a36Sopenharmony_ci#define JME_PM_OPS (&jme_pm_ops) 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ci#else 324262306a36Sopenharmony_ci 324362306a36Sopenharmony_ci#define JME_PM_OPS NULL 324462306a36Sopenharmony_ci#endif 324562306a36Sopenharmony_ci 324662306a36Sopenharmony_cistatic const struct pci_device_id jme_pci_tbl[] = { 324762306a36Sopenharmony_ci { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC250) }, 324862306a36Sopenharmony_ci { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC260) }, 324962306a36Sopenharmony_ci { } 325062306a36Sopenharmony_ci}; 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_cistatic struct pci_driver jme_driver = { 325362306a36Sopenharmony_ci .name = DRV_NAME, 325462306a36Sopenharmony_ci .id_table = jme_pci_tbl, 325562306a36Sopenharmony_ci .probe = jme_init_one, 325662306a36Sopenharmony_ci .remove = jme_remove_one, 325762306a36Sopenharmony_ci .shutdown = jme_shutdown, 325862306a36Sopenharmony_ci .driver.pm = JME_PM_OPS, 325962306a36Sopenharmony_ci}; 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_cistatic int __init 326262306a36Sopenharmony_cijme_init_module(void) 326362306a36Sopenharmony_ci{ 326462306a36Sopenharmony_ci pr_info("JMicron JMC2XX ethernet driver version %s\n", DRV_VERSION); 326562306a36Sopenharmony_ci return pci_register_driver(&jme_driver); 326662306a36Sopenharmony_ci} 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_cistatic void __exit 326962306a36Sopenharmony_cijme_cleanup_module(void) 327062306a36Sopenharmony_ci{ 327162306a36Sopenharmony_ci pci_unregister_driver(&jme_driver); 327262306a36Sopenharmony_ci} 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_cimodule_init(jme_init_module); 327562306a36Sopenharmony_cimodule_exit(jme_cleanup_module); 327662306a36Sopenharmony_ci 327762306a36Sopenharmony_ciMODULE_AUTHOR("Guo-Fu Tseng <cooldavid@cooldavid.org>"); 327862306a36Sopenharmony_ciMODULE_DESCRIPTION("JMicron JMC2x0 PCI Express Ethernet driver"); 327962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 328062306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 328162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, jme_pci_tbl); 3282