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, &reg);
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, &reg);
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