18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * JMicron JMC2x0 series PCIe Ethernet Linux Device Driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2008 JMicron Technology Corporation
68c2ecf20Sopenharmony_ci * https://www.jmicron.com/
78c2ecf20Sopenharmony_ci * Copyright (c) 2009 - 2010 Guo-Fu Tseng <cooldavid@cooldavid.org>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Author: Guo-Fu Tseng <cooldavid@cooldavid.org>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/kernel.h>
168c2ecf20Sopenharmony_ci#include <linux/pci.h>
178c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
188c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
198c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
208c2ecf20Sopenharmony_ci#include <linux/mii.h>
218c2ecf20Sopenharmony_ci#include <linux/crc32.h>
228c2ecf20Sopenharmony_ci#include <linux/delay.h>
238c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
248c2ecf20Sopenharmony_ci#include <linux/in.h>
258c2ecf20Sopenharmony_ci#include <linux/ip.h>
268c2ecf20Sopenharmony_ci#include <linux/ipv6.h>
278c2ecf20Sopenharmony_ci#include <linux/tcp.h>
288c2ecf20Sopenharmony_ci#include <linux/udp.h>
298c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
308c2ecf20Sopenharmony_ci#include <linux/slab.h>
318c2ecf20Sopenharmony_ci#include <net/ip6_checksum.h>
328c2ecf20Sopenharmony_ci#include "jme.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic int force_pseudohp = -1;
358c2ecf20Sopenharmony_cistatic int no_pseudohp = -1;
368c2ecf20Sopenharmony_cistatic int no_extplug = -1;
378c2ecf20Sopenharmony_cimodule_param(force_pseudohp, int, 0);
388c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force_pseudohp,
398c2ecf20Sopenharmony_ci	"Enable pseudo hot-plug feature manually by driver instead of BIOS.");
408c2ecf20Sopenharmony_cimodule_param(no_pseudohp, int, 0);
418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(no_pseudohp, "Disable pseudo hot-plug feature.");
428c2ecf20Sopenharmony_cimodule_param(no_extplug, int, 0);
438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(no_extplug,
448c2ecf20Sopenharmony_ci	"Do not use external plug signal for pseudo hot-plug.");
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic int
478c2ecf20Sopenharmony_cijme_mdio_read(struct net_device *netdev, int phy, int reg)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
508c2ecf20Sopenharmony_ci	int i, val, again = (reg == MII_BMSR) ? 1 : 0;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciread_again:
538c2ecf20Sopenharmony_ci	jwrite32(jme, JME_SMI, SMI_OP_REQ |
548c2ecf20Sopenharmony_ci				smi_phy_addr(phy) |
558c2ecf20Sopenharmony_ci				smi_reg_addr(reg));
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	wmb();
588c2ecf20Sopenharmony_ci	for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) {
598c2ecf20Sopenharmony_ci		udelay(20);
608c2ecf20Sopenharmony_ci		val = jread32(jme, JME_SMI);
618c2ecf20Sopenharmony_ci		if ((val & SMI_OP_REQ) == 0)
628c2ecf20Sopenharmony_ci			break;
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	if (i == 0) {
668c2ecf20Sopenharmony_ci		pr_err("phy(%d) read timeout : %d\n", phy, reg);
678c2ecf20Sopenharmony_ci		return 0;
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	if (again--)
718c2ecf20Sopenharmony_ci		goto read_again;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return (val & SMI_DATA_MASK) >> SMI_DATA_SHIFT;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic void
778c2ecf20Sopenharmony_cijme_mdio_write(struct net_device *netdev,
788c2ecf20Sopenharmony_ci				int phy, int reg, int val)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
818c2ecf20Sopenharmony_ci	int i;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	jwrite32(jme, JME_SMI, SMI_OP_WRITE | SMI_OP_REQ |
848c2ecf20Sopenharmony_ci		((val << SMI_DATA_SHIFT) & SMI_DATA_MASK) |
858c2ecf20Sopenharmony_ci		smi_phy_addr(phy) | smi_reg_addr(reg));
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	wmb();
888c2ecf20Sopenharmony_ci	for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) {
898c2ecf20Sopenharmony_ci		udelay(20);
908c2ecf20Sopenharmony_ci		if ((jread32(jme, JME_SMI) & SMI_OP_REQ) == 0)
918c2ecf20Sopenharmony_ci			break;
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (i == 0)
958c2ecf20Sopenharmony_ci		pr_err("phy(%d) write timeout : %d\n", phy, reg);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic inline void
998c2ecf20Sopenharmony_cijme_reset_phy_processor(struct jme_adapter *jme)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	u32 val;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	jme_mdio_write(jme->dev,
1048c2ecf20Sopenharmony_ci			jme->mii_if.phy_id,
1058c2ecf20Sopenharmony_ci			MII_ADVERTISE, ADVERTISE_ALL |
1068c2ecf20Sopenharmony_ci			ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	if (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250)
1098c2ecf20Sopenharmony_ci		jme_mdio_write(jme->dev,
1108c2ecf20Sopenharmony_ci				jme->mii_if.phy_id,
1118c2ecf20Sopenharmony_ci				MII_CTRL1000,
1128c2ecf20Sopenharmony_ci				ADVERTISE_1000FULL | ADVERTISE_1000HALF);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	val = jme_mdio_read(jme->dev,
1158c2ecf20Sopenharmony_ci				jme->mii_if.phy_id,
1168c2ecf20Sopenharmony_ci				MII_BMCR);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	jme_mdio_write(jme->dev,
1198c2ecf20Sopenharmony_ci			jme->mii_if.phy_id,
1208c2ecf20Sopenharmony_ci			MII_BMCR, val | BMCR_RESET);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic void
1248c2ecf20Sopenharmony_cijme_setup_wakeup_frame(struct jme_adapter *jme,
1258c2ecf20Sopenharmony_ci		       const u32 *mask, u32 crc, int fnr)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	int i;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/*
1308c2ecf20Sopenharmony_ci	 * Setup CRC pattern
1318c2ecf20Sopenharmony_ci	 */
1328c2ecf20Sopenharmony_ci	jwrite32(jme, JME_WFOI, WFOI_CRC_SEL | (fnr & WFOI_FRAME_SEL));
1338c2ecf20Sopenharmony_ci	wmb();
1348c2ecf20Sopenharmony_ci	jwrite32(jme, JME_WFODP, crc);
1358c2ecf20Sopenharmony_ci	wmb();
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	/*
1388c2ecf20Sopenharmony_ci	 * Setup Mask
1398c2ecf20Sopenharmony_ci	 */
1408c2ecf20Sopenharmony_ci	for (i = 0 ; i < WAKEUP_FRAME_MASK_DWNR ; ++i) {
1418c2ecf20Sopenharmony_ci		jwrite32(jme, JME_WFOI,
1428c2ecf20Sopenharmony_ci				((i << WFOI_MASK_SHIFT) & WFOI_MASK_SEL) |
1438c2ecf20Sopenharmony_ci				(fnr & WFOI_FRAME_SEL));
1448c2ecf20Sopenharmony_ci		wmb();
1458c2ecf20Sopenharmony_ci		jwrite32(jme, JME_WFODP, mask[i]);
1468c2ecf20Sopenharmony_ci		wmb();
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic inline void
1518c2ecf20Sopenharmony_cijme_mac_rxclk_off(struct jme_adapter *jme)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	jme->reg_gpreg1 |= GPREG1_RXCLKOFF;
1548c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_GPREG1, jme->reg_gpreg1);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic inline void
1588c2ecf20Sopenharmony_cijme_mac_rxclk_on(struct jme_adapter *jme)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	jme->reg_gpreg1 &= ~GPREG1_RXCLKOFF;
1618c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_GPREG1, jme->reg_gpreg1);
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic inline void
1658c2ecf20Sopenharmony_cijme_mac_txclk_off(struct jme_adapter *jme)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	jme->reg_ghc &= ~(GHC_TO_CLK_SRC | GHC_TXMAC_CLK_SRC);
1688c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_GHC, jme->reg_ghc);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic inline void
1728c2ecf20Sopenharmony_cijme_mac_txclk_on(struct jme_adapter *jme)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	u32 speed = jme->reg_ghc & GHC_SPEED;
1758c2ecf20Sopenharmony_ci	if (speed == GHC_SPEED_1000M)
1768c2ecf20Sopenharmony_ci		jme->reg_ghc |= GHC_TO_CLK_GPHY | GHC_TXMAC_CLK_GPHY;
1778c2ecf20Sopenharmony_ci	else
1788c2ecf20Sopenharmony_ci		jme->reg_ghc |= GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE;
1798c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_GHC, jme->reg_ghc);
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic inline void
1838c2ecf20Sopenharmony_cijme_reset_ghc_speed(struct jme_adapter *jme)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	jme->reg_ghc &= ~(GHC_SPEED | GHC_DPX);
1868c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_GHC, jme->reg_ghc);
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic inline void
1908c2ecf20Sopenharmony_cijme_reset_250A2_workaround(struct jme_adapter *jme)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	jme->reg_gpreg1 &= ~(GPREG1_HALFMODEPATCH |
1938c2ecf20Sopenharmony_ci			     GPREG1_RSSPATCH);
1948c2ecf20Sopenharmony_ci	jwrite32(jme, JME_GPREG1, jme->reg_gpreg1);
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic inline void
1988c2ecf20Sopenharmony_cijme_assert_ghc_reset(struct jme_adapter *jme)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	jme->reg_ghc |= GHC_SWRST;
2018c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_GHC, jme->reg_ghc);
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic inline void
2058c2ecf20Sopenharmony_cijme_clear_ghc_reset(struct jme_adapter *jme)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	jme->reg_ghc &= ~GHC_SWRST;
2088c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_GHC, jme->reg_ghc);
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic void
2128c2ecf20Sopenharmony_cijme_reset_mac_processor(struct jme_adapter *jme)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	static const u32 mask[WAKEUP_FRAME_MASK_DWNR] = {0, 0, 0, 0};
2158c2ecf20Sopenharmony_ci	u32 crc = 0xCDCDCDCD;
2168c2ecf20Sopenharmony_ci	u32 gpreg0;
2178c2ecf20Sopenharmony_ci	int i;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	jme_reset_ghc_speed(jme);
2208c2ecf20Sopenharmony_ci	jme_reset_250A2_workaround(jme);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	jme_mac_rxclk_on(jme);
2238c2ecf20Sopenharmony_ci	jme_mac_txclk_on(jme);
2248c2ecf20Sopenharmony_ci	udelay(1);
2258c2ecf20Sopenharmony_ci	jme_assert_ghc_reset(jme);
2268c2ecf20Sopenharmony_ci	udelay(1);
2278c2ecf20Sopenharmony_ci	jme_mac_rxclk_off(jme);
2288c2ecf20Sopenharmony_ci	jme_mac_txclk_off(jme);
2298c2ecf20Sopenharmony_ci	udelay(1);
2308c2ecf20Sopenharmony_ci	jme_clear_ghc_reset(jme);
2318c2ecf20Sopenharmony_ci	udelay(1);
2328c2ecf20Sopenharmony_ci	jme_mac_rxclk_on(jme);
2338c2ecf20Sopenharmony_ci	jme_mac_txclk_on(jme);
2348c2ecf20Sopenharmony_ci	udelay(1);
2358c2ecf20Sopenharmony_ci	jme_mac_rxclk_off(jme);
2368c2ecf20Sopenharmony_ci	jme_mac_txclk_off(jme);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXDBA_LO, 0x00000000);
2398c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXDBA_HI, 0x00000000);
2408c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXQDC, 0x00000000);
2418c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXNDA, 0x00000000);
2428c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TXDBA_LO, 0x00000000);
2438c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TXDBA_HI, 0x00000000);
2448c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TXQDC, 0x00000000);
2458c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TXNDA, 0x00000000);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXMCHT_LO, 0x00000000);
2488c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXMCHT_HI, 0x00000000);
2498c2ecf20Sopenharmony_ci	for (i = 0 ; i < WAKEUP_FRAME_NR ; ++i)
2508c2ecf20Sopenharmony_ci		jme_setup_wakeup_frame(jme, mask, crc, i);
2518c2ecf20Sopenharmony_ci	if (jme->fpgaver)
2528c2ecf20Sopenharmony_ci		gpreg0 = GPREG0_DEFAULT | GPREG0_LNKINTPOLL;
2538c2ecf20Sopenharmony_ci	else
2548c2ecf20Sopenharmony_ci		gpreg0 = GPREG0_DEFAULT;
2558c2ecf20Sopenharmony_ci	jwrite32(jme, JME_GPREG0, gpreg0);
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic inline void
2598c2ecf20Sopenharmony_cijme_clear_pm_enable_wol(struct jme_adapter *jme)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	jwrite32(jme, JME_PMCS, PMCS_STMASK | jme->reg_pmcs);
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic inline void
2658c2ecf20Sopenharmony_cijme_clear_pm_disable_wol(struct jme_adapter *jme)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	jwrite32(jme, JME_PMCS, PMCS_STMASK);
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic int
2718c2ecf20Sopenharmony_cijme_reload_eeprom(struct jme_adapter *jme)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	u32 val;
2748c2ecf20Sopenharmony_ci	int i;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	val = jread32(jme, JME_SMBCSR);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (val & SMBCSR_EEPROMD) {
2798c2ecf20Sopenharmony_ci		val |= SMBCSR_CNACK;
2808c2ecf20Sopenharmony_ci		jwrite32(jme, JME_SMBCSR, val);
2818c2ecf20Sopenharmony_ci		val |= SMBCSR_RELOAD;
2828c2ecf20Sopenharmony_ci		jwrite32(jme, JME_SMBCSR, val);
2838c2ecf20Sopenharmony_ci		mdelay(12);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci		for (i = JME_EEPROM_RELOAD_TIMEOUT; i > 0; --i) {
2868c2ecf20Sopenharmony_ci			mdelay(1);
2878c2ecf20Sopenharmony_ci			if ((jread32(jme, JME_SMBCSR) & SMBCSR_RELOAD) == 0)
2888c2ecf20Sopenharmony_ci				break;
2898c2ecf20Sopenharmony_ci		}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci		if (i == 0) {
2928c2ecf20Sopenharmony_ci			pr_err("eeprom reload timeout\n");
2938c2ecf20Sopenharmony_ci			return -EIO;
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	return 0;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic void
3018c2ecf20Sopenharmony_cijme_load_macaddr(struct net_device *netdev)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
3048c2ecf20Sopenharmony_ci	unsigned char macaddr[ETH_ALEN];
3058c2ecf20Sopenharmony_ci	u32 val;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	spin_lock_bh(&jme->macaddr_lock);
3088c2ecf20Sopenharmony_ci	val = jread32(jme, JME_RXUMA_LO);
3098c2ecf20Sopenharmony_ci	macaddr[0] = (val >>  0) & 0xFF;
3108c2ecf20Sopenharmony_ci	macaddr[1] = (val >>  8) & 0xFF;
3118c2ecf20Sopenharmony_ci	macaddr[2] = (val >> 16) & 0xFF;
3128c2ecf20Sopenharmony_ci	macaddr[3] = (val >> 24) & 0xFF;
3138c2ecf20Sopenharmony_ci	val = jread32(jme, JME_RXUMA_HI);
3148c2ecf20Sopenharmony_ci	macaddr[4] = (val >>  0) & 0xFF;
3158c2ecf20Sopenharmony_ci	macaddr[5] = (val >>  8) & 0xFF;
3168c2ecf20Sopenharmony_ci	memcpy(netdev->dev_addr, macaddr, ETH_ALEN);
3178c2ecf20Sopenharmony_ci	spin_unlock_bh(&jme->macaddr_lock);
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic inline void
3218c2ecf20Sopenharmony_cijme_set_rx_pcc(struct jme_adapter *jme, int p)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	switch (p) {
3248c2ecf20Sopenharmony_ci	case PCC_OFF:
3258c2ecf20Sopenharmony_ci		jwrite32(jme, JME_PCCRX0,
3268c2ecf20Sopenharmony_ci			((PCC_OFF_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) |
3278c2ecf20Sopenharmony_ci			((PCC_OFF_CNT << PCCRX_SHIFT) & PCCRX_MASK));
3288c2ecf20Sopenharmony_ci		break;
3298c2ecf20Sopenharmony_ci	case PCC_P1:
3308c2ecf20Sopenharmony_ci		jwrite32(jme, JME_PCCRX0,
3318c2ecf20Sopenharmony_ci			((PCC_P1_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) |
3328c2ecf20Sopenharmony_ci			((PCC_P1_CNT << PCCRX_SHIFT) & PCCRX_MASK));
3338c2ecf20Sopenharmony_ci		break;
3348c2ecf20Sopenharmony_ci	case PCC_P2:
3358c2ecf20Sopenharmony_ci		jwrite32(jme, JME_PCCRX0,
3368c2ecf20Sopenharmony_ci			((PCC_P2_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) |
3378c2ecf20Sopenharmony_ci			((PCC_P2_CNT << PCCRX_SHIFT) & PCCRX_MASK));
3388c2ecf20Sopenharmony_ci		break;
3398c2ecf20Sopenharmony_ci	case PCC_P3:
3408c2ecf20Sopenharmony_ci		jwrite32(jme, JME_PCCRX0,
3418c2ecf20Sopenharmony_ci			((PCC_P3_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) |
3428c2ecf20Sopenharmony_ci			((PCC_P3_CNT << PCCRX_SHIFT) & PCCRX_MASK));
3438c2ecf20Sopenharmony_ci		break;
3448c2ecf20Sopenharmony_ci	default:
3458c2ecf20Sopenharmony_ci		break;
3468c2ecf20Sopenharmony_ci	}
3478c2ecf20Sopenharmony_ci	wmb();
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (!(test_bit(JME_FLAG_POLL, &jme->flags)))
3508c2ecf20Sopenharmony_ci		netif_info(jme, rx_status, jme->dev, "Switched to PCC_P%d\n", p);
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic void
3548c2ecf20Sopenharmony_cijme_start_irq(struct jme_adapter *jme)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	register struct dynpcc_info *dpi = &(jme->dpi);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	jme_set_rx_pcc(jme, PCC_P1);
3598c2ecf20Sopenharmony_ci	dpi->cur		= PCC_P1;
3608c2ecf20Sopenharmony_ci	dpi->attempt		= PCC_P1;
3618c2ecf20Sopenharmony_ci	dpi->cnt		= 0;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	jwrite32(jme, JME_PCCTX,
3648c2ecf20Sopenharmony_ci			((PCC_TX_TO << PCCTXTO_SHIFT) & PCCTXTO_MASK) |
3658c2ecf20Sopenharmony_ci			((PCC_TX_CNT << PCCTX_SHIFT) & PCCTX_MASK) |
3668c2ecf20Sopenharmony_ci			PCCTXQ0_EN
3678c2ecf20Sopenharmony_ci		);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	/*
3708c2ecf20Sopenharmony_ci	 * Enable Interrupts
3718c2ecf20Sopenharmony_ci	 */
3728c2ecf20Sopenharmony_ci	jwrite32(jme, JME_IENS, INTR_ENABLE);
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic inline void
3768c2ecf20Sopenharmony_cijme_stop_irq(struct jme_adapter *jme)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	/*
3798c2ecf20Sopenharmony_ci	 * Disable Interrupts
3808c2ecf20Sopenharmony_ci	 */
3818c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_IENC, INTR_ENABLE);
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cistatic u32
3858c2ecf20Sopenharmony_cijme_linkstat_from_phy(struct jme_adapter *jme)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	u32 phylink, bmsr;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	phylink = jme_mdio_read(jme->dev, jme->mii_if.phy_id, 17);
3908c2ecf20Sopenharmony_ci	bmsr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMSR);
3918c2ecf20Sopenharmony_ci	if (bmsr & BMSR_ANCOMP)
3928c2ecf20Sopenharmony_ci		phylink |= PHY_LINK_AUTONEG_COMPLETE;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return phylink;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic inline void
3988c2ecf20Sopenharmony_cijme_set_phyfifo_5level(struct jme_adapter *jme)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0004);
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic inline void
4048c2ecf20Sopenharmony_cijme_set_phyfifo_8level(struct jme_adapter *jme)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0000);
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic int
4108c2ecf20Sopenharmony_cijme_check_link(struct net_device *netdev, int testonly)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
4138c2ecf20Sopenharmony_ci	u32 phylink, cnt = JME_SPDRSV_TIMEOUT, bmcr;
4148c2ecf20Sopenharmony_ci	char linkmsg[64];
4158c2ecf20Sopenharmony_ci	int rc = 0;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	linkmsg[0] = '\0';
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	if (jme->fpgaver)
4208c2ecf20Sopenharmony_ci		phylink = jme_linkstat_from_phy(jme);
4218c2ecf20Sopenharmony_ci	else
4228c2ecf20Sopenharmony_ci		phylink = jread32(jme, JME_PHY_LINK);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (phylink & PHY_LINK_UP) {
4258c2ecf20Sopenharmony_ci		if (!(phylink & PHY_LINK_AUTONEG_COMPLETE)) {
4268c2ecf20Sopenharmony_ci			/*
4278c2ecf20Sopenharmony_ci			 * If we did not enable AN
4288c2ecf20Sopenharmony_ci			 * Speed/Duplex Info should be obtained from SMI
4298c2ecf20Sopenharmony_ci			 */
4308c2ecf20Sopenharmony_ci			phylink = PHY_LINK_UP;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci			bmcr = jme_mdio_read(jme->dev,
4338c2ecf20Sopenharmony_ci						jme->mii_if.phy_id,
4348c2ecf20Sopenharmony_ci						MII_BMCR);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci			phylink |= ((bmcr & BMCR_SPEED1000) &&
4378c2ecf20Sopenharmony_ci					(bmcr & BMCR_SPEED100) == 0) ?
4388c2ecf20Sopenharmony_ci					PHY_LINK_SPEED_1000M :
4398c2ecf20Sopenharmony_ci					(bmcr & BMCR_SPEED100) ?
4408c2ecf20Sopenharmony_ci					PHY_LINK_SPEED_100M :
4418c2ecf20Sopenharmony_ci					PHY_LINK_SPEED_10M;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci			phylink |= (bmcr & BMCR_FULLDPLX) ?
4448c2ecf20Sopenharmony_ci					 PHY_LINK_DUPLEX : 0;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci			strcat(linkmsg, "Forced: ");
4478c2ecf20Sopenharmony_ci		} else {
4488c2ecf20Sopenharmony_ci			/*
4498c2ecf20Sopenharmony_ci			 * Keep polling for speed/duplex resolve complete
4508c2ecf20Sopenharmony_ci			 */
4518c2ecf20Sopenharmony_ci			while (!(phylink & PHY_LINK_SPEEDDPU_RESOLVED) &&
4528c2ecf20Sopenharmony_ci				--cnt) {
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci				udelay(1);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci				if (jme->fpgaver)
4578c2ecf20Sopenharmony_ci					phylink = jme_linkstat_from_phy(jme);
4588c2ecf20Sopenharmony_ci				else
4598c2ecf20Sopenharmony_ci					phylink = jread32(jme, JME_PHY_LINK);
4608c2ecf20Sopenharmony_ci			}
4618c2ecf20Sopenharmony_ci			if (!cnt)
4628c2ecf20Sopenharmony_ci				pr_err("Waiting speed resolve timeout\n");
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci			strcat(linkmsg, "ANed: ");
4658c2ecf20Sopenharmony_ci		}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci		if (jme->phylink == phylink) {
4688c2ecf20Sopenharmony_ci			rc = 1;
4698c2ecf20Sopenharmony_ci			goto out;
4708c2ecf20Sopenharmony_ci		}
4718c2ecf20Sopenharmony_ci		if (testonly)
4728c2ecf20Sopenharmony_ci			goto out;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci		jme->phylink = phylink;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci		/*
4778c2ecf20Sopenharmony_ci		 * The speed/duplex setting of jme->reg_ghc already cleared
4788c2ecf20Sopenharmony_ci		 * by jme_reset_mac_processor()
4798c2ecf20Sopenharmony_ci		 */
4808c2ecf20Sopenharmony_ci		switch (phylink & PHY_LINK_SPEED_MASK) {
4818c2ecf20Sopenharmony_ci		case PHY_LINK_SPEED_10M:
4828c2ecf20Sopenharmony_ci			jme->reg_ghc |= GHC_SPEED_10M;
4838c2ecf20Sopenharmony_ci			strcat(linkmsg, "10 Mbps, ");
4848c2ecf20Sopenharmony_ci			break;
4858c2ecf20Sopenharmony_ci		case PHY_LINK_SPEED_100M:
4868c2ecf20Sopenharmony_ci			jme->reg_ghc |= GHC_SPEED_100M;
4878c2ecf20Sopenharmony_ci			strcat(linkmsg, "100 Mbps, ");
4888c2ecf20Sopenharmony_ci			break;
4898c2ecf20Sopenharmony_ci		case PHY_LINK_SPEED_1000M:
4908c2ecf20Sopenharmony_ci			jme->reg_ghc |= GHC_SPEED_1000M;
4918c2ecf20Sopenharmony_ci			strcat(linkmsg, "1000 Mbps, ");
4928c2ecf20Sopenharmony_ci			break;
4938c2ecf20Sopenharmony_ci		default:
4948c2ecf20Sopenharmony_ci			break;
4958c2ecf20Sopenharmony_ci		}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci		if (phylink & PHY_LINK_DUPLEX) {
4988c2ecf20Sopenharmony_ci			jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT);
4998c2ecf20Sopenharmony_ci			jwrite32(jme, JME_TXTRHD, TXTRHD_FULLDUPLEX);
5008c2ecf20Sopenharmony_ci			jme->reg_ghc |= GHC_DPX;
5018c2ecf20Sopenharmony_ci		} else {
5028c2ecf20Sopenharmony_ci			jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT |
5038c2ecf20Sopenharmony_ci						TXMCS_BACKOFF |
5048c2ecf20Sopenharmony_ci						TXMCS_CARRIERSENSE |
5058c2ecf20Sopenharmony_ci						TXMCS_COLLISION);
5068c2ecf20Sopenharmony_ci			jwrite32(jme, JME_TXTRHD, TXTRHD_HALFDUPLEX);
5078c2ecf20Sopenharmony_ci		}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci		jwrite32(jme, JME_GHC, jme->reg_ghc);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci		if (is_buggy250(jme->pdev->device, jme->chiprev)) {
5128c2ecf20Sopenharmony_ci			jme->reg_gpreg1 &= ~(GPREG1_HALFMODEPATCH |
5138c2ecf20Sopenharmony_ci					     GPREG1_RSSPATCH);
5148c2ecf20Sopenharmony_ci			if (!(phylink & PHY_LINK_DUPLEX))
5158c2ecf20Sopenharmony_ci				jme->reg_gpreg1 |= GPREG1_HALFMODEPATCH;
5168c2ecf20Sopenharmony_ci			switch (phylink & PHY_LINK_SPEED_MASK) {
5178c2ecf20Sopenharmony_ci			case PHY_LINK_SPEED_10M:
5188c2ecf20Sopenharmony_ci				jme_set_phyfifo_8level(jme);
5198c2ecf20Sopenharmony_ci				jme->reg_gpreg1 |= GPREG1_RSSPATCH;
5208c2ecf20Sopenharmony_ci				break;
5218c2ecf20Sopenharmony_ci			case PHY_LINK_SPEED_100M:
5228c2ecf20Sopenharmony_ci				jme_set_phyfifo_5level(jme);
5238c2ecf20Sopenharmony_ci				jme->reg_gpreg1 |= GPREG1_RSSPATCH;
5248c2ecf20Sopenharmony_ci				break;
5258c2ecf20Sopenharmony_ci			case PHY_LINK_SPEED_1000M:
5268c2ecf20Sopenharmony_ci				jme_set_phyfifo_8level(jme);
5278c2ecf20Sopenharmony_ci				break;
5288c2ecf20Sopenharmony_ci			default:
5298c2ecf20Sopenharmony_ci				break;
5308c2ecf20Sopenharmony_ci			}
5318c2ecf20Sopenharmony_ci		}
5328c2ecf20Sopenharmony_ci		jwrite32(jme, JME_GPREG1, jme->reg_gpreg1);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci		strcat(linkmsg, (phylink & PHY_LINK_DUPLEX) ?
5358c2ecf20Sopenharmony_ci					"Full-Duplex, " :
5368c2ecf20Sopenharmony_ci					"Half-Duplex, ");
5378c2ecf20Sopenharmony_ci		strcat(linkmsg, (phylink & PHY_LINK_MDI_STAT) ?
5388c2ecf20Sopenharmony_ci					"MDI-X" :
5398c2ecf20Sopenharmony_ci					"MDI");
5408c2ecf20Sopenharmony_ci		netif_info(jme, link, jme->dev, "Link is up at %s\n", linkmsg);
5418c2ecf20Sopenharmony_ci		netif_carrier_on(netdev);
5428c2ecf20Sopenharmony_ci	} else {
5438c2ecf20Sopenharmony_ci		if (testonly)
5448c2ecf20Sopenharmony_ci			goto out;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci		netif_info(jme, link, jme->dev, "Link is down\n");
5478c2ecf20Sopenharmony_ci		jme->phylink = 0;
5488c2ecf20Sopenharmony_ci		netif_carrier_off(netdev);
5498c2ecf20Sopenharmony_ci	}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ciout:
5528c2ecf20Sopenharmony_ci	return rc;
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_cistatic int
5568c2ecf20Sopenharmony_cijme_setup_tx_resources(struct jme_adapter *jme)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	struct jme_ring *txring = &(jme->txring[0]);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	txring->alloc = dma_alloc_coherent(&(jme->pdev->dev),
5618c2ecf20Sopenharmony_ci				   TX_RING_ALLOC_SIZE(jme->tx_ring_size),
5628c2ecf20Sopenharmony_ci				   &(txring->dmaalloc),
5638c2ecf20Sopenharmony_ci				   GFP_ATOMIC);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	if (!txring->alloc)
5668c2ecf20Sopenharmony_ci		goto err_set_null;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	/*
5698c2ecf20Sopenharmony_ci	 * 16 Bytes align
5708c2ecf20Sopenharmony_ci	 */
5718c2ecf20Sopenharmony_ci	txring->desc		= (void *)ALIGN((unsigned long)(txring->alloc),
5728c2ecf20Sopenharmony_ci						RING_DESC_ALIGN);
5738c2ecf20Sopenharmony_ci	txring->dma		= ALIGN(txring->dmaalloc, RING_DESC_ALIGN);
5748c2ecf20Sopenharmony_ci	txring->next_to_use	= 0;
5758c2ecf20Sopenharmony_ci	atomic_set(&txring->next_to_clean, 0);
5768c2ecf20Sopenharmony_ci	atomic_set(&txring->nr_free, jme->tx_ring_size);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	txring->bufinf		= kcalloc(jme->tx_ring_size,
5798c2ecf20Sopenharmony_ci						sizeof(struct jme_buffer_info),
5808c2ecf20Sopenharmony_ci						GFP_ATOMIC);
5818c2ecf20Sopenharmony_ci	if (unlikely(!(txring->bufinf)))
5828c2ecf20Sopenharmony_ci		goto err_free_txring;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	return 0;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cierr_free_txring:
5878c2ecf20Sopenharmony_ci	dma_free_coherent(&(jme->pdev->dev),
5888c2ecf20Sopenharmony_ci			  TX_RING_ALLOC_SIZE(jme->tx_ring_size),
5898c2ecf20Sopenharmony_ci			  txring->alloc,
5908c2ecf20Sopenharmony_ci			  txring->dmaalloc);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_cierr_set_null:
5938c2ecf20Sopenharmony_ci	txring->desc = NULL;
5948c2ecf20Sopenharmony_ci	txring->dmaalloc = 0;
5958c2ecf20Sopenharmony_ci	txring->dma = 0;
5968c2ecf20Sopenharmony_ci	txring->bufinf = NULL;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	return -ENOMEM;
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic void
6028c2ecf20Sopenharmony_cijme_free_tx_resources(struct jme_adapter *jme)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	int i;
6058c2ecf20Sopenharmony_ci	struct jme_ring *txring = &(jme->txring[0]);
6068c2ecf20Sopenharmony_ci	struct jme_buffer_info *txbi;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	if (txring->alloc) {
6098c2ecf20Sopenharmony_ci		if (txring->bufinf) {
6108c2ecf20Sopenharmony_ci			for (i = 0 ; i < jme->tx_ring_size ; ++i) {
6118c2ecf20Sopenharmony_ci				txbi = txring->bufinf + i;
6128c2ecf20Sopenharmony_ci				if (txbi->skb) {
6138c2ecf20Sopenharmony_ci					dev_kfree_skb(txbi->skb);
6148c2ecf20Sopenharmony_ci					txbi->skb = NULL;
6158c2ecf20Sopenharmony_ci				}
6168c2ecf20Sopenharmony_ci				txbi->mapping		= 0;
6178c2ecf20Sopenharmony_ci				txbi->len		= 0;
6188c2ecf20Sopenharmony_ci				txbi->nr_desc		= 0;
6198c2ecf20Sopenharmony_ci				txbi->start_xmit	= 0;
6208c2ecf20Sopenharmony_ci			}
6218c2ecf20Sopenharmony_ci			kfree(txring->bufinf);
6228c2ecf20Sopenharmony_ci		}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci		dma_free_coherent(&(jme->pdev->dev),
6258c2ecf20Sopenharmony_ci				  TX_RING_ALLOC_SIZE(jme->tx_ring_size),
6268c2ecf20Sopenharmony_ci				  txring->alloc,
6278c2ecf20Sopenharmony_ci				  txring->dmaalloc);
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci		txring->alloc		= NULL;
6308c2ecf20Sopenharmony_ci		txring->desc		= NULL;
6318c2ecf20Sopenharmony_ci		txring->dmaalloc	= 0;
6328c2ecf20Sopenharmony_ci		txring->dma		= 0;
6338c2ecf20Sopenharmony_ci		txring->bufinf		= NULL;
6348c2ecf20Sopenharmony_ci	}
6358c2ecf20Sopenharmony_ci	txring->next_to_use	= 0;
6368c2ecf20Sopenharmony_ci	atomic_set(&txring->next_to_clean, 0);
6378c2ecf20Sopenharmony_ci	atomic_set(&txring->nr_free, 0);
6388c2ecf20Sopenharmony_ci}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_cistatic inline void
6418c2ecf20Sopenharmony_cijme_enable_tx_engine(struct jme_adapter *jme)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	/*
6448c2ecf20Sopenharmony_ci	 * Select Queue 0
6458c2ecf20Sopenharmony_ci	 */
6468c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TXCS, TXCS_DEFAULT | TXCS_SELECT_QUEUE0);
6478c2ecf20Sopenharmony_ci	wmb();
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	/*
6508c2ecf20Sopenharmony_ci	 * Setup TX Queue 0 DMA Bass Address
6518c2ecf20Sopenharmony_ci	 */
6528c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TXDBA_LO, (__u64)jme->txring[0].dma & 0xFFFFFFFFUL);
6538c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TXDBA_HI, (__u64)(jme->txring[0].dma) >> 32);
6548c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TXNDA, (__u64)jme->txring[0].dma & 0xFFFFFFFFUL);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	/*
6578c2ecf20Sopenharmony_ci	 * Setup TX Descptor Count
6588c2ecf20Sopenharmony_ci	 */
6598c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TXQDC, jme->tx_ring_size);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	/*
6628c2ecf20Sopenharmony_ci	 * Enable TX Engine
6638c2ecf20Sopenharmony_ci	 */
6648c2ecf20Sopenharmony_ci	wmb();
6658c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_TXCS, jme->reg_txcs |
6668c2ecf20Sopenharmony_ci				TXCS_SELECT_QUEUE0 |
6678c2ecf20Sopenharmony_ci				TXCS_ENABLE);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	/*
6708c2ecf20Sopenharmony_ci	 * Start clock for TX MAC Processor
6718c2ecf20Sopenharmony_ci	 */
6728c2ecf20Sopenharmony_ci	jme_mac_txclk_on(jme);
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_cistatic inline void
6768c2ecf20Sopenharmony_cijme_disable_tx_engine(struct jme_adapter *jme)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	int i;
6798c2ecf20Sopenharmony_ci	u32 val;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	/*
6828c2ecf20Sopenharmony_ci	 * Disable TX Engine
6838c2ecf20Sopenharmony_ci	 */
6848c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TXCS, jme->reg_txcs | TXCS_SELECT_QUEUE0);
6858c2ecf20Sopenharmony_ci	wmb();
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	val = jread32(jme, JME_TXCS);
6888c2ecf20Sopenharmony_ci	for (i = JME_TX_DISABLE_TIMEOUT ; (val & TXCS_ENABLE) && i > 0 ; --i) {
6898c2ecf20Sopenharmony_ci		mdelay(1);
6908c2ecf20Sopenharmony_ci		val = jread32(jme, JME_TXCS);
6918c2ecf20Sopenharmony_ci		rmb();
6928c2ecf20Sopenharmony_ci	}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	if (!i)
6958c2ecf20Sopenharmony_ci		pr_err("Disable TX engine timeout\n");
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	/*
6988c2ecf20Sopenharmony_ci	 * Stop clock for TX MAC Processor
6998c2ecf20Sopenharmony_ci	 */
7008c2ecf20Sopenharmony_ci	jme_mac_txclk_off(jme);
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_cistatic void
7048c2ecf20Sopenharmony_cijme_set_clean_rxdesc(struct jme_adapter *jme, int i)
7058c2ecf20Sopenharmony_ci{
7068c2ecf20Sopenharmony_ci	struct jme_ring *rxring = &(jme->rxring[0]);
7078c2ecf20Sopenharmony_ci	register struct rxdesc *rxdesc = rxring->desc;
7088c2ecf20Sopenharmony_ci	struct jme_buffer_info *rxbi = rxring->bufinf;
7098c2ecf20Sopenharmony_ci	rxdesc += i;
7108c2ecf20Sopenharmony_ci	rxbi += i;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	rxdesc->dw[0] = 0;
7138c2ecf20Sopenharmony_ci	rxdesc->dw[1] = 0;
7148c2ecf20Sopenharmony_ci	rxdesc->desc1.bufaddrh	= cpu_to_le32((__u64)rxbi->mapping >> 32);
7158c2ecf20Sopenharmony_ci	rxdesc->desc1.bufaddrl	= cpu_to_le32(
7168c2ecf20Sopenharmony_ci					(__u64)rxbi->mapping & 0xFFFFFFFFUL);
7178c2ecf20Sopenharmony_ci	rxdesc->desc1.datalen	= cpu_to_le16(rxbi->len);
7188c2ecf20Sopenharmony_ci	if (jme->dev->features & NETIF_F_HIGHDMA)
7198c2ecf20Sopenharmony_ci		rxdesc->desc1.flags = RXFLAG_64BIT;
7208c2ecf20Sopenharmony_ci	wmb();
7218c2ecf20Sopenharmony_ci	rxdesc->desc1.flags	|= RXFLAG_OWN | RXFLAG_INT;
7228c2ecf20Sopenharmony_ci}
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_cistatic int
7258c2ecf20Sopenharmony_cijme_make_new_rx_buf(struct jme_adapter *jme, int i)
7268c2ecf20Sopenharmony_ci{
7278c2ecf20Sopenharmony_ci	struct jme_ring *rxring = &(jme->rxring[0]);
7288c2ecf20Sopenharmony_ci	struct jme_buffer_info *rxbi = rxring->bufinf + i;
7298c2ecf20Sopenharmony_ci	struct sk_buff *skb;
7308c2ecf20Sopenharmony_ci	dma_addr_t mapping;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	skb = netdev_alloc_skb(jme->dev,
7338c2ecf20Sopenharmony_ci		jme->dev->mtu + RX_EXTRA_LEN);
7348c2ecf20Sopenharmony_ci	if (unlikely(!skb))
7358c2ecf20Sopenharmony_ci		return -ENOMEM;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	mapping = pci_map_page(jme->pdev, virt_to_page(skb->data),
7388c2ecf20Sopenharmony_ci			       offset_in_page(skb->data), skb_tailroom(skb),
7398c2ecf20Sopenharmony_ci			       PCI_DMA_FROMDEVICE);
7408c2ecf20Sopenharmony_ci	if (unlikely(pci_dma_mapping_error(jme->pdev, mapping))) {
7418c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
7428c2ecf20Sopenharmony_ci		return -ENOMEM;
7438c2ecf20Sopenharmony_ci	}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	if (likely(rxbi->mapping))
7468c2ecf20Sopenharmony_ci		pci_unmap_page(jme->pdev, rxbi->mapping,
7478c2ecf20Sopenharmony_ci			       rxbi->len, PCI_DMA_FROMDEVICE);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	rxbi->skb = skb;
7508c2ecf20Sopenharmony_ci	rxbi->len = skb_tailroom(skb);
7518c2ecf20Sopenharmony_ci	rxbi->mapping = mapping;
7528c2ecf20Sopenharmony_ci	return 0;
7538c2ecf20Sopenharmony_ci}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cistatic void
7568c2ecf20Sopenharmony_cijme_free_rx_buf(struct jme_adapter *jme, int i)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	struct jme_ring *rxring = &(jme->rxring[0]);
7598c2ecf20Sopenharmony_ci	struct jme_buffer_info *rxbi = rxring->bufinf;
7608c2ecf20Sopenharmony_ci	rxbi += i;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	if (rxbi->skb) {
7638c2ecf20Sopenharmony_ci		pci_unmap_page(jme->pdev,
7648c2ecf20Sopenharmony_ci				 rxbi->mapping,
7658c2ecf20Sopenharmony_ci				 rxbi->len,
7668c2ecf20Sopenharmony_ci				 PCI_DMA_FROMDEVICE);
7678c2ecf20Sopenharmony_ci		dev_kfree_skb(rxbi->skb);
7688c2ecf20Sopenharmony_ci		rxbi->skb = NULL;
7698c2ecf20Sopenharmony_ci		rxbi->mapping = 0;
7708c2ecf20Sopenharmony_ci		rxbi->len = 0;
7718c2ecf20Sopenharmony_ci	}
7728c2ecf20Sopenharmony_ci}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_cistatic void
7758c2ecf20Sopenharmony_cijme_free_rx_resources(struct jme_adapter *jme)
7768c2ecf20Sopenharmony_ci{
7778c2ecf20Sopenharmony_ci	int i;
7788c2ecf20Sopenharmony_ci	struct jme_ring *rxring = &(jme->rxring[0]);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	if (rxring->alloc) {
7818c2ecf20Sopenharmony_ci		if (rxring->bufinf) {
7828c2ecf20Sopenharmony_ci			for (i = 0 ; i < jme->rx_ring_size ; ++i)
7838c2ecf20Sopenharmony_ci				jme_free_rx_buf(jme, i);
7848c2ecf20Sopenharmony_ci			kfree(rxring->bufinf);
7858c2ecf20Sopenharmony_ci		}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci		dma_free_coherent(&(jme->pdev->dev),
7888c2ecf20Sopenharmony_ci				  RX_RING_ALLOC_SIZE(jme->rx_ring_size),
7898c2ecf20Sopenharmony_ci				  rxring->alloc,
7908c2ecf20Sopenharmony_ci				  rxring->dmaalloc);
7918c2ecf20Sopenharmony_ci		rxring->alloc    = NULL;
7928c2ecf20Sopenharmony_ci		rxring->desc     = NULL;
7938c2ecf20Sopenharmony_ci		rxring->dmaalloc = 0;
7948c2ecf20Sopenharmony_ci		rxring->dma      = 0;
7958c2ecf20Sopenharmony_ci		rxring->bufinf   = NULL;
7968c2ecf20Sopenharmony_ci	}
7978c2ecf20Sopenharmony_ci	rxring->next_to_use   = 0;
7988c2ecf20Sopenharmony_ci	atomic_set(&rxring->next_to_clean, 0);
7998c2ecf20Sopenharmony_ci}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_cistatic int
8028c2ecf20Sopenharmony_cijme_setup_rx_resources(struct jme_adapter *jme)
8038c2ecf20Sopenharmony_ci{
8048c2ecf20Sopenharmony_ci	int i;
8058c2ecf20Sopenharmony_ci	struct jme_ring *rxring = &(jme->rxring[0]);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	rxring->alloc = dma_alloc_coherent(&(jme->pdev->dev),
8088c2ecf20Sopenharmony_ci				   RX_RING_ALLOC_SIZE(jme->rx_ring_size),
8098c2ecf20Sopenharmony_ci				   &(rxring->dmaalloc),
8108c2ecf20Sopenharmony_ci				   GFP_ATOMIC);
8118c2ecf20Sopenharmony_ci	if (!rxring->alloc)
8128c2ecf20Sopenharmony_ci		goto err_set_null;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	/*
8158c2ecf20Sopenharmony_ci	 * 16 Bytes align
8168c2ecf20Sopenharmony_ci	 */
8178c2ecf20Sopenharmony_ci	rxring->desc		= (void *)ALIGN((unsigned long)(rxring->alloc),
8188c2ecf20Sopenharmony_ci						RING_DESC_ALIGN);
8198c2ecf20Sopenharmony_ci	rxring->dma		= ALIGN(rxring->dmaalloc, RING_DESC_ALIGN);
8208c2ecf20Sopenharmony_ci	rxring->next_to_use	= 0;
8218c2ecf20Sopenharmony_ci	atomic_set(&rxring->next_to_clean, 0);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	rxring->bufinf		= kcalloc(jme->rx_ring_size,
8248c2ecf20Sopenharmony_ci						sizeof(struct jme_buffer_info),
8258c2ecf20Sopenharmony_ci						GFP_ATOMIC);
8268c2ecf20Sopenharmony_ci	if (unlikely(!(rxring->bufinf)))
8278c2ecf20Sopenharmony_ci		goto err_free_rxring;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	/*
8308c2ecf20Sopenharmony_ci	 * Initiallize Receive Descriptors
8318c2ecf20Sopenharmony_ci	 */
8328c2ecf20Sopenharmony_ci	for (i = 0 ; i < jme->rx_ring_size ; ++i) {
8338c2ecf20Sopenharmony_ci		if (unlikely(jme_make_new_rx_buf(jme, i))) {
8348c2ecf20Sopenharmony_ci			jme_free_rx_resources(jme);
8358c2ecf20Sopenharmony_ci			return -ENOMEM;
8368c2ecf20Sopenharmony_ci		}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci		jme_set_clean_rxdesc(jme, i);
8398c2ecf20Sopenharmony_ci	}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	return 0;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_cierr_free_rxring:
8448c2ecf20Sopenharmony_ci	dma_free_coherent(&(jme->pdev->dev),
8458c2ecf20Sopenharmony_ci			  RX_RING_ALLOC_SIZE(jme->rx_ring_size),
8468c2ecf20Sopenharmony_ci			  rxring->alloc,
8478c2ecf20Sopenharmony_ci			  rxring->dmaalloc);
8488c2ecf20Sopenharmony_cierr_set_null:
8498c2ecf20Sopenharmony_ci	rxring->desc = NULL;
8508c2ecf20Sopenharmony_ci	rxring->dmaalloc = 0;
8518c2ecf20Sopenharmony_ci	rxring->dma = 0;
8528c2ecf20Sopenharmony_ci	rxring->bufinf = NULL;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	return -ENOMEM;
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_cistatic inline void
8588c2ecf20Sopenharmony_cijme_enable_rx_engine(struct jme_adapter *jme)
8598c2ecf20Sopenharmony_ci{
8608c2ecf20Sopenharmony_ci	/*
8618c2ecf20Sopenharmony_ci	 * Select Queue 0
8628c2ecf20Sopenharmony_ci	 */
8638c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXCS, jme->reg_rxcs |
8648c2ecf20Sopenharmony_ci				RXCS_QUEUESEL_Q0);
8658c2ecf20Sopenharmony_ci	wmb();
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	/*
8688c2ecf20Sopenharmony_ci	 * Setup RX DMA Bass Address
8698c2ecf20Sopenharmony_ci	 */
8708c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXDBA_LO, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL);
8718c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXDBA_HI, (__u64)(jme->rxring[0].dma) >> 32);
8728c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXNDA, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	/*
8758c2ecf20Sopenharmony_ci	 * Setup RX Descriptor Count
8768c2ecf20Sopenharmony_ci	 */
8778c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXQDC, jme->rx_ring_size);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	/*
8808c2ecf20Sopenharmony_ci	 * Setup Unicast Filter
8818c2ecf20Sopenharmony_ci	 */
8828c2ecf20Sopenharmony_ci	jme_set_unicastaddr(jme->dev);
8838c2ecf20Sopenharmony_ci	jme_set_multi(jme->dev);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	/*
8868c2ecf20Sopenharmony_ci	 * Enable RX Engine
8878c2ecf20Sopenharmony_ci	 */
8888c2ecf20Sopenharmony_ci	wmb();
8898c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_RXCS, jme->reg_rxcs |
8908c2ecf20Sopenharmony_ci				RXCS_QUEUESEL_Q0 |
8918c2ecf20Sopenharmony_ci				RXCS_ENABLE |
8928c2ecf20Sopenharmony_ci				RXCS_QST);
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	/*
8958c2ecf20Sopenharmony_ci	 * Start clock for RX MAC Processor
8968c2ecf20Sopenharmony_ci	 */
8978c2ecf20Sopenharmony_ci	jme_mac_rxclk_on(jme);
8988c2ecf20Sopenharmony_ci}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_cistatic inline void
9018c2ecf20Sopenharmony_cijme_restart_rx_engine(struct jme_adapter *jme)
9028c2ecf20Sopenharmony_ci{
9038c2ecf20Sopenharmony_ci	/*
9048c2ecf20Sopenharmony_ci	 * Start RX Engine
9058c2ecf20Sopenharmony_ci	 */
9068c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXCS, jme->reg_rxcs |
9078c2ecf20Sopenharmony_ci				RXCS_QUEUESEL_Q0 |
9088c2ecf20Sopenharmony_ci				RXCS_ENABLE |
9098c2ecf20Sopenharmony_ci				RXCS_QST);
9108c2ecf20Sopenharmony_ci}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_cistatic inline void
9138c2ecf20Sopenharmony_cijme_disable_rx_engine(struct jme_adapter *jme)
9148c2ecf20Sopenharmony_ci{
9158c2ecf20Sopenharmony_ci	int i;
9168c2ecf20Sopenharmony_ci	u32 val;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	/*
9198c2ecf20Sopenharmony_ci	 * Disable RX Engine
9208c2ecf20Sopenharmony_ci	 */
9218c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXCS, jme->reg_rxcs);
9228c2ecf20Sopenharmony_ci	wmb();
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	val = jread32(jme, JME_RXCS);
9258c2ecf20Sopenharmony_ci	for (i = JME_RX_DISABLE_TIMEOUT ; (val & RXCS_ENABLE) && i > 0 ; --i) {
9268c2ecf20Sopenharmony_ci		mdelay(1);
9278c2ecf20Sopenharmony_ci		val = jread32(jme, JME_RXCS);
9288c2ecf20Sopenharmony_ci		rmb();
9298c2ecf20Sopenharmony_ci	}
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	if (!i)
9328c2ecf20Sopenharmony_ci		pr_err("Disable RX engine timeout\n");
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	/*
9358c2ecf20Sopenharmony_ci	 * Stop clock for RX MAC Processor
9368c2ecf20Sopenharmony_ci	 */
9378c2ecf20Sopenharmony_ci	jme_mac_rxclk_off(jme);
9388c2ecf20Sopenharmony_ci}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_cistatic u16
9418c2ecf20Sopenharmony_cijme_udpsum(struct sk_buff *skb)
9428c2ecf20Sopenharmony_ci{
9438c2ecf20Sopenharmony_ci	u16 csum = 0xFFFFu;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	if (skb->len < (ETH_HLEN + sizeof(struct iphdr)))
9468c2ecf20Sopenharmony_ci		return csum;
9478c2ecf20Sopenharmony_ci	if (skb->protocol != htons(ETH_P_IP))
9488c2ecf20Sopenharmony_ci		return csum;
9498c2ecf20Sopenharmony_ci	skb_set_network_header(skb, ETH_HLEN);
9508c2ecf20Sopenharmony_ci	if ((ip_hdr(skb)->protocol != IPPROTO_UDP) ||
9518c2ecf20Sopenharmony_ci	    (skb->len < (ETH_HLEN +
9528c2ecf20Sopenharmony_ci			(ip_hdr(skb)->ihl << 2) +
9538c2ecf20Sopenharmony_ci			sizeof(struct udphdr)))) {
9548c2ecf20Sopenharmony_ci		skb_reset_network_header(skb);
9558c2ecf20Sopenharmony_ci		return csum;
9568c2ecf20Sopenharmony_ci	}
9578c2ecf20Sopenharmony_ci	skb_set_transport_header(skb,
9588c2ecf20Sopenharmony_ci			ETH_HLEN + (ip_hdr(skb)->ihl << 2));
9598c2ecf20Sopenharmony_ci	csum = udp_hdr(skb)->check;
9608c2ecf20Sopenharmony_ci	skb_reset_transport_header(skb);
9618c2ecf20Sopenharmony_ci	skb_reset_network_header(skb);
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	return csum;
9648c2ecf20Sopenharmony_ci}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_cistatic int
9678c2ecf20Sopenharmony_cijme_rxsum_ok(struct jme_adapter *jme, u16 flags, struct sk_buff *skb)
9688c2ecf20Sopenharmony_ci{
9698c2ecf20Sopenharmony_ci	if (!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4)))
9708c2ecf20Sopenharmony_ci		return false;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_TCPON | RXWBFLAG_TCPCS))
9738c2ecf20Sopenharmony_ci			== RXWBFLAG_TCPON)) {
9748c2ecf20Sopenharmony_ci		if (flags & RXWBFLAG_IPV4)
9758c2ecf20Sopenharmony_ci			netif_err(jme, rx_err, jme->dev, "TCP Checksum error\n");
9768c2ecf20Sopenharmony_ci		return false;
9778c2ecf20Sopenharmony_ci	}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS))
9808c2ecf20Sopenharmony_ci			== RXWBFLAG_UDPON) && jme_udpsum(skb)) {
9818c2ecf20Sopenharmony_ci		if (flags & RXWBFLAG_IPV4)
9828c2ecf20Sopenharmony_ci			netif_err(jme, rx_err, jme->dev, "UDP Checksum error\n");
9838c2ecf20Sopenharmony_ci		return false;
9848c2ecf20Sopenharmony_ci	}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	if (unlikely((flags & (RXWBFLAG_IPV4 | RXWBFLAG_IPCS))
9878c2ecf20Sopenharmony_ci			== RXWBFLAG_IPV4)) {
9888c2ecf20Sopenharmony_ci		netif_err(jme, rx_err, jme->dev, "IPv4 Checksum error\n");
9898c2ecf20Sopenharmony_ci		return false;
9908c2ecf20Sopenharmony_ci	}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	return true;
9938c2ecf20Sopenharmony_ci}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_cistatic void
9968c2ecf20Sopenharmony_cijme_alloc_and_feed_skb(struct jme_adapter *jme, int idx)
9978c2ecf20Sopenharmony_ci{
9988c2ecf20Sopenharmony_ci	struct jme_ring *rxring = &(jme->rxring[0]);
9998c2ecf20Sopenharmony_ci	struct rxdesc *rxdesc = rxring->desc;
10008c2ecf20Sopenharmony_ci	struct jme_buffer_info *rxbi = rxring->bufinf;
10018c2ecf20Sopenharmony_ci	struct sk_buff *skb;
10028c2ecf20Sopenharmony_ci	int framesize;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	rxdesc += idx;
10058c2ecf20Sopenharmony_ci	rxbi += idx;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	skb = rxbi->skb;
10088c2ecf20Sopenharmony_ci	pci_dma_sync_single_for_cpu(jme->pdev,
10098c2ecf20Sopenharmony_ci					rxbi->mapping,
10108c2ecf20Sopenharmony_ci					rxbi->len,
10118c2ecf20Sopenharmony_ci					PCI_DMA_FROMDEVICE);
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	if (unlikely(jme_make_new_rx_buf(jme, idx))) {
10148c2ecf20Sopenharmony_ci		pci_dma_sync_single_for_device(jme->pdev,
10158c2ecf20Sopenharmony_ci						rxbi->mapping,
10168c2ecf20Sopenharmony_ci						rxbi->len,
10178c2ecf20Sopenharmony_ci						PCI_DMA_FROMDEVICE);
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci		++(NET_STAT(jme).rx_dropped);
10208c2ecf20Sopenharmony_ci	} else {
10218c2ecf20Sopenharmony_ci		framesize = le16_to_cpu(rxdesc->descwb.framesize)
10228c2ecf20Sopenharmony_ci				- RX_PREPAD_SIZE;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci		skb_reserve(skb, RX_PREPAD_SIZE);
10258c2ecf20Sopenharmony_ci		skb_put(skb, framesize);
10268c2ecf20Sopenharmony_ci		skb->protocol = eth_type_trans(skb, jme->dev);
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci		if (jme_rxsum_ok(jme, le16_to_cpu(rxdesc->descwb.flags), skb))
10298c2ecf20Sopenharmony_ci			skb->ip_summed = CHECKSUM_UNNECESSARY;
10308c2ecf20Sopenharmony_ci		else
10318c2ecf20Sopenharmony_ci			skb_checksum_none_assert(skb);
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci		if (rxdesc->descwb.flags & cpu_to_le16(RXWBFLAG_TAGON)) {
10348c2ecf20Sopenharmony_ci			u16 vid = le16_to_cpu(rxdesc->descwb.vlan);
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
10378c2ecf20Sopenharmony_ci			NET_STAT(jme).rx_bytes += 4;
10388c2ecf20Sopenharmony_ci		}
10398c2ecf20Sopenharmony_ci		jme->jme_rx(skb);
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci		if ((rxdesc->descwb.flags & cpu_to_le16(RXWBFLAG_DEST)) ==
10428c2ecf20Sopenharmony_ci		    cpu_to_le16(RXWBFLAG_DEST_MUL))
10438c2ecf20Sopenharmony_ci			++(NET_STAT(jme).multicast);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci		NET_STAT(jme).rx_bytes += framesize;
10468c2ecf20Sopenharmony_ci		++(NET_STAT(jme).rx_packets);
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	jme_set_clean_rxdesc(jme, idx);
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_cistatic int
10548c2ecf20Sopenharmony_cijme_process_receive(struct jme_adapter *jme, int limit)
10558c2ecf20Sopenharmony_ci{
10568c2ecf20Sopenharmony_ci	struct jme_ring *rxring = &(jme->rxring[0]);
10578c2ecf20Sopenharmony_ci	struct rxdesc *rxdesc;
10588c2ecf20Sopenharmony_ci	int i, j, ccnt, desccnt, mask = jme->rx_ring_mask;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	if (unlikely(!atomic_dec_and_test(&jme->rx_cleaning)))
10618c2ecf20Sopenharmony_ci		goto out_inc;
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	if (unlikely(atomic_read(&jme->link_changing) != 1))
10648c2ecf20Sopenharmony_ci		goto out_inc;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	if (unlikely(!netif_carrier_ok(jme->dev)))
10678c2ecf20Sopenharmony_ci		goto out_inc;
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	i = atomic_read(&rxring->next_to_clean);
10708c2ecf20Sopenharmony_ci	while (limit > 0) {
10718c2ecf20Sopenharmony_ci		rxdesc = rxring->desc;
10728c2ecf20Sopenharmony_ci		rxdesc += i;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci		if ((rxdesc->descwb.flags & cpu_to_le16(RXWBFLAG_OWN)) ||
10758c2ecf20Sopenharmony_ci		!(rxdesc->descwb.desccnt & RXWBDCNT_WBCPL))
10768c2ecf20Sopenharmony_ci			goto out;
10778c2ecf20Sopenharmony_ci		--limit;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci		rmb();
10808c2ecf20Sopenharmony_ci		desccnt = rxdesc->descwb.desccnt & RXWBDCNT_DCNT;
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci		if (unlikely(desccnt > 1 ||
10838c2ecf20Sopenharmony_ci		rxdesc->descwb.errstat & RXWBERR_ALLERR)) {
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci			if (rxdesc->descwb.errstat & RXWBERR_CRCERR)
10868c2ecf20Sopenharmony_ci				++(NET_STAT(jme).rx_crc_errors);
10878c2ecf20Sopenharmony_ci			else if (rxdesc->descwb.errstat & RXWBERR_OVERUN)
10888c2ecf20Sopenharmony_ci				++(NET_STAT(jme).rx_fifo_errors);
10898c2ecf20Sopenharmony_ci			else
10908c2ecf20Sopenharmony_ci				++(NET_STAT(jme).rx_errors);
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci			if (desccnt > 1)
10938c2ecf20Sopenharmony_ci				limit -= desccnt - 1;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci			for (j = i, ccnt = desccnt ; ccnt-- ; ) {
10968c2ecf20Sopenharmony_ci				jme_set_clean_rxdesc(jme, j);
10978c2ecf20Sopenharmony_ci				j = (j + 1) & (mask);
10988c2ecf20Sopenharmony_ci			}
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci		} else {
11018c2ecf20Sopenharmony_ci			jme_alloc_and_feed_skb(jme, i);
11028c2ecf20Sopenharmony_ci		}
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci		i = (i + desccnt) & (mask);
11058c2ecf20Sopenharmony_ci	}
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ciout:
11088c2ecf20Sopenharmony_ci	atomic_set(&rxring->next_to_clean, i);
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ciout_inc:
11118c2ecf20Sopenharmony_ci	atomic_inc(&jme->rx_cleaning);
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	return limit > 0 ? limit : 0;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_cistatic void
11188c2ecf20Sopenharmony_cijme_attempt_pcc(struct dynpcc_info *dpi, int atmp)
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	if (likely(atmp == dpi->cur)) {
11218c2ecf20Sopenharmony_ci		dpi->cnt = 0;
11228c2ecf20Sopenharmony_ci		return;
11238c2ecf20Sopenharmony_ci	}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	if (dpi->attempt == atmp) {
11268c2ecf20Sopenharmony_ci		++(dpi->cnt);
11278c2ecf20Sopenharmony_ci	} else {
11288c2ecf20Sopenharmony_ci		dpi->attempt = atmp;
11298c2ecf20Sopenharmony_ci		dpi->cnt = 0;
11308c2ecf20Sopenharmony_ci	}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_cistatic void
11358c2ecf20Sopenharmony_cijme_dynamic_pcc(struct jme_adapter *jme)
11368c2ecf20Sopenharmony_ci{
11378c2ecf20Sopenharmony_ci	register struct dynpcc_info *dpi = &(jme->dpi);
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	if ((NET_STAT(jme).rx_bytes - dpi->last_bytes) > PCC_P3_THRESHOLD)
11408c2ecf20Sopenharmony_ci		jme_attempt_pcc(dpi, PCC_P3);
11418c2ecf20Sopenharmony_ci	else if ((NET_STAT(jme).rx_packets - dpi->last_pkts) > PCC_P2_THRESHOLD ||
11428c2ecf20Sopenharmony_ci		 dpi->intr_cnt > PCC_INTR_THRESHOLD)
11438c2ecf20Sopenharmony_ci		jme_attempt_pcc(dpi, PCC_P2);
11448c2ecf20Sopenharmony_ci	else
11458c2ecf20Sopenharmony_ci		jme_attempt_pcc(dpi, PCC_P1);
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	if (unlikely(dpi->attempt != dpi->cur && dpi->cnt > 5)) {
11488c2ecf20Sopenharmony_ci		if (dpi->attempt < dpi->cur)
11498c2ecf20Sopenharmony_ci			tasklet_schedule(&jme->rxclean_task);
11508c2ecf20Sopenharmony_ci		jme_set_rx_pcc(jme, dpi->attempt);
11518c2ecf20Sopenharmony_ci		dpi->cur = dpi->attempt;
11528c2ecf20Sopenharmony_ci		dpi->cnt = 0;
11538c2ecf20Sopenharmony_ci	}
11548c2ecf20Sopenharmony_ci}
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_cistatic void
11578c2ecf20Sopenharmony_cijme_start_pcc_timer(struct jme_adapter *jme)
11588c2ecf20Sopenharmony_ci{
11598c2ecf20Sopenharmony_ci	struct dynpcc_info *dpi = &(jme->dpi);
11608c2ecf20Sopenharmony_ci	dpi->last_bytes		= NET_STAT(jme).rx_bytes;
11618c2ecf20Sopenharmony_ci	dpi->last_pkts		= NET_STAT(jme).rx_packets;
11628c2ecf20Sopenharmony_ci	dpi->intr_cnt		= 0;
11638c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TMCSR,
11648c2ecf20Sopenharmony_ci		TMCSR_EN | ((0xFFFFFF - PCC_INTERVAL_US) & TMCSR_CNT));
11658c2ecf20Sopenharmony_ci}
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_cistatic inline void
11688c2ecf20Sopenharmony_cijme_stop_pcc_timer(struct jme_adapter *jme)
11698c2ecf20Sopenharmony_ci{
11708c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TMCSR, 0);
11718c2ecf20Sopenharmony_ci}
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_cistatic void
11748c2ecf20Sopenharmony_cijme_shutdown_nic(struct jme_adapter *jme)
11758c2ecf20Sopenharmony_ci{
11768c2ecf20Sopenharmony_ci	u32 phylink;
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	phylink = jme_linkstat_from_phy(jme);
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	if (!(phylink & PHY_LINK_UP)) {
11818c2ecf20Sopenharmony_ci		/*
11828c2ecf20Sopenharmony_ci		 * Disable all interrupt before issue timer
11838c2ecf20Sopenharmony_ci		 */
11848c2ecf20Sopenharmony_ci		jme_stop_irq(jme);
11858c2ecf20Sopenharmony_ci		jwrite32(jme, JME_TIMER2, TMCSR_EN | 0xFFFFFE);
11868c2ecf20Sopenharmony_ci	}
11878c2ecf20Sopenharmony_ci}
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_cistatic void
11908c2ecf20Sopenharmony_cijme_pcc_tasklet(struct tasklet_struct *t)
11918c2ecf20Sopenharmony_ci{
11928c2ecf20Sopenharmony_ci	struct jme_adapter *jme = from_tasklet(jme, t, pcc_task);
11938c2ecf20Sopenharmony_ci	struct net_device *netdev = jme->dev;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	if (unlikely(test_bit(JME_FLAG_SHUTDOWN, &jme->flags))) {
11968c2ecf20Sopenharmony_ci		jme_shutdown_nic(jme);
11978c2ecf20Sopenharmony_ci		return;
11988c2ecf20Sopenharmony_ci	}
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	if (unlikely(!netif_carrier_ok(netdev) ||
12018c2ecf20Sopenharmony_ci		(atomic_read(&jme->link_changing) != 1)
12028c2ecf20Sopenharmony_ci	)) {
12038c2ecf20Sopenharmony_ci		jme_stop_pcc_timer(jme);
12048c2ecf20Sopenharmony_ci		return;
12058c2ecf20Sopenharmony_ci	}
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	if (!(test_bit(JME_FLAG_POLL, &jme->flags)))
12088c2ecf20Sopenharmony_ci		jme_dynamic_pcc(jme);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	jme_start_pcc_timer(jme);
12118c2ecf20Sopenharmony_ci}
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_cistatic inline void
12148c2ecf20Sopenharmony_cijme_polling_mode(struct jme_adapter *jme)
12158c2ecf20Sopenharmony_ci{
12168c2ecf20Sopenharmony_ci	jme_set_rx_pcc(jme, PCC_OFF);
12178c2ecf20Sopenharmony_ci}
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_cistatic inline void
12208c2ecf20Sopenharmony_cijme_interrupt_mode(struct jme_adapter *jme)
12218c2ecf20Sopenharmony_ci{
12228c2ecf20Sopenharmony_ci	jme_set_rx_pcc(jme, PCC_P1);
12238c2ecf20Sopenharmony_ci}
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_cistatic inline int
12268c2ecf20Sopenharmony_cijme_pseudo_hotplug_enabled(struct jme_adapter *jme)
12278c2ecf20Sopenharmony_ci{
12288c2ecf20Sopenharmony_ci	u32 apmc;
12298c2ecf20Sopenharmony_ci	apmc = jread32(jme, JME_APMC);
12308c2ecf20Sopenharmony_ci	return apmc & JME_APMC_PSEUDO_HP_EN;
12318c2ecf20Sopenharmony_ci}
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_cistatic void
12348c2ecf20Sopenharmony_cijme_start_shutdown_timer(struct jme_adapter *jme)
12358c2ecf20Sopenharmony_ci{
12368c2ecf20Sopenharmony_ci	u32 apmc;
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	apmc = jread32(jme, JME_APMC) | JME_APMC_PCIE_SD_EN;
12398c2ecf20Sopenharmony_ci	apmc &= ~JME_APMC_EPIEN_CTRL;
12408c2ecf20Sopenharmony_ci	if (!no_extplug) {
12418c2ecf20Sopenharmony_ci		jwrite32f(jme, JME_APMC, apmc | JME_APMC_EPIEN_CTRL_EN);
12428c2ecf20Sopenharmony_ci		wmb();
12438c2ecf20Sopenharmony_ci	}
12448c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_APMC, apmc);
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_TIMER2, 0);
12478c2ecf20Sopenharmony_ci	set_bit(JME_FLAG_SHUTDOWN, &jme->flags);
12488c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TMCSR,
12498c2ecf20Sopenharmony_ci		TMCSR_EN | ((0xFFFFFF - APMC_PHP_SHUTDOWN_DELAY) & TMCSR_CNT));
12508c2ecf20Sopenharmony_ci}
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_cistatic void
12538c2ecf20Sopenharmony_cijme_stop_shutdown_timer(struct jme_adapter *jme)
12548c2ecf20Sopenharmony_ci{
12558c2ecf20Sopenharmony_ci	u32 apmc;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_TMCSR, 0);
12588c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_TIMER2, 0);
12598c2ecf20Sopenharmony_ci	clear_bit(JME_FLAG_SHUTDOWN, &jme->flags);
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	apmc = jread32(jme, JME_APMC);
12628c2ecf20Sopenharmony_ci	apmc &= ~(JME_APMC_PCIE_SD_EN | JME_APMC_EPIEN_CTRL);
12638c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_APMC, apmc | JME_APMC_EPIEN_CTRL_DIS);
12648c2ecf20Sopenharmony_ci	wmb();
12658c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_APMC, apmc);
12668c2ecf20Sopenharmony_ci}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_cistatic void jme_link_change_tasklet(struct tasklet_struct *t)
12698c2ecf20Sopenharmony_ci{
12708c2ecf20Sopenharmony_ci	struct jme_adapter *jme = from_tasklet(jme, t, linkch_task);
12718c2ecf20Sopenharmony_ci	struct net_device *netdev = jme->dev;
12728c2ecf20Sopenharmony_ci	int rc;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	while (!atomic_dec_and_test(&jme->link_changing)) {
12758c2ecf20Sopenharmony_ci		atomic_inc(&jme->link_changing);
12768c2ecf20Sopenharmony_ci		netif_info(jme, intr, jme->dev, "Get link change lock failed\n");
12778c2ecf20Sopenharmony_ci		while (atomic_read(&jme->link_changing) != 1)
12788c2ecf20Sopenharmony_ci			netif_info(jme, intr, jme->dev, "Waiting link change lock\n");
12798c2ecf20Sopenharmony_ci	}
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	if (jme_check_link(netdev, 1) && jme->old_mtu == netdev->mtu)
12828c2ecf20Sopenharmony_ci		goto out;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	jme->old_mtu = netdev->mtu;
12858c2ecf20Sopenharmony_ci	netif_stop_queue(netdev);
12868c2ecf20Sopenharmony_ci	if (jme_pseudo_hotplug_enabled(jme))
12878c2ecf20Sopenharmony_ci		jme_stop_shutdown_timer(jme);
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	jme_stop_pcc_timer(jme);
12908c2ecf20Sopenharmony_ci	tasklet_disable(&jme->txclean_task);
12918c2ecf20Sopenharmony_ci	tasklet_disable(&jme->rxclean_task);
12928c2ecf20Sopenharmony_ci	tasklet_disable(&jme->rxempty_task);
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	if (netif_carrier_ok(netdev)) {
12958c2ecf20Sopenharmony_ci		jme_disable_rx_engine(jme);
12968c2ecf20Sopenharmony_ci		jme_disable_tx_engine(jme);
12978c2ecf20Sopenharmony_ci		jme_reset_mac_processor(jme);
12988c2ecf20Sopenharmony_ci		jme_free_rx_resources(jme);
12998c2ecf20Sopenharmony_ci		jme_free_tx_resources(jme);
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci		if (test_bit(JME_FLAG_POLL, &jme->flags))
13028c2ecf20Sopenharmony_ci			jme_polling_mode(jme);
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci		netif_carrier_off(netdev);
13058c2ecf20Sopenharmony_ci	}
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	jme_check_link(netdev, 0);
13088c2ecf20Sopenharmony_ci	if (netif_carrier_ok(netdev)) {
13098c2ecf20Sopenharmony_ci		rc = jme_setup_rx_resources(jme);
13108c2ecf20Sopenharmony_ci		if (rc) {
13118c2ecf20Sopenharmony_ci			pr_err("Allocating resources for RX error, Device STOPPED!\n");
13128c2ecf20Sopenharmony_ci			goto out_enable_tasklet;
13138c2ecf20Sopenharmony_ci		}
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci		rc = jme_setup_tx_resources(jme);
13168c2ecf20Sopenharmony_ci		if (rc) {
13178c2ecf20Sopenharmony_ci			pr_err("Allocating resources for TX error, Device STOPPED!\n");
13188c2ecf20Sopenharmony_ci			goto err_out_free_rx_resources;
13198c2ecf20Sopenharmony_ci		}
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci		jme_enable_rx_engine(jme);
13228c2ecf20Sopenharmony_ci		jme_enable_tx_engine(jme);
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci		netif_start_queue(netdev);
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci		if (test_bit(JME_FLAG_POLL, &jme->flags))
13278c2ecf20Sopenharmony_ci			jme_interrupt_mode(jme);
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci		jme_start_pcc_timer(jme);
13308c2ecf20Sopenharmony_ci	} else if (jme_pseudo_hotplug_enabled(jme)) {
13318c2ecf20Sopenharmony_ci		jme_start_shutdown_timer(jme);
13328c2ecf20Sopenharmony_ci	}
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	goto out_enable_tasklet;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_cierr_out_free_rx_resources:
13378c2ecf20Sopenharmony_ci	jme_free_rx_resources(jme);
13388c2ecf20Sopenharmony_ciout_enable_tasklet:
13398c2ecf20Sopenharmony_ci	tasklet_enable(&jme->txclean_task);
13408c2ecf20Sopenharmony_ci	tasklet_enable(&jme->rxclean_task);
13418c2ecf20Sopenharmony_ci	tasklet_enable(&jme->rxempty_task);
13428c2ecf20Sopenharmony_ciout:
13438c2ecf20Sopenharmony_ci	atomic_inc(&jme->link_changing);
13448c2ecf20Sopenharmony_ci}
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_cistatic void
13478c2ecf20Sopenharmony_cijme_rx_clean_tasklet(struct tasklet_struct *t)
13488c2ecf20Sopenharmony_ci{
13498c2ecf20Sopenharmony_ci	struct jme_adapter *jme = from_tasklet(jme, t, rxclean_task);
13508c2ecf20Sopenharmony_ci	struct dynpcc_info *dpi = &(jme->dpi);
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	jme_process_receive(jme, jme->rx_ring_size);
13538c2ecf20Sopenharmony_ci	++(dpi->intr_cnt);
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_cistatic int
13588c2ecf20Sopenharmony_cijme_poll(JME_NAPI_HOLDER(holder), JME_NAPI_WEIGHT(budget))
13598c2ecf20Sopenharmony_ci{
13608c2ecf20Sopenharmony_ci	struct jme_adapter *jme = jme_napi_priv(holder);
13618c2ecf20Sopenharmony_ci	int rest;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	rest = jme_process_receive(jme, JME_NAPI_WEIGHT_VAL(budget));
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	while (atomic_read(&jme->rx_empty) > 0) {
13668c2ecf20Sopenharmony_ci		atomic_dec(&jme->rx_empty);
13678c2ecf20Sopenharmony_ci		++(NET_STAT(jme).rx_dropped);
13688c2ecf20Sopenharmony_ci		jme_restart_rx_engine(jme);
13698c2ecf20Sopenharmony_ci	}
13708c2ecf20Sopenharmony_ci	atomic_inc(&jme->rx_empty);
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	if (rest) {
13738c2ecf20Sopenharmony_ci		JME_RX_COMPLETE(netdev, holder);
13748c2ecf20Sopenharmony_ci		jme_interrupt_mode(jme);
13758c2ecf20Sopenharmony_ci	}
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	JME_NAPI_WEIGHT_SET(budget, rest);
13788c2ecf20Sopenharmony_ci	return JME_NAPI_WEIGHT_VAL(budget) - rest;
13798c2ecf20Sopenharmony_ci}
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_cistatic void
13828c2ecf20Sopenharmony_cijme_rx_empty_tasklet(struct tasklet_struct *t)
13838c2ecf20Sopenharmony_ci{
13848c2ecf20Sopenharmony_ci	struct jme_adapter *jme = from_tasklet(jme, t, rxempty_task);
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	if (unlikely(atomic_read(&jme->link_changing) != 1))
13878c2ecf20Sopenharmony_ci		return;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	if (unlikely(!netif_carrier_ok(jme->dev)))
13908c2ecf20Sopenharmony_ci		return;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	netif_info(jme, rx_status, jme->dev, "RX Queue Full!\n");
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	jme_rx_clean_tasklet(&jme->rxclean_task);
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	while (atomic_read(&jme->rx_empty) > 0) {
13978c2ecf20Sopenharmony_ci		atomic_dec(&jme->rx_empty);
13988c2ecf20Sopenharmony_ci		++(NET_STAT(jme).rx_dropped);
13998c2ecf20Sopenharmony_ci		jme_restart_rx_engine(jme);
14008c2ecf20Sopenharmony_ci	}
14018c2ecf20Sopenharmony_ci	atomic_inc(&jme->rx_empty);
14028c2ecf20Sopenharmony_ci}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_cistatic void
14058c2ecf20Sopenharmony_cijme_wake_queue_if_stopped(struct jme_adapter *jme)
14068c2ecf20Sopenharmony_ci{
14078c2ecf20Sopenharmony_ci	struct jme_ring *txring = &(jme->txring[0]);
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	smp_wmb();
14108c2ecf20Sopenharmony_ci	if (unlikely(netif_queue_stopped(jme->dev) &&
14118c2ecf20Sopenharmony_ci	atomic_read(&txring->nr_free) >= (jme->tx_wake_threshold))) {
14128c2ecf20Sopenharmony_ci		netif_info(jme, tx_done, jme->dev, "TX Queue Waked\n");
14138c2ecf20Sopenharmony_ci		netif_wake_queue(jme->dev);
14148c2ecf20Sopenharmony_ci	}
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_cistatic void jme_tx_clean_tasklet(struct tasklet_struct *t)
14198c2ecf20Sopenharmony_ci{
14208c2ecf20Sopenharmony_ci	struct jme_adapter *jme = from_tasklet(jme, t, txclean_task);
14218c2ecf20Sopenharmony_ci	struct jme_ring *txring = &(jme->txring[0]);
14228c2ecf20Sopenharmony_ci	struct txdesc *txdesc = txring->desc;
14238c2ecf20Sopenharmony_ci	struct jme_buffer_info *txbi = txring->bufinf, *ctxbi, *ttxbi;
14248c2ecf20Sopenharmony_ci	int i, j, cnt = 0, max, err, mask;
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	tx_dbg(jme, "Into txclean\n");
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	if (unlikely(!atomic_dec_and_test(&jme->tx_cleaning)))
14298c2ecf20Sopenharmony_ci		goto out;
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	if (unlikely(atomic_read(&jme->link_changing) != 1))
14328c2ecf20Sopenharmony_ci		goto out;
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	if (unlikely(!netif_carrier_ok(jme->dev)))
14358c2ecf20Sopenharmony_ci		goto out;
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	max = jme->tx_ring_size - atomic_read(&txring->nr_free);
14388c2ecf20Sopenharmony_ci	mask = jme->tx_ring_mask;
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	for (i = atomic_read(&txring->next_to_clean) ; cnt < max ; ) {
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci		ctxbi = txbi + i;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci		if (likely(ctxbi->skb &&
14458c2ecf20Sopenharmony_ci		!(txdesc[i].descwb.flags & TXWBFLAG_OWN))) {
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci			tx_dbg(jme, "txclean: %d+%d@%lu\n",
14488c2ecf20Sopenharmony_ci			       i, ctxbi->nr_desc, jiffies);
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci			err = txdesc[i].descwb.flags & TXWBFLAG_ALLERR;
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci			for (j = 1 ; j < ctxbi->nr_desc ; ++j) {
14538c2ecf20Sopenharmony_ci				ttxbi = txbi + ((i + j) & (mask));
14548c2ecf20Sopenharmony_ci				txdesc[(i + j) & (mask)].dw[0] = 0;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci				pci_unmap_page(jme->pdev,
14578c2ecf20Sopenharmony_ci						 ttxbi->mapping,
14588c2ecf20Sopenharmony_ci						 ttxbi->len,
14598c2ecf20Sopenharmony_ci						 PCI_DMA_TODEVICE);
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci				ttxbi->mapping = 0;
14628c2ecf20Sopenharmony_ci				ttxbi->len = 0;
14638c2ecf20Sopenharmony_ci			}
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci			dev_kfree_skb(ctxbi->skb);
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci			cnt += ctxbi->nr_desc;
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci			if (unlikely(err)) {
14708c2ecf20Sopenharmony_ci				++(NET_STAT(jme).tx_carrier_errors);
14718c2ecf20Sopenharmony_ci			} else {
14728c2ecf20Sopenharmony_ci				++(NET_STAT(jme).tx_packets);
14738c2ecf20Sopenharmony_ci				NET_STAT(jme).tx_bytes += ctxbi->len;
14748c2ecf20Sopenharmony_ci			}
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci			ctxbi->skb = NULL;
14778c2ecf20Sopenharmony_ci			ctxbi->len = 0;
14788c2ecf20Sopenharmony_ci			ctxbi->start_xmit = 0;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci		} else {
14818c2ecf20Sopenharmony_ci			break;
14828c2ecf20Sopenharmony_ci		}
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci		i = (i + ctxbi->nr_desc) & mask;
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci		ctxbi->nr_desc = 0;
14878c2ecf20Sopenharmony_ci	}
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	tx_dbg(jme, "txclean: done %d@%lu\n", i, jiffies);
14908c2ecf20Sopenharmony_ci	atomic_set(&txring->next_to_clean, i);
14918c2ecf20Sopenharmony_ci	atomic_add(cnt, &txring->nr_free);
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci	jme_wake_queue_if_stopped(jme);
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ciout:
14968c2ecf20Sopenharmony_ci	atomic_inc(&jme->tx_cleaning);
14978c2ecf20Sopenharmony_ci}
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_cistatic void
15008c2ecf20Sopenharmony_cijme_intr_msi(struct jme_adapter *jme, u32 intrstat)
15018c2ecf20Sopenharmony_ci{
15028c2ecf20Sopenharmony_ci	/*
15038c2ecf20Sopenharmony_ci	 * Disable interrupt
15048c2ecf20Sopenharmony_ci	 */
15058c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_IENC, INTR_ENABLE);
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci	if (intrstat & (INTR_LINKCH | INTR_SWINTR)) {
15088c2ecf20Sopenharmony_ci		/*
15098c2ecf20Sopenharmony_ci		 * Link change event is critical
15108c2ecf20Sopenharmony_ci		 * all other events are ignored
15118c2ecf20Sopenharmony_ci		 */
15128c2ecf20Sopenharmony_ci		jwrite32(jme, JME_IEVE, intrstat);
15138c2ecf20Sopenharmony_ci		tasklet_schedule(&jme->linkch_task);
15148c2ecf20Sopenharmony_ci		goto out_reenable;
15158c2ecf20Sopenharmony_ci	}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	if (intrstat & INTR_TMINTR) {
15188c2ecf20Sopenharmony_ci		jwrite32(jme, JME_IEVE, INTR_TMINTR);
15198c2ecf20Sopenharmony_ci		tasklet_schedule(&jme->pcc_task);
15208c2ecf20Sopenharmony_ci	}
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	if (intrstat & (INTR_PCCTXTO | INTR_PCCTX)) {
15238c2ecf20Sopenharmony_ci		jwrite32(jme, JME_IEVE, INTR_PCCTXTO | INTR_PCCTX | INTR_TX0);
15248c2ecf20Sopenharmony_ci		tasklet_schedule(&jme->txclean_task);
15258c2ecf20Sopenharmony_ci	}
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	if ((intrstat & (INTR_PCCRX0TO | INTR_PCCRX0 | INTR_RX0EMP))) {
15288c2ecf20Sopenharmony_ci		jwrite32(jme, JME_IEVE, (intrstat & (INTR_PCCRX0TO |
15298c2ecf20Sopenharmony_ci						     INTR_PCCRX0 |
15308c2ecf20Sopenharmony_ci						     INTR_RX0EMP)) |
15318c2ecf20Sopenharmony_ci					INTR_RX0);
15328c2ecf20Sopenharmony_ci	}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	if (test_bit(JME_FLAG_POLL, &jme->flags)) {
15358c2ecf20Sopenharmony_ci		if (intrstat & INTR_RX0EMP)
15368c2ecf20Sopenharmony_ci			atomic_inc(&jme->rx_empty);
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci		if ((intrstat & (INTR_PCCRX0TO | INTR_PCCRX0 | INTR_RX0EMP))) {
15398c2ecf20Sopenharmony_ci			if (likely(JME_RX_SCHEDULE_PREP(jme))) {
15408c2ecf20Sopenharmony_ci				jme_polling_mode(jme);
15418c2ecf20Sopenharmony_ci				JME_RX_SCHEDULE(jme);
15428c2ecf20Sopenharmony_ci			}
15438c2ecf20Sopenharmony_ci		}
15448c2ecf20Sopenharmony_ci	} else {
15458c2ecf20Sopenharmony_ci		if (intrstat & INTR_RX0EMP) {
15468c2ecf20Sopenharmony_ci			atomic_inc(&jme->rx_empty);
15478c2ecf20Sopenharmony_ci			tasklet_hi_schedule(&jme->rxempty_task);
15488c2ecf20Sopenharmony_ci		} else if (intrstat & (INTR_PCCRX0TO | INTR_PCCRX0)) {
15498c2ecf20Sopenharmony_ci			tasklet_hi_schedule(&jme->rxclean_task);
15508c2ecf20Sopenharmony_ci		}
15518c2ecf20Sopenharmony_ci	}
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ciout_reenable:
15548c2ecf20Sopenharmony_ci	/*
15558c2ecf20Sopenharmony_ci	 * Re-enable interrupt
15568c2ecf20Sopenharmony_ci	 */
15578c2ecf20Sopenharmony_ci	jwrite32f(jme, JME_IENS, INTR_ENABLE);
15588c2ecf20Sopenharmony_ci}
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_cistatic irqreturn_t
15618c2ecf20Sopenharmony_cijme_intr(int irq, void *dev_id)
15628c2ecf20Sopenharmony_ci{
15638c2ecf20Sopenharmony_ci	struct net_device *netdev = dev_id;
15648c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
15658c2ecf20Sopenharmony_ci	u32 intrstat;
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	intrstat = jread32(jme, JME_IEVE);
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	/*
15708c2ecf20Sopenharmony_ci	 * Check if it's really an interrupt for us
15718c2ecf20Sopenharmony_ci	 */
15728c2ecf20Sopenharmony_ci	if (unlikely((intrstat & INTR_ENABLE) == 0))
15738c2ecf20Sopenharmony_ci		return IRQ_NONE;
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	/*
15768c2ecf20Sopenharmony_ci	 * Check if the device still exist
15778c2ecf20Sopenharmony_ci	 */
15788c2ecf20Sopenharmony_ci	if (unlikely(intrstat == ~((typeof(intrstat))0)))
15798c2ecf20Sopenharmony_ci		return IRQ_NONE;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	jme_intr_msi(jme, intrstat);
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
15848c2ecf20Sopenharmony_ci}
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_cistatic irqreturn_t
15878c2ecf20Sopenharmony_cijme_msi(int irq, void *dev_id)
15888c2ecf20Sopenharmony_ci{
15898c2ecf20Sopenharmony_ci	struct net_device *netdev = dev_id;
15908c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
15918c2ecf20Sopenharmony_ci	u32 intrstat;
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	intrstat = jread32(jme, JME_IEVE);
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	jme_intr_msi(jme, intrstat);
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
15988c2ecf20Sopenharmony_ci}
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_cistatic void
16018c2ecf20Sopenharmony_cijme_reset_link(struct jme_adapter *jme)
16028c2ecf20Sopenharmony_ci{
16038c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TMCSR, TMCSR_SWIT);
16048c2ecf20Sopenharmony_ci}
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_cistatic void
16078c2ecf20Sopenharmony_cijme_restart_an(struct jme_adapter *jme)
16088c2ecf20Sopenharmony_ci{
16098c2ecf20Sopenharmony_ci	u32 bmcr;
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	spin_lock_bh(&jme->phy_lock);
16128c2ecf20Sopenharmony_ci	bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR);
16138c2ecf20Sopenharmony_ci	bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
16148c2ecf20Sopenharmony_ci	jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr);
16158c2ecf20Sopenharmony_ci	spin_unlock_bh(&jme->phy_lock);
16168c2ecf20Sopenharmony_ci}
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_cistatic int
16198c2ecf20Sopenharmony_cijme_request_irq(struct jme_adapter *jme)
16208c2ecf20Sopenharmony_ci{
16218c2ecf20Sopenharmony_ci	int rc;
16228c2ecf20Sopenharmony_ci	struct net_device *netdev = jme->dev;
16238c2ecf20Sopenharmony_ci	irq_handler_t handler = jme_intr;
16248c2ecf20Sopenharmony_ci	int irq_flags = IRQF_SHARED;
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	if (!pci_enable_msi(jme->pdev)) {
16278c2ecf20Sopenharmony_ci		set_bit(JME_FLAG_MSI, &jme->flags);
16288c2ecf20Sopenharmony_ci		handler = jme_msi;
16298c2ecf20Sopenharmony_ci		irq_flags = 0;
16308c2ecf20Sopenharmony_ci	}
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	rc = request_irq(jme->pdev->irq, handler, irq_flags, netdev->name,
16338c2ecf20Sopenharmony_ci			  netdev);
16348c2ecf20Sopenharmony_ci	if (rc) {
16358c2ecf20Sopenharmony_ci		netdev_err(netdev,
16368c2ecf20Sopenharmony_ci			   "Unable to request %s interrupt (return: %d)\n",
16378c2ecf20Sopenharmony_ci			   test_bit(JME_FLAG_MSI, &jme->flags) ? "MSI" : "INTx",
16388c2ecf20Sopenharmony_ci			   rc);
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci		if (test_bit(JME_FLAG_MSI, &jme->flags)) {
16418c2ecf20Sopenharmony_ci			pci_disable_msi(jme->pdev);
16428c2ecf20Sopenharmony_ci			clear_bit(JME_FLAG_MSI, &jme->flags);
16438c2ecf20Sopenharmony_ci		}
16448c2ecf20Sopenharmony_ci	} else {
16458c2ecf20Sopenharmony_ci		netdev->irq = jme->pdev->irq;
16468c2ecf20Sopenharmony_ci	}
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	return rc;
16498c2ecf20Sopenharmony_ci}
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_cistatic void
16528c2ecf20Sopenharmony_cijme_free_irq(struct jme_adapter *jme)
16538c2ecf20Sopenharmony_ci{
16548c2ecf20Sopenharmony_ci	free_irq(jme->pdev->irq, jme->dev);
16558c2ecf20Sopenharmony_ci	if (test_bit(JME_FLAG_MSI, &jme->flags)) {
16568c2ecf20Sopenharmony_ci		pci_disable_msi(jme->pdev);
16578c2ecf20Sopenharmony_ci		clear_bit(JME_FLAG_MSI, &jme->flags);
16588c2ecf20Sopenharmony_ci		jme->dev->irq = jme->pdev->irq;
16598c2ecf20Sopenharmony_ci	}
16608c2ecf20Sopenharmony_ci}
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_cistatic inline void
16638c2ecf20Sopenharmony_cijme_new_phy_on(struct jme_adapter *jme)
16648c2ecf20Sopenharmony_ci{
16658c2ecf20Sopenharmony_ci	u32 reg;
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	reg = jread32(jme, JME_PHY_PWR);
16688c2ecf20Sopenharmony_ci	reg &= ~(PHY_PWR_DWN1SEL | PHY_PWR_DWN1SW |
16698c2ecf20Sopenharmony_ci		 PHY_PWR_DWN2 | PHY_PWR_CLKSEL);
16708c2ecf20Sopenharmony_ci	jwrite32(jme, JME_PHY_PWR, reg);
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	pci_read_config_dword(jme->pdev, PCI_PRIV_PE1, &reg);
16738c2ecf20Sopenharmony_ci	reg &= ~PE1_GPREG0_PBG;
16748c2ecf20Sopenharmony_ci	reg |= PE1_GPREG0_ENBG;
16758c2ecf20Sopenharmony_ci	pci_write_config_dword(jme->pdev, PCI_PRIV_PE1, reg);
16768c2ecf20Sopenharmony_ci}
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_cistatic inline void
16798c2ecf20Sopenharmony_cijme_new_phy_off(struct jme_adapter *jme)
16808c2ecf20Sopenharmony_ci{
16818c2ecf20Sopenharmony_ci	u32 reg;
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	reg = jread32(jme, JME_PHY_PWR);
16848c2ecf20Sopenharmony_ci	reg |= PHY_PWR_DWN1SEL | PHY_PWR_DWN1SW |
16858c2ecf20Sopenharmony_ci	       PHY_PWR_DWN2 | PHY_PWR_CLKSEL;
16868c2ecf20Sopenharmony_ci	jwrite32(jme, JME_PHY_PWR, reg);
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci	pci_read_config_dword(jme->pdev, PCI_PRIV_PE1, &reg);
16898c2ecf20Sopenharmony_ci	reg &= ~PE1_GPREG0_PBG;
16908c2ecf20Sopenharmony_ci	reg |= PE1_GPREG0_PDD3COLD;
16918c2ecf20Sopenharmony_ci	pci_write_config_dword(jme->pdev, PCI_PRIV_PE1, reg);
16928c2ecf20Sopenharmony_ci}
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_cistatic inline void
16958c2ecf20Sopenharmony_cijme_phy_on(struct jme_adapter *jme)
16968c2ecf20Sopenharmony_ci{
16978c2ecf20Sopenharmony_ci	u32 bmcr;
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci	bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR);
17008c2ecf20Sopenharmony_ci	bmcr &= ~BMCR_PDOWN;
17018c2ecf20Sopenharmony_ci	jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr);
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	if (new_phy_power_ctrl(jme->chip_main_rev))
17048c2ecf20Sopenharmony_ci		jme_new_phy_on(jme);
17058c2ecf20Sopenharmony_ci}
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_cistatic inline void
17088c2ecf20Sopenharmony_cijme_phy_off(struct jme_adapter *jme)
17098c2ecf20Sopenharmony_ci{
17108c2ecf20Sopenharmony_ci	u32 bmcr;
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR);
17138c2ecf20Sopenharmony_ci	bmcr |= BMCR_PDOWN;
17148c2ecf20Sopenharmony_ci	jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr);
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	if (new_phy_power_ctrl(jme->chip_main_rev))
17178c2ecf20Sopenharmony_ci		jme_new_phy_off(jme);
17188c2ecf20Sopenharmony_ci}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_cistatic int
17218c2ecf20Sopenharmony_cijme_phy_specreg_read(struct jme_adapter *jme, u32 specreg)
17228c2ecf20Sopenharmony_ci{
17238c2ecf20Sopenharmony_ci	u32 phy_addr;
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	phy_addr = JM_PHY_SPEC_REG_READ | specreg;
17268c2ecf20Sopenharmony_ci	jme_mdio_write(jme->dev, jme->mii_if.phy_id, JM_PHY_SPEC_ADDR_REG,
17278c2ecf20Sopenharmony_ci			phy_addr);
17288c2ecf20Sopenharmony_ci	return jme_mdio_read(jme->dev, jme->mii_if.phy_id,
17298c2ecf20Sopenharmony_ci			JM_PHY_SPEC_DATA_REG);
17308c2ecf20Sopenharmony_ci}
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_cistatic void
17338c2ecf20Sopenharmony_cijme_phy_specreg_write(struct jme_adapter *jme, u32 ext_reg, u32 phy_data)
17348c2ecf20Sopenharmony_ci{
17358c2ecf20Sopenharmony_ci	u32 phy_addr;
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	phy_addr = JM_PHY_SPEC_REG_WRITE | ext_reg;
17388c2ecf20Sopenharmony_ci	jme_mdio_write(jme->dev, jme->mii_if.phy_id, JM_PHY_SPEC_DATA_REG,
17398c2ecf20Sopenharmony_ci			phy_data);
17408c2ecf20Sopenharmony_ci	jme_mdio_write(jme->dev, jme->mii_if.phy_id, JM_PHY_SPEC_ADDR_REG,
17418c2ecf20Sopenharmony_ci			phy_addr);
17428c2ecf20Sopenharmony_ci}
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_cistatic int
17458c2ecf20Sopenharmony_cijme_phy_calibration(struct jme_adapter *jme)
17468c2ecf20Sopenharmony_ci{
17478c2ecf20Sopenharmony_ci	u32 ctrl1000, phy_data;
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	jme_phy_off(jme);
17508c2ecf20Sopenharmony_ci	jme_phy_on(jme);
17518c2ecf20Sopenharmony_ci	/*  Enabel PHY test mode 1 */
17528c2ecf20Sopenharmony_ci	ctrl1000 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_CTRL1000);
17538c2ecf20Sopenharmony_ci	ctrl1000 &= ~PHY_GAD_TEST_MODE_MSK;
17548c2ecf20Sopenharmony_ci	ctrl1000 |= PHY_GAD_TEST_MODE_1;
17558c2ecf20Sopenharmony_ci	jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_CTRL1000, ctrl1000);
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	phy_data = jme_phy_specreg_read(jme, JM_PHY_EXT_COMM_2_REG);
17588c2ecf20Sopenharmony_ci	phy_data &= ~JM_PHY_EXT_COMM_2_CALI_MODE_0;
17598c2ecf20Sopenharmony_ci	phy_data |= JM_PHY_EXT_COMM_2_CALI_LATCH |
17608c2ecf20Sopenharmony_ci			JM_PHY_EXT_COMM_2_CALI_ENABLE;
17618c2ecf20Sopenharmony_ci	jme_phy_specreg_write(jme, JM_PHY_EXT_COMM_2_REG, phy_data);
17628c2ecf20Sopenharmony_ci	msleep(20);
17638c2ecf20Sopenharmony_ci	phy_data = jme_phy_specreg_read(jme, JM_PHY_EXT_COMM_2_REG);
17648c2ecf20Sopenharmony_ci	phy_data &= ~(JM_PHY_EXT_COMM_2_CALI_ENABLE |
17658c2ecf20Sopenharmony_ci			JM_PHY_EXT_COMM_2_CALI_MODE_0 |
17668c2ecf20Sopenharmony_ci			JM_PHY_EXT_COMM_2_CALI_LATCH);
17678c2ecf20Sopenharmony_ci	jme_phy_specreg_write(jme, JM_PHY_EXT_COMM_2_REG, phy_data);
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci	/*  Disable PHY test mode */
17708c2ecf20Sopenharmony_ci	ctrl1000 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_CTRL1000);
17718c2ecf20Sopenharmony_ci	ctrl1000 &= ~PHY_GAD_TEST_MODE_MSK;
17728c2ecf20Sopenharmony_ci	jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_CTRL1000, ctrl1000);
17738c2ecf20Sopenharmony_ci	return 0;
17748c2ecf20Sopenharmony_ci}
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_cistatic int
17778c2ecf20Sopenharmony_cijme_phy_setEA(struct jme_adapter *jme)
17788c2ecf20Sopenharmony_ci{
17798c2ecf20Sopenharmony_ci	u32 phy_comm0 = 0, phy_comm1 = 0;
17808c2ecf20Sopenharmony_ci	u8 nic_ctrl;
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci	pci_read_config_byte(jme->pdev, PCI_PRIV_SHARE_NICCTRL, &nic_ctrl);
17838c2ecf20Sopenharmony_ci	if ((nic_ctrl & 0x3) == JME_FLAG_PHYEA_ENABLE)
17848c2ecf20Sopenharmony_ci		return 0;
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	switch (jme->pdev->device) {
17878c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_JMICRON_JMC250:
17888c2ecf20Sopenharmony_ci		if (((jme->chip_main_rev == 5) &&
17898c2ecf20Sopenharmony_ci			((jme->chip_sub_rev == 0) || (jme->chip_sub_rev == 1) ||
17908c2ecf20Sopenharmony_ci			(jme->chip_sub_rev == 3))) ||
17918c2ecf20Sopenharmony_ci			(jme->chip_main_rev >= 6)) {
17928c2ecf20Sopenharmony_ci			phy_comm0 = 0x008A;
17938c2ecf20Sopenharmony_ci			phy_comm1 = 0x4109;
17948c2ecf20Sopenharmony_ci		}
17958c2ecf20Sopenharmony_ci		if ((jme->chip_main_rev == 3) &&
17968c2ecf20Sopenharmony_ci			((jme->chip_sub_rev == 1) || (jme->chip_sub_rev == 2)))
17978c2ecf20Sopenharmony_ci			phy_comm0 = 0xE088;
17988c2ecf20Sopenharmony_ci		break;
17998c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_JMICRON_JMC260:
18008c2ecf20Sopenharmony_ci		if (((jme->chip_main_rev == 5) &&
18018c2ecf20Sopenharmony_ci			((jme->chip_sub_rev == 0) || (jme->chip_sub_rev == 1) ||
18028c2ecf20Sopenharmony_ci			(jme->chip_sub_rev == 3))) ||
18038c2ecf20Sopenharmony_ci			(jme->chip_main_rev >= 6)) {
18048c2ecf20Sopenharmony_ci			phy_comm0 = 0x008A;
18058c2ecf20Sopenharmony_ci			phy_comm1 = 0x4109;
18068c2ecf20Sopenharmony_ci		}
18078c2ecf20Sopenharmony_ci		if ((jme->chip_main_rev == 3) &&
18088c2ecf20Sopenharmony_ci			((jme->chip_sub_rev == 1) || (jme->chip_sub_rev == 2)))
18098c2ecf20Sopenharmony_ci			phy_comm0 = 0xE088;
18108c2ecf20Sopenharmony_ci		if ((jme->chip_main_rev == 2) && (jme->chip_sub_rev == 0))
18118c2ecf20Sopenharmony_ci			phy_comm0 = 0x608A;
18128c2ecf20Sopenharmony_ci		if ((jme->chip_main_rev == 2) && (jme->chip_sub_rev == 2))
18138c2ecf20Sopenharmony_ci			phy_comm0 = 0x408A;
18148c2ecf20Sopenharmony_ci		break;
18158c2ecf20Sopenharmony_ci	default:
18168c2ecf20Sopenharmony_ci		return -ENODEV;
18178c2ecf20Sopenharmony_ci	}
18188c2ecf20Sopenharmony_ci	if (phy_comm0)
18198c2ecf20Sopenharmony_ci		jme_phy_specreg_write(jme, JM_PHY_EXT_COMM_0_REG, phy_comm0);
18208c2ecf20Sopenharmony_ci	if (phy_comm1)
18218c2ecf20Sopenharmony_ci		jme_phy_specreg_write(jme, JM_PHY_EXT_COMM_1_REG, phy_comm1);
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	return 0;
18248c2ecf20Sopenharmony_ci}
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_cistatic int
18278c2ecf20Sopenharmony_cijme_open(struct net_device *netdev)
18288c2ecf20Sopenharmony_ci{
18298c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
18308c2ecf20Sopenharmony_ci	int rc;
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	jme_clear_pm_disable_wol(jme);
18338c2ecf20Sopenharmony_ci	JME_NAPI_ENABLE(jme);
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	tasklet_setup(&jme->linkch_task, jme_link_change_tasklet);
18368c2ecf20Sopenharmony_ci	tasklet_setup(&jme->txclean_task, jme_tx_clean_tasklet);
18378c2ecf20Sopenharmony_ci	tasklet_setup(&jme->rxclean_task, jme_rx_clean_tasklet);
18388c2ecf20Sopenharmony_ci	tasklet_setup(&jme->rxempty_task, jme_rx_empty_tasklet);
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_ci	rc = jme_request_irq(jme);
18418c2ecf20Sopenharmony_ci	if (rc)
18428c2ecf20Sopenharmony_ci		goto err_out;
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci	jme_start_irq(jme);
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	jme_phy_on(jme);
18478c2ecf20Sopenharmony_ci	if (test_bit(JME_FLAG_SSET, &jme->flags))
18488c2ecf20Sopenharmony_ci		jme_set_link_ksettings(netdev, &jme->old_cmd);
18498c2ecf20Sopenharmony_ci	else
18508c2ecf20Sopenharmony_ci		jme_reset_phy_processor(jme);
18518c2ecf20Sopenharmony_ci	jme_phy_calibration(jme);
18528c2ecf20Sopenharmony_ci	jme_phy_setEA(jme);
18538c2ecf20Sopenharmony_ci	jme_reset_link(jme);
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	return 0;
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_cierr_out:
18588c2ecf20Sopenharmony_ci	netif_stop_queue(netdev);
18598c2ecf20Sopenharmony_ci	netif_carrier_off(netdev);
18608c2ecf20Sopenharmony_ci	return rc;
18618c2ecf20Sopenharmony_ci}
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_cistatic void
18648c2ecf20Sopenharmony_cijme_set_100m_half(struct jme_adapter *jme)
18658c2ecf20Sopenharmony_ci{
18668c2ecf20Sopenharmony_ci	u32 bmcr, tmp;
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	jme_phy_on(jme);
18698c2ecf20Sopenharmony_ci	bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR);
18708c2ecf20Sopenharmony_ci	tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
18718c2ecf20Sopenharmony_ci		       BMCR_SPEED1000 | BMCR_FULLDPLX);
18728c2ecf20Sopenharmony_ci	tmp |= BMCR_SPEED100;
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci	if (bmcr != tmp)
18758c2ecf20Sopenharmony_ci		jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, tmp);
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	if (jme->fpgaver)
18788c2ecf20Sopenharmony_ci		jwrite32(jme, JME_GHC, GHC_SPEED_100M | GHC_LINK_POLL);
18798c2ecf20Sopenharmony_ci	else
18808c2ecf20Sopenharmony_ci		jwrite32(jme, JME_GHC, GHC_SPEED_100M);
18818c2ecf20Sopenharmony_ci}
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci#define JME_WAIT_LINK_TIME 2000 /* 2000ms */
18848c2ecf20Sopenharmony_cistatic void
18858c2ecf20Sopenharmony_cijme_wait_link(struct jme_adapter *jme)
18868c2ecf20Sopenharmony_ci{
18878c2ecf20Sopenharmony_ci	u32 phylink, to = JME_WAIT_LINK_TIME;
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	msleep(1000);
18908c2ecf20Sopenharmony_ci	phylink = jme_linkstat_from_phy(jme);
18918c2ecf20Sopenharmony_ci	while (!(phylink & PHY_LINK_UP) && (to -= 10) > 0) {
18928c2ecf20Sopenharmony_ci		usleep_range(10000, 11000);
18938c2ecf20Sopenharmony_ci		phylink = jme_linkstat_from_phy(jme);
18948c2ecf20Sopenharmony_ci	}
18958c2ecf20Sopenharmony_ci}
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_cistatic void
18988c2ecf20Sopenharmony_cijme_powersave_phy(struct jme_adapter *jme)
18998c2ecf20Sopenharmony_ci{
19008c2ecf20Sopenharmony_ci	if (jme->reg_pmcs && device_may_wakeup(&jme->pdev->dev)) {
19018c2ecf20Sopenharmony_ci		jme_set_100m_half(jme);
19028c2ecf20Sopenharmony_ci		if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
19038c2ecf20Sopenharmony_ci			jme_wait_link(jme);
19048c2ecf20Sopenharmony_ci		jme_clear_pm_enable_wol(jme);
19058c2ecf20Sopenharmony_ci	} else {
19068c2ecf20Sopenharmony_ci		jme_phy_off(jme);
19078c2ecf20Sopenharmony_ci	}
19088c2ecf20Sopenharmony_ci}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_cistatic int
19118c2ecf20Sopenharmony_cijme_close(struct net_device *netdev)
19128c2ecf20Sopenharmony_ci{
19138c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	netif_stop_queue(netdev);
19168c2ecf20Sopenharmony_ci	netif_carrier_off(netdev);
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	jme_stop_irq(jme);
19198c2ecf20Sopenharmony_ci	jme_free_irq(jme);
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci	JME_NAPI_DISABLE(jme);
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	tasklet_kill(&jme->linkch_task);
19248c2ecf20Sopenharmony_ci	tasklet_kill(&jme->txclean_task);
19258c2ecf20Sopenharmony_ci	tasklet_kill(&jme->rxclean_task);
19268c2ecf20Sopenharmony_ci	tasklet_kill(&jme->rxempty_task);
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci	jme_disable_rx_engine(jme);
19298c2ecf20Sopenharmony_ci	jme_disable_tx_engine(jme);
19308c2ecf20Sopenharmony_ci	jme_reset_mac_processor(jme);
19318c2ecf20Sopenharmony_ci	jme_free_rx_resources(jme);
19328c2ecf20Sopenharmony_ci	jme_free_tx_resources(jme);
19338c2ecf20Sopenharmony_ci	jme->phylink = 0;
19348c2ecf20Sopenharmony_ci	jme_phy_off(jme);
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci	return 0;
19378c2ecf20Sopenharmony_ci}
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_cistatic int
19408c2ecf20Sopenharmony_cijme_alloc_txdesc(struct jme_adapter *jme,
19418c2ecf20Sopenharmony_ci			struct sk_buff *skb)
19428c2ecf20Sopenharmony_ci{
19438c2ecf20Sopenharmony_ci	struct jme_ring *txring = &(jme->txring[0]);
19448c2ecf20Sopenharmony_ci	int idx, nr_alloc, mask = jme->tx_ring_mask;
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	idx = txring->next_to_use;
19478c2ecf20Sopenharmony_ci	nr_alloc = skb_shinfo(skb)->nr_frags + 2;
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	if (unlikely(atomic_read(&txring->nr_free) < nr_alloc))
19508c2ecf20Sopenharmony_ci		return -1;
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci	atomic_sub(nr_alloc, &txring->nr_free);
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci	txring->next_to_use = (txring->next_to_use + nr_alloc) & mask;
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci	return idx;
19578c2ecf20Sopenharmony_ci}
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_cistatic int
19608c2ecf20Sopenharmony_cijme_fill_tx_map(struct pci_dev *pdev,
19618c2ecf20Sopenharmony_ci		struct txdesc *txdesc,
19628c2ecf20Sopenharmony_ci		struct jme_buffer_info *txbi,
19638c2ecf20Sopenharmony_ci		struct page *page,
19648c2ecf20Sopenharmony_ci		u32 page_offset,
19658c2ecf20Sopenharmony_ci		u32 len,
19668c2ecf20Sopenharmony_ci		bool hidma)
19678c2ecf20Sopenharmony_ci{
19688c2ecf20Sopenharmony_ci	dma_addr_t dmaaddr;
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci	dmaaddr = pci_map_page(pdev,
19718c2ecf20Sopenharmony_ci				page,
19728c2ecf20Sopenharmony_ci				page_offset,
19738c2ecf20Sopenharmony_ci				len,
19748c2ecf20Sopenharmony_ci				PCI_DMA_TODEVICE);
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci	if (unlikely(pci_dma_mapping_error(pdev, dmaaddr)))
19778c2ecf20Sopenharmony_ci		return -EINVAL;
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	pci_dma_sync_single_for_device(pdev,
19808c2ecf20Sopenharmony_ci				       dmaaddr,
19818c2ecf20Sopenharmony_ci				       len,
19828c2ecf20Sopenharmony_ci				       PCI_DMA_TODEVICE);
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	txdesc->dw[0] = 0;
19858c2ecf20Sopenharmony_ci	txdesc->dw[1] = 0;
19868c2ecf20Sopenharmony_ci	txdesc->desc2.flags	= TXFLAG_OWN;
19878c2ecf20Sopenharmony_ci	txdesc->desc2.flags	|= (hidma) ? TXFLAG_64BIT : 0;
19888c2ecf20Sopenharmony_ci	txdesc->desc2.datalen	= cpu_to_le16(len);
19898c2ecf20Sopenharmony_ci	txdesc->desc2.bufaddrh	= cpu_to_le32((__u64)dmaaddr >> 32);
19908c2ecf20Sopenharmony_ci	txdesc->desc2.bufaddrl	= cpu_to_le32(
19918c2ecf20Sopenharmony_ci					(__u64)dmaaddr & 0xFFFFFFFFUL);
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_ci	txbi->mapping = dmaaddr;
19948c2ecf20Sopenharmony_ci	txbi->len = len;
19958c2ecf20Sopenharmony_ci	return 0;
19968c2ecf20Sopenharmony_ci}
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_cistatic void jme_drop_tx_map(struct jme_adapter *jme, int startidx, int count)
19998c2ecf20Sopenharmony_ci{
20008c2ecf20Sopenharmony_ci	struct jme_ring *txring = &(jme->txring[0]);
20018c2ecf20Sopenharmony_ci	struct jme_buffer_info *txbi = txring->bufinf, *ctxbi;
20028c2ecf20Sopenharmony_ci	int mask = jme->tx_ring_mask;
20038c2ecf20Sopenharmony_ci	int j;
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_ci	for (j = 0 ; j < count ; j++) {
20068c2ecf20Sopenharmony_ci		ctxbi = txbi + ((startidx + j + 2) & (mask));
20078c2ecf20Sopenharmony_ci		pci_unmap_page(jme->pdev,
20088c2ecf20Sopenharmony_ci				ctxbi->mapping,
20098c2ecf20Sopenharmony_ci				ctxbi->len,
20108c2ecf20Sopenharmony_ci				PCI_DMA_TODEVICE);
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci		ctxbi->mapping = 0;
20138c2ecf20Sopenharmony_ci		ctxbi->len = 0;
20148c2ecf20Sopenharmony_ci	}
20158c2ecf20Sopenharmony_ci}
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_cistatic int
20188c2ecf20Sopenharmony_cijme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx)
20198c2ecf20Sopenharmony_ci{
20208c2ecf20Sopenharmony_ci	struct jme_ring *txring = &(jme->txring[0]);
20218c2ecf20Sopenharmony_ci	struct txdesc *txdesc = txring->desc, *ctxdesc;
20228c2ecf20Sopenharmony_ci	struct jme_buffer_info *txbi = txring->bufinf, *ctxbi;
20238c2ecf20Sopenharmony_ci	bool hidma = jme->dev->features & NETIF_F_HIGHDMA;
20248c2ecf20Sopenharmony_ci	int i, nr_frags = skb_shinfo(skb)->nr_frags;
20258c2ecf20Sopenharmony_ci	int mask = jme->tx_ring_mask;
20268c2ecf20Sopenharmony_ci	u32 len;
20278c2ecf20Sopenharmony_ci	int ret = 0;
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	for (i = 0 ; i < nr_frags ; ++i) {
20308c2ecf20Sopenharmony_ci		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci		ctxdesc = txdesc + ((idx + i + 2) & (mask));
20338c2ecf20Sopenharmony_ci		ctxbi = txbi + ((idx + i + 2) & (mask));
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci		ret = jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi,
20368c2ecf20Sopenharmony_ci				      skb_frag_page(frag), skb_frag_off(frag),
20378c2ecf20Sopenharmony_ci				      skb_frag_size(frag), hidma);
20388c2ecf20Sopenharmony_ci		if (ret) {
20398c2ecf20Sopenharmony_ci			jme_drop_tx_map(jme, idx, i);
20408c2ecf20Sopenharmony_ci			goto out;
20418c2ecf20Sopenharmony_ci		}
20428c2ecf20Sopenharmony_ci	}
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_ci	len = skb_is_nonlinear(skb) ? skb_headlen(skb) : skb->len;
20458c2ecf20Sopenharmony_ci	ctxdesc = txdesc + ((idx + 1) & (mask));
20468c2ecf20Sopenharmony_ci	ctxbi = txbi + ((idx + 1) & (mask));
20478c2ecf20Sopenharmony_ci	ret = jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, virt_to_page(skb->data),
20488c2ecf20Sopenharmony_ci			offset_in_page(skb->data), len, hidma);
20498c2ecf20Sopenharmony_ci	if (ret)
20508c2ecf20Sopenharmony_ci		jme_drop_tx_map(jme, idx, i);
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ciout:
20538c2ecf20Sopenharmony_ci	return ret;
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci}
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_cistatic int
20598c2ecf20Sopenharmony_cijme_tx_tso(struct sk_buff *skb, __le16 *mss, u8 *flags)
20608c2ecf20Sopenharmony_ci{
20618c2ecf20Sopenharmony_ci	*mss = cpu_to_le16(skb_shinfo(skb)->gso_size << TXDESC_MSS_SHIFT);
20628c2ecf20Sopenharmony_ci	if (*mss) {
20638c2ecf20Sopenharmony_ci		*flags |= TXFLAG_LSEN;
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci		if (skb->protocol == htons(ETH_P_IP)) {
20668c2ecf20Sopenharmony_ci			struct iphdr *iph = ip_hdr(skb);
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci			iph->check = 0;
20698c2ecf20Sopenharmony_ci			tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
20708c2ecf20Sopenharmony_ci								iph->daddr, 0,
20718c2ecf20Sopenharmony_ci								IPPROTO_TCP,
20728c2ecf20Sopenharmony_ci								0);
20738c2ecf20Sopenharmony_ci		} else {
20748c2ecf20Sopenharmony_ci			tcp_v6_gso_csum_prep(skb);
20758c2ecf20Sopenharmony_ci		}
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci		return 0;
20788c2ecf20Sopenharmony_ci	}
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci	return 1;
20818c2ecf20Sopenharmony_ci}
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_cistatic void
20848c2ecf20Sopenharmony_cijme_tx_csum(struct jme_adapter *jme, struct sk_buff *skb, u8 *flags)
20858c2ecf20Sopenharmony_ci{
20868c2ecf20Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_PARTIAL) {
20878c2ecf20Sopenharmony_ci		u8 ip_proto;
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci		switch (skb->protocol) {
20908c2ecf20Sopenharmony_ci		case htons(ETH_P_IP):
20918c2ecf20Sopenharmony_ci			ip_proto = ip_hdr(skb)->protocol;
20928c2ecf20Sopenharmony_ci			break;
20938c2ecf20Sopenharmony_ci		case htons(ETH_P_IPV6):
20948c2ecf20Sopenharmony_ci			ip_proto = ipv6_hdr(skb)->nexthdr;
20958c2ecf20Sopenharmony_ci			break;
20968c2ecf20Sopenharmony_ci		default:
20978c2ecf20Sopenharmony_ci			ip_proto = 0;
20988c2ecf20Sopenharmony_ci			break;
20998c2ecf20Sopenharmony_ci		}
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci		switch (ip_proto) {
21028c2ecf20Sopenharmony_ci		case IPPROTO_TCP:
21038c2ecf20Sopenharmony_ci			*flags |= TXFLAG_TCPCS;
21048c2ecf20Sopenharmony_ci			break;
21058c2ecf20Sopenharmony_ci		case IPPROTO_UDP:
21068c2ecf20Sopenharmony_ci			*flags |= TXFLAG_UDPCS;
21078c2ecf20Sopenharmony_ci			break;
21088c2ecf20Sopenharmony_ci		default:
21098c2ecf20Sopenharmony_ci			netif_err(jme, tx_err, jme->dev, "Error upper layer protocol\n");
21108c2ecf20Sopenharmony_ci			break;
21118c2ecf20Sopenharmony_ci		}
21128c2ecf20Sopenharmony_ci	}
21138c2ecf20Sopenharmony_ci}
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_cistatic inline void
21168c2ecf20Sopenharmony_cijme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags)
21178c2ecf20Sopenharmony_ci{
21188c2ecf20Sopenharmony_ci	if (skb_vlan_tag_present(skb)) {
21198c2ecf20Sopenharmony_ci		*flags |= TXFLAG_TAGON;
21208c2ecf20Sopenharmony_ci		*vlan = cpu_to_le16(skb_vlan_tag_get(skb));
21218c2ecf20Sopenharmony_ci	}
21228c2ecf20Sopenharmony_ci}
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_cistatic int
21258c2ecf20Sopenharmony_cijme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
21268c2ecf20Sopenharmony_ci{
21278c2ecf20Sopenharmony_ci	struct jme_ring *txring = &(jme->txring[0]);
21288c2ecf20Sopenharmony_ci	struct txdesc *txdesc;
21298c2ecf20Sopenharmony_ci	struct jme_buffer_info *txbi;
21308c2ecf20Sopenharmony_ci	u8 flags;
21318c2ecf20Sopenharmony_ci	int ret = 0;
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ci	txdesc = (struct txdesc *)txring->desc + idx;
21348c2ecf20Sopenharmony_ci	txbi = txring->bufinf + idx;
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_ci	txdesc->dw[0] = 0;
21378c2ecf20Sopenharmony_ci	txdesc->dw[1] = 0;
21388c2ecf20Sopenharmony_ci	txdesc->dw[2] = 0;
21398c2ecf20Sopenharmony_ci	txdesc->dw[3] = 0;
21408c2ecf20Sopenharmony_ci	txdesc->desc1.pktsize = cpu_to_le16(skb->len);
21418c2ecf20Sopenharmony_ci	/*
21428c2ecf20Sopenharmony_ci	 * Set OWN bit at final.
21438c2ecf20Sopenharmony_ci	 * When kernel transmit faster than NIC.
21448c2ecf20Sopenharmony_ci	 * And NIC trying to send this descriptor before we tell
21458c2ecf20Sopenharmony_ci	 * it to start sending this TX queue.
21468c2ecf20Sopenharmony_ci	 * Other fields are already filled correctly.
21478c2ecf20Sopenharmony_ci	 */
21488c2ecf20Sopenharmony_ci	wmb();
21498c2ecf20Sopenharmony_ci	flags = TXFLAG_OWN | TXFLAG_INT;
21508c2ecf20Sopenharmony_ci	/*
21518c2ecf20Sopenharmony_ci	 * Set checksum flags while not tso
21528c2ecf20Sopenharmony_ci	 */
21538c2ecf20Sopenharmony_ci	if (jme_tx_tso(skb, &txdesc->desc1.mss, &flags))
21548c2ecf20Sopenharmony_ci		jme_tx_csum(jme, skb, &flags);
21558c2ecf20Sopenharmony_ci	jme_tx_vlan(skb, &txdesc->desc1.vlan, &flags);
21568c2ecf20Sopenharmony_ci	ret = jme_map_tx_skb(jme, skb, idx);
21578c2ecf20Sopenharmony_ci	if (ret)
21588c2ecf20Sopenharmony_ci		return ret;
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci	txdesc->desc1.flags = flags;
21618c2ecf20Sopenharmony_ci	/*
21628c2ecf20Sopenharmony_ci	 * Set tx buffer info after telling NIC to send
21638c2ecf20Sopenharmony_ci	 * For better tx_clean timing
21648c2ecf20Sopenharmony_ci	 */
21658c2ecf20Sopenharmony_ci	wmb();
21668c2ecf20Sopenharmony_ci	txbi->nr_desc = skb_shinfo(skb)->nr_frags + 2;
21678c2ecf20Sopenharmony_ci	txbi->skb = skb;
21688c2ecf20Sopenharmony_ci	txbi->len = skb->len;
21698c2ecf20Sopenharmony_ci	txbi->start_xmit = jiffies;
21708c2ecf20Sopenharmony_ci	if (!txbi->start_xmit)
21718c2ecf20Sopenharmony_ci		txbi->start_xmit = (0UL-1);
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	return 0;
21748c2ecf20Sopenharmony_ci}
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_cistatic void
21778c2ecf20Sopenharmony_cijme_stop_queue_if_full(struct jme_adapter *jme)
21788c2ecf20Sopenharmony_ci{
21798c2ecf20Sopenharmony_ci	struct jme_ring *txring = &(jme->txring[0]);
21808c2ecf20Sopenharmony_ci	struct jme_buffer_info *txbi = txring->bufinf;
21818c2ecf20Sopenharmony_ci	int idx = atomic_read(&txring->next_to_clean);
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci	txbi += idx;
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_ci	smp_wmb();
21868c2ecf20Sopenharmony_ci	if (unlikely(atomic_read(&txring->nr_free) < (MAX_SKB_FRAGS+2))) {
21878c2ecf20Sopenharmony_ci		netif_stop_queue(jme->dev);
21888c2ecf20Sopenharmony_ci		netif_info(jme, tx_queued, jme->dev, "TX Queue Paused\n");
21898c2ecf20Sopenharmony_ci		smp_wmb();
21908c2ecf20Sopenharmony_ci		if (atomic_read(&txring->nr_free)
21918c2ecf20Sopenharmony_ci			>= (jme->tx_wake_threshold)) {
21928c2ecf20Sopenharmony_ci			netif_wake_queue(jme->dev);
21938c2ecf20Sopenharmony_ci			netif_info(jme, tx_queued, jme->dev, "TX Queue Fast Waked\n");
21948c2ecf20Sopenharmony_ci		}
21958c2ecf20Sopenharmony_ci	}
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci	if (unlikely(txbi->start_xmit &&
21988c2ecf20Sopenharmony_ci			(jiffies - txbi->start_xmit) >= TX_TIMEOUT &&
21998c2ecf20Sopenharmony_ci			txbi->skb)) {
22008c2ecf20Sopenharmony_ci		netif_stop_queue(jme->dev);
22018c2ecf20Sopenharmony_ci		netif_info(jme, tx_queued, jme->dev,
22028c2ecf20Sopenharmony_ci			   "TX Queue Stopped %d@%lu\n", idx, jiffies);
22038c2ecf20Sopenharmony_ci	}
22048c2ecf20Sopenharmony_ci}
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci/*
22078c2ecf20Sopenharmony_ci * This function is already protected by netif_tx_lock()
22088c2ecf20Sopenharmony_ci */
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_cistatic netdev_tx_t
22118c2ecf20Sopenharmony_cijme_start_xmit(struct sk_buff *skb, struct net_device *netdev)
22128c2ecf20Sopenharmony_ci{
22138c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
22148c2ecf20Sopenharmony_ci	int idx;
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	if (unlikely(skb_is_gso(skb) && skb_cow_head(skb, 0))) {
22178c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
22188c2ecf20Sopenharmony_ci		++(NET_STAT(jme).tx_dropped);
22198c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
22208c2ecf20Sopenharmony_ci	}
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci	idx = jme_alloc_txdesc(jme, skb);
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci	if (unlikely(idx < 0)) {
22258c2ecf20Sopenharmony_ci		netif_stop_queue(netdev);
22268c2ecf20Sopenharmony_ci		netif_err(jme, tx_err, jme->dev,
22278c2ecf20Sopenharmony_ci			  "BUG! Tx ring full when queue awake!\n");
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci		return NETDEV_TX_BUSY;
22308c2ecf20Sopenharmony_ci	}
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci	if (jme_fill_tx_desc(jme, skb, idx))
22338c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_ci	jwrite32(jme, JME_TXCS, jme->reg_txcs |
22368c2ecf20Sopenharmony_ci				TXCS_SELECT_QUEUE0 |
22378c2ecf20Sopenharmony_ci				TXCS_QUEUE0S |
22388c2ecf20Sopenharmony_ci				TXCS_ENABLE);
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_ci	tx_dbg(jme, "xmit: %d+%d@%lu\n",
22418c2ecf20Sopenharmony_ci	       idx, skb_shinfo(skb)->nr_frags + 2, jiffies);
22428c2ecf20Sopenharmony_ci	jme_stop_queue_if_full(jme);
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
22458c2ecf20Sopenharmony_ci}
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_cistatic void
22488c2ecf20Sopenharmony_cijme_set_unicastaddr(struct net_device *netdev)
22498c2ecf20Sopenharmony_ci{
22508c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
22518c2ecf20Sopenharmony_ci	u32 val;
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci	val = (netdev->dev_addr[3] & 0xff) << 24 |
22548c2ecf20Sopenharmony_ci	      (netdev->dev_addr[2] & 0xff) << 16 |
22558c2ecf20Sopenharmony_ci	      (netdev->dev_addr[1] & 0xff) <<  8 |
22568c2ecf20Sopenharmony_ci	      (netdev->dev_addr[0] & 0xff);
22578c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXUMA_LO, val);
22588c2ecf20Sopenharmony_ci	val = (netdev->dev_addr[5] & 0xff) << 8 |
22598c2ecf20Sopenharmony_ci	      (netdev->dev_addr[4] & 0xff);
22608c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXUMA_HI, val);
22618c2ecf20Sopenharmony_ci}
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_cistatic int
22648c2ecf20Sopenharmony_cijme_set_macaddr(struct net_device *netdev, void *p)
22658c2ecf20Sopenharmony_ci{
22668c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
22678c2ecf20Sopenharmony_ci	struct sockaddr *addr = p;
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci	if (netif_running(netdev))
22708c2ecf20Sopenharmony_ci		return -EBUSY;
22718c2ecf20Sopenharmony_ci
22728c2ecf20Sopenharmony_ci	spin_lock_bh(&jme->macaddr_lock);
22738c2ecf20Sopenharmony_ci	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
22748c2ecf20Sopenharmony_ci	jme_set_unicastaddr(netdev);
22758c2ecf20Sopenharmony_ci	spin_unlock_bh(&jme->macaddr_lock);
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci	return 0;
22788c2ecf20Sopenharmony_ci}
22798c2ecf20Sopenharmony_ci
22808c2ecf20Sopenharmony_cistatic void
22818c2ecf20Sopenharmony_cijme_set_multi(struct net_device *netdev)
22828c2ecf20Sopenharmony_ci{
22838c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
22848c2ecf20Sopenharmony_ci	u32 mc_hash[2] = {};
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci	spin_lock_bh(&jme->rxmcs_lock);
22878c2ecf20Sopenharmony_ci
22888c2ecf20Sopenharmony_ci	jme->reg_rxmcs |= RXMCS_BRDFRAME | RXMCS_UNIFRAME;
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_ci	if (netdev->flags & IFF_PROMISC) {
22918c2ecf20Sopenharmony_ci		jme->reg_rxmcs |= RXMCS_ALLFRAME;
22928c2ecf20Sopenharmony_ci	} else if (netdev->flags & IFF_ALLMULTI) {
22938c2ecf20Sopenharmony_ci		jme->reg_rxmcs |= RXMCS_ALLMULFRAME;
22948c2ecf20Sopenharmony_ci	} else if (netdev->flags & IFF_MULTICAST) {
22958c2ecf20Sopenharmony_ci		struct netdev_hw_addr *ha;
22968c2ecf20Sopenharmony_ci		int bit_nr;
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_ci		jme->reg_rxmcs |= RXMCS_MULFRAME | RXMCS_MULFILTERED;
22998c2ecf20Sopenharmony_ci		netdev_for_each_mc_addr(ha, netdev) {
23008c2ecf20Sopenharmony_ci			bit_nr = ether_crc(ETH_ALEN, ha->addr) & 0x3F;
23018c2ecf20Sopenharmony_ci			mc_hash[bit_nr >> 5] |= 1 << (bit_nr & 0x1F);
23028c2ecf20Sopenharmony_ci		}
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci		jwrite32(jme, JME_RXMCHT_LO, mc_hash[0]);
23058c2ecf20Sopenharmony_ci		jwrite32(jme, JME_RXMCHT_HI, mc_hash[1]);
23068c2ecf20Sopenharmony_ci	}
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci	wmb();
23098c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXMCS, jme->reg_rxmcs);
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci	spin_unlock_bh(&jme->rxmcs_lock);
23128c2ecf20Sopenharmony_ci}
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_cistatic int
23158c2ecf20Sopenharmony_cijme_change_mtu(struct net_device *netdev, int new_mtu)
23168c2ecf20Sopenharmony_ci{
23178c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci	netdev->mtu = new_mtu;
23208c2ecf20Sopenharmony_ci	netdev_update_features(netdev);
23218c2ecf20Sopenharmony_ci
23228c2ecf20Sopenharmony_ci	jme_restart_rx_engine(jme);
23238c2ecf20Sopenharmony_ci	jme_reset_link(jme);
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci	return 0;
23268c2ecf20Sopenharmony_ci}
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_cistatic void
23298c2ecf20Sopenharmony_cijme_tx_timeout(struct net_device *netdev, unsigned int txqueue)
23308c2ecf20Sopenharmony_ci{
23318c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	jme->phylink = 0;
23348c2ecf20Sopenharmony_ci	jme_reset_phy_processor(jme);
23358c2ecf20Sopenharmony_ci	if (test_bit(JME_FLAG_SSET, &jme->flags))
23368c2ecf20Sopenharmony_ci		jme_set_link_ksettings(netdev, &jme->old_cmd);
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci	/*
23398c2ecf20Sopenharmony_ci	 * Force to Reset the link again
23408c2ecf20Sopenharmony_ci	 */
23418c2ecf20Sopenharmony_ci	jme_reset_link(jme);
23428c2ecf20Sopenharmony_ci}
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_cistatic void
23458c2ecf20Sopenharmony_cijme_get_drvinfo(struct net_device *netdev,
23468c2ecf20Sopenharmony_ci		     struct ethtool_drvinfo *info)
23478c2ecf20Sopenharmony_ci{
23488c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
23498c2ecf20Sopenharmony_ci
23508c2ecf20Sopenharmony_ci	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
23518c2ecf20Sopenharmony_ci	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
23528c2ecf20Sopenharmony_ci	strlcpy(info->bus_info, pci_name(jme->pdev), sizeof(info->bus_info));
23538c2ecf20Sopenharmony_ci}
23548c2ecf20Sopenharmony_ci
23558c2ecf20Sopenharmony_cistatic int
23568c2ecf20Sopenharmony_cijme_get_regs_len(struct net_device *netdev)
23578c2ecf20Sopenharmony_ci{
23588c2ecf20Sopenharmony_ci	return JME_REG_LEN;
23598c2ecf20Sopenharmony_ci}
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_cistatic void
23628c2ecf20Sopenharmony_cimmapio_memcpy(struct jme_adapter *jme, u32 *p, u32 reg, int len)
23638c2ecf20Sopenharmony_ci{
23648c2ecf20Sopenharmony_ci	int i;
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci	for (i = 0 ; i < len ; i += 4)
23678c2ecf20Sopenharmony_ci		p[i >> 2] = jread32(jme, reg + i);
23688c2ecf20Sopenharmony_ci}
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_cistatic void
23718c2ecf20Sopenharmony_cimdio_memcpy(struct jme_adapter *jme, u32 *p, int reg_nr)
23728c2ecf20Sopenharmony_ci{
23738c2ecf20Sopenharmony_ci	int i;
23748c2ecf20Sopenharmony_ci	u16 *p16 = (u16 *)p;
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_ci	for (i = 0 ; i < reg_nr ; ++i)
23778c2ecf20Sopenharmony_ci		p16[i] = jme_mdio_read(jme->dev, jme->mii_if.phy_id, i);
23788c2ecf20Sopenharmony_ci}
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_cistatic void
23818c2ecf20Sopenharmony_cijme_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
23828c2ecf20Sopenharmony_ci{
23838c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
23848c2ecf20Sopenharmony_ci	u32 *p32 = (u32 *)p;
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	memset(p, 0xFF, JME_REG_LEN);
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ci	regs->version = 1;
23898c2ecf20Sopenharmony_ci	mmapio_memcpy(jme, p32, JME_MAC, JME_MAC_LEN);
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ci	p32 += 0x100 >> 2;
23928c2ecf20Sopenharmony_ci	mmapio_memcpy(jme, p32, JME_PHY, JME_PHY_LEN);
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_ci	p32 += 0x100 >> 2;
23958c2ecf20Sopenharmony_ci	mmapio_memcpy(jme, p32, JME_MISC, JME_MISC_LEN);
23968c2ecf20Sopenharmony_ci
23978c2ecf20Sopenharmony_ci	p32 += 0x100 >> 2;
23988c2ecf20Sopenharmony_ci	mmapio_memcpy(jme, p32, JME_RSS, JME_RSS_LEN);
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_ci	p32 += 0x100 >> 2;
24018c2ecf20Sopenharmony_ci	mdio_memcpy(jme, p32, JME_PHY_REG_NR);
24028c2ecf20Sopenharmony_ci}
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_cistatic int
24058c2ecf20Sopenharmony_cijme_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd)
24068c2ecf20Sopenharmony_ci{
24078c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci	ecmd->tx_coalesce_usecs = PCC_TX_TO;
24108c2ecf20Sopenharmony_ci	ecmd->tx_max_coalesced_frames = PCC_TX_CNT;
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci	if (test_bit(JME_FLAG_POLL, &jme->flags)) {
24138c2ecf20Sopenharmony_ci		ecmd->use_adaptive_rx_coalesce = false;
24148c2ecf20Sopenharmony_ci		ecmd->rx_coalesce_usecs = 0;
24158c2ecf20Sopenharmony_ci		ecmd->rx_max_coalesced_frames = 0;
24168c2ecf20Sopenharmony_ci		return 0;
24178c2ecf20Sopenharmony_ci	}
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_ci	ecmd->use_adaptive_rx_coalesce = true;
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci	switch (jme->dpi.cur) {
24228c2ecf20Sopenharmony_ci	case PCC_P1:
24238c2ecf20Sopenharmony_ci		ecmd->rx_coalesce_usecs = PCC_P1_TO;
24248c2ecf20Sopenharmony_ci		ecmd->rx_max_coalesced_frames = PCC_P1_CNT;
24258c2ecf20Sopenharmony_ci		break;
24268c2ecf20Sopenharmony_ci	case PCC_P2:
24278c2ecf20Sopenharmony_ci		ecmd->rx_coalesce_usecs = PCC_P2_TO;
24288c2ecf20Sopenharmony_ci		ecmd->rx_max_coalesced_frames = PCC_P2_CNT;
24298c2ecf20Sopenharmony_ci		break;
24308c2ecf20Sopenharmony_ci	case PCC_P3:
24318c2ecf20Sopenharmony_ci		ecmd->rx_coalesce_usecs = PCC_P3_TO;
24328c2ecf20Sopenharmony_ci		ecmd->rx_max_coalesced_frames = PCC_P3_CNT;
24338c2ecf20Sopenharmony_ci		break;
24348c2ecf20Sopenharmony_ci	default:
24358c2ecf20Sopenharmony_ci		break;
24368c2ecf20Sopenharmony_ci	}
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_ci	return 0;
24398c2ecf20Sopenharmony_ci}
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_cistatic int
24428c2ecf20Sopenharmony_cijme_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd)
24438c2ecf20Sopenharmony_ci{
24448c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
24458c2ecf20Sopenharmony_ci	struct dynpcc_info *dpi = &(jme->dpi);
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_ci	if (netif_running(netdev))
24488c2ecf20Sopenharmony_ci		return -EBUSY;
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_ci	if (ecmd->use_adaptive_rx_coalesce &&
24518c2ecf20Sopenharmony_ci	    test_bit(JME_FLAG_POLL, &jme->flags)) {
24528c2ecf20Sopenharmony_ci		clear_bit(JME_FLAG_POLL, &jme->flags);
24538c2ecf20Sopenharmony_ci		jme->jme_rx = netif_rx;
24548c2ecf20Sopenharmony_ci		dpi->cur		= PCC_P1;
24558c2ecf20Sopenharmony_ci		dpi->attempt		= PCC_P1;
24568c2ecf20Sopenharmony_ci		dpi->cnt		= 0;
24578c2ecf20Sopenharmony_ci		jme_set_rx_pcc(jme, PCC_P1);
24588c2ecf20Sopenharmony_ci		jme_interrupt_mode(jme);
24598c2ecf20Sopenharmony_ci	} else if (!(ecmd->use_adaptive_rx_coalesce) &&
24608c2ecf20Sopenharmony_ci		   !(test_bit(JME_FLAG_POLL, &jme->flags))) {
24618c2ecf20Sopenharmony_ci		set_bit(JME_FLAG_POLL, &jme->flags);
24628c2ecf20Sopenharmony_ci		jme->jme_rx = netif_receive_skb;
24638c2ecf20Sopenharmony_ci		jme_interrupt_mode(jme);
24648c2ecf20Sopenharmony_ci	}
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_ci	return 0;
24678c2ecf20Sopenharmony_ci}
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_cistatic void
24708c2ecf20Sopenharmony_cijme_get_pauseparam(struct net_device *netdev,
24718c2ecf20Sopenharmony_ci			struct ethtool_pauseparam *ecmd)
24728c2ecf20Sopenharmony_ci{
24738c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
24748c2ecf20Sopenharmony_ci	u32 val;
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_ci	ecmd->tx_pause = (jme->reg_txpfc & TXPFC_PF_EN) != 0;
24778c2ecf20Sopenharmony_ci	ecmd->rx_pause = (jme->reg_rxmcs & RXMCS_FLOWCTRL) != 0;
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_ci	spin_lock_bh(&jme->phy_lock);
24808c2ecf20Sopenharmony_ci	val = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE);
24818c2ecf20Sopenharmony_ci	spin_unlock_bh(&jme->phy_lock);
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci	ecmd->autoneg =
24848c2ecf20Sopenharmony_ci		(val & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) != 0;
24858c2ecf20Sopenharmony_ci}
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_cistatic int
24888c2ecf20Sopenharmony_cijme_set_pauseparam(struct net_device *netdev,
24898c2ecf20Sopenharmony_ci			struct ethtool_pauseparam *ecmd)
24908c2ecf20Sopenharmony_ci{
24918c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
24928c2ecf20Sopenharmony_ci	u32 val;
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	if (((jme->reg_txpfc & TXPFC_PF_EN) != 0) ^
24958c2ecf20Sopenharmony_ci		(ecmd->tx_pause != 0)) {
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci		if (ecmd->tx_pause)
24988c2ecf20Sopenharmony_ci			jme->reg_txpfc |= TXPFC_PF_EN;
24998c2ecf20Sopenharmony_ci		else
25008c2ecf20Sopenharmony_ci			jme->reg_txpfc &= ~TXPFC_PF_EN;
25018c2ecf20Sopenharmony_ci
25028c2ecf20Sopenharmony_ci		jwrite32(jme, JME_TXPFC, jme->reg_txpfc);
25038c2ecf20Sopenharmony_ci	}
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci	spin_lock_bh(&jme->rxmcs_lock);
25068c2ecf20Sopenharmony_ci	if (((jme->reg_rxmcs & RXMCS_FLOWCTRL) != 0) ^
25078c2ecf20Sopenharmony_ci		(ecmd->rx_pause != 0)) {
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci		if (ecmd->rx_pause)
25108c2ecf20Sopenharmony_ci			jme->reg_rxmcs |= RXMCS_FLOWCTRL;
25118c2ecf20Sopenharmony_ci		else
25128c2ecf20Sopenharmony_ci			jme->reg_rxmcs &= ~RXMCS_FLOWCTRL;
25138c2ecf20Sopenharmony_ci
25148c2ecf20Sopenharmony_ci		jwrite32(jme, JME_RXMCS, jme->reg_rxmcs);
25158c2ecf20Sopenharmony_ci	}
25168c2ecf20Sopenharmony_ci	spin_unlock_bh(&jme->rxmcs_lock);
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci	spin_lock_bh(&jme->phy_lock);
25198c2ecf20Sopenharmony_ci	val = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE);
25208c2ecf20Sopenharmony_ci	if (((val & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) != 0) ^
25218c2ecf20Sopenharmony_ci		(ecmd->autoneg != 0)) {
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci		if (ecmd->autoneg)
25248c2ecf20Sopenharmony_ci			val |= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
25258c2ecf20Sopenharmony_ci		else
25268c2ecf20Sopenharmony_ci			val &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci		jme_mdio_write(jme->dev, jme->mii_if.phy_id,
25298c2ecf20Sopenharmony_ci				MII_ADVERTISE, val);
25308c2ecf20Sopenharmony_ci	}
25318c2ecf20Sopenharmony_ci	spin_unlock_bh(&jme->phy_lock);
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ci	return 0;
25348c2ecf20Sopenharmony_ci}
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_cistatic void
25378c2ecf20Sopenharmony_cijme_get_wol(struct net_device *netdev,
25388c2ecf20Sopenharmony_ci		struct ethtool_wolinfo *wol)
25398c2ecf20Sopenharmony_ci{
25408c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_ci	wol->supported = WAKE_MAGIC | WAKE_PHY;
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci	wol->wolopts = 0;
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci	if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
25478c2ecf20Sopenharmony_ci		wol->wolopts |= WAKE_PHY;
25488c2ecf20Sopenharmony_ci
25498c2ecf20Sopenharmony_ci	if (jme->reg_pmcs & PMCS_MFEN)
25508c2ecf20Sopenharmony_ci		wol->wolopts |= WAKE_MAGIC;
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci}
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_cistatic int
25558c2ecf20Sopenharmony_cijme_set_wol(struct net_device *netdev,
25568c2ecf20Sopenharmony_ci		struct ethtool_wolinfo *wol)
25578c2ecf20Sopenharmony_ci{
25588c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci	if (wol->wolopts & (WAKE_MAGICSECURE |
25618c2ecf20Sopenharmony_ci				WAKE_UCAST |
25628c2ecf20Sopenharmony_ci				WAKE_MCAST |
25638c2ecf20Sopenharmony_ci				WAKE_BCAST |
25648c2ecf20Sopenharmony_ci				WAKE_ARP))
25658c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci	jme->reg_pmcs = 0;
25688c2ecf20Sopenharmony_ci
25698c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_PHY)
25708c2ecf20Sopenharmony_ci		jme->reg_pmcs |= PMCS_LFEN | PMCS_LREN;
25718c2ecf20Sopenharmony_ci
25728c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_MAGIC)
25738c2ecf20Sopenharmony_ci		jme->reg_pmcs |= PMCS_MFEN;
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci	return 0;
25768c2ecf20Sopenharmony_ci}
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_cistatic int
25798c2ecf20Sopenharmony_cijme_get_link_ksettings(struct net_device *netdev,
25808c2ecf20Sopenharmony_ci		       struct ethtool_link_ksettings *cmd)
25818c2ecf20Sopenharmony_ci{
25828c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci	spin_lock_bh(&jme->phy_lock);
25858c2ecf20Sopenharmony_ci	mii_ethtool_get_link_ksettings(&jme->mii_if, cmd);
25868c2ecf20Sopenharmony_ci	spin_unlock_bh(&jme->phy_lock);
25878c2ecf20Sopenharmony_ci	return 0;
25888c2ecf20Sopenharmony_ci}
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_cistatic int
25918c2ecf20Sopenharmony_cijme_set_link_ksettings(struct net_device *netdev,
25928c2ecf20Sopenharmony_ci		       const struct ethtool_link_ksettings *cmd)
25938c2ecf20Sopenharmony_ci{
25948c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
25958c2ecf20Sopenharmony_ci	int rc, fdc = 0;
25968c2ecf20Sopenharmony_ci
25978c2ecf20Sopenharmony_ci	if (cmd->base.speed == SPEED_1000 &&
25988c2ecf20Sopenharmony_ci	    cmd->base.autoneg != AUTONEG_ENABLE)
25998c2ecf20Sopenharmony_ci		return -EINVAL;
26008c2ecf20Sopenharmony_ci
26018c2ecf20Sopenharmony_ci	/*
26028c2ecf20Sopenharmony_ci	 * Check If user changed duplex only while force_media.
26038c2ecf20Sopenharmony_ci	 * Hardware would not generate link change interrupt.
26048c2ecf20Sopenharmony_ci	 */
26058c2ecf20Sopenharmony_ci	if (jme->mii_if.force_media &&
26068c2ecf20Sopenharmony_ci	    cmd->base.autoneg != AUTONEG_ENABLE &&
26078c2ecf20Sopenharmony_ci	    (jme->mii_if.full_duplex != cmd->base.duplex))
26088c2ecf20Sopenharmony_ci		fdc = 1;
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci	spin_lock_bh(&jme->phy_lock);
26118c2ecf20Sopenharmony_ci	rc = mii_ethtool_set_link_ksettings(&jme->mii_if, cmd);
26128c2ecf20Sopenharmony_ci	spin_unlock_bh(&jme->phy_lock);
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci	if (!rc) {
26158c2ecf20Sopenharmony_ci		if (fdc)
26168c2ecf20Sopenharmony_ci			jme_reset_link(jme);
26178c2ecf20Sopenharmony_ci		jme->old_cmd = *cmd;
26188c2ecf20Sopenharmony_ci		set_bit(JME_FLAG_SSET, &jme->flags);
26198c2ecf20Sopenharmony_ci	}
26208c2ecf20Sopenharmony_ci
26218c2ecf20Sopenharmony_ci	return rc;
26228c2ecf20Sopenharmony_ci}
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_cistatic int
26258c2ecf20Sopenharmony_cijme_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
26268c2ecf20Sopenharmony_ci{
26278c2ecf20Sopenharmony_ci	int rc;
26288c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
26298c2ecf20Sopenharmony_ci	struct mii_ioctl_data *mii_data = if_mii(rq);
26308c2ecf20Sopenharmony_ci	unsigned int duplex_chg;
26318c2ecf20Sopenharmony_ci
26328c2ecf20Sopenharmony_ci	if (cmd == SIOCSMIIREG) {
26338c2ecf20Sopenharmony_ci		u16 val = mii_data->val_in;
26348c2ecf20Sopenharmony_ci		if (!(val & (BMCR_RESET|BMCR_ANENABLE)) &&
26358c2ecf20Sopenharmony_ci		    (val & BMCR_SPEED1000))
26368c2ecf20Sopenharmony_ci			return -EINVAL;
26378c2ecf20Sopenharmony_ci	}
26388c2ecf20Sopenharmony_ci
26398c2ecf20Sopenharmony_ci	spin_lock_bh(&jme->phy_lock);
26408c2ecf20Sopenharmony_ci	rc = generic_mii_ioctl(&jme->mii_if, mii_data, cmd, &duplex_chg);
26418c2ecf20Sopenharmony_ci	spin_unlock_bh(&jme->phy_lock);
26428c2ecf20Sopenharmony_ci
26438c2ecf20Sopenharmony_ci	if (!rc && (cmd == SIOCSMIIREG)) {
26448c2ecf20Sopenharmony_ci		if (duplex_chg)
26458c2ecf20Sopenharmony_ci			jme_reset_link(jme);
26468c2ecf20Sopenharmony_ci		jme_get_link_ksettings(netdev, &jme->old_cmd);
26478c2ecf20Sopenharmony_ci		set_bit(JME_FLAG_SSET, &jme->flags);
26488c2ecf20Sopenharmony_ci	}
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci	return rc;
26518c2ecf20Sopenharmony_ci}
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_cistatic u32
26548c2ecf20Sopenharmony_cijme_get_link(struct net_device *netdev)
26558c2ecf20Sopenharmony_ci{
26568c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
26578c2ecf20Sopenharmony_ci	return jread32(jme, JME_PHY_LINK) & PHY_LINK_UP;
26588c2ecf20Sopenharmony_ci}
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_cistatic u32
26618c2ecf20Sopenharmony_cijme_get_msglevel(struct net_device *netdev)
26628c2ecf20Sopenharmony_ci{
26638c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
26648c2ecf20Sopenharmony_ci	return jme->msg_enable;
26658c2ecf20Sopenharmony_ci}
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_cistatic void
26688c2ecf20Sopenharmony_cijme_set_msglevel(struct net_device *netdev, u32 value)
26698c2ecf20Sopenharmony_ci{
26708c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
26718c2ecf20Sopenharmony_ci	jme->msg_enable = value;
26728c2ecf20Sopenharmony_ci}
26738c2ecf20Sopenharmony_ci
26748c2ecf20Sopenharmony_cistatic netdev_features_t
26758c2ecf20Sopenharmony_cijme_fix_features(struct net_device *netdev, netdev_features_t features)
26768c2ecf20Sopenharmony_ci{
26778c2ecf20Sopenharmony_ci	if (netdev->mtu > 1900)
26788c2ecf20Sopenharmony_ci		features &= ~(NETIF_F_ALL_TSO | NETIF_F_CSUM_MASK);
26798c2ecf20Sopenharmony_ci	return features;
26808c2ecf20Sopenharmony_ci}
26818c2ecf20Sopenharmony_ci
26828c2ecf20Sopenharmony_cistatic int
26838c2ecf20Sopenharmony_cijme_set_features(struct net_device *netdev, netdev_features_t features)
26848c2ecf20Sopenharmony_ci{
26858c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
26868c2ecf20Sopenharmony_ci
26878c2ecf20Sopenharmony_ci	spin_lock_bh(&jme->rxmcs_lock);
26888c2ecf20Sopenharmony_ci	if (features & NETIF_F_RXCSUM)
26898c2ecf20Sopenharmony_ci		jme->reg_rxmcs |= RXMCS_CHECKSUM;
26908c2ecf20Sopenharmony_ci	else
26918c2ecf20Sopenharmony_ci		jme->reg_rxmcs &= ~RXMCS_CHECKSUM;
26928c2ecf20Sopenharmony_ci	jwrite32(jme, JME_RXMCS, jme->reg_rxmcs);
26938c2ecf20Sopenharmony_ci	spin_unlock_bh(&jme->rxmcs_lock);
26948c2ecf20Sopenharmony_ci
26958c2ecf20Sopenharmony_ci	return 0;
26968c2ecf20Sopenharmony_ci}
26978c2ecf20Sopenharmony_ci
26988c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
26998c2ecf20Sopenharmony_cistatic void jme_netpoll(struct net_device *dev)
27008c2ecf20Sopenharmony_ci{
27018c2ecf20Sopenharmony_ci	unsigned long flags;
27028c2ecf20Sopenharmony_ci
27038c2ecf20Sopenharmony_ci	local_irq_save(flags);
27048c2ecf20Sopenharmony_ci	jme_intr(dev->irq, dev);
27058c2ecf20Sopenharmony_ci	local_irq_restore(flags);
27068c2ecf20Sopenharmony_ci}
27078c2ecf20Sopenharmony_ci#endif
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_cistatic int
27108c2ecf20Sopenharmony_cijme_nway_reset(struct net_device *netdev)
27118c2ecf20Sopenharmony_ci{
27128c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
27138c2ecf20Sopenharmony_ci	jme_restart_an(jme);
27148c2ecf20Sopenharmony_ci	return 0;
27158c2ecf20Sopenharmony_ci}
27168c2ecf20Sopenharmony_ci
27178c2ecf20Sopenharmony_cistatic u8
27188c2ecf20Sopenharmony_cijme_smb_read(struct jme_adapter *jme, unsigned int addr)
27198c2ecf20Sopenharmony_ci{
27208c2ecf20Sopenharmony_ci	u32 val;
27218c2ecf20Sopenharmony_ci	int to;
27228c2ecf20Sopenharmony_ci
27238c2ecf20Sopenharmony_ci	val = jread32(jme, JME_SMBCSR);
27248c2ecf20Sopenharmony_ci	to = JME_SMB_BUSY_TIMEOUT;
27258c2ecf20Sopenharmony_ci	while ((val & SMBCSR_BUSY) && --to) {
27268c2ecf20Sopenharmony_ci		msleep(1);
27278c2ecf20Sopenharmony_ci		val = jread32(jme, JME_SMBCSR);
27288c2ecf20Sopenharmony_ci	}
27298c2ecf20Sopenharmony_ci	if (!to) {
27308c2ecf20Sopenharmony_ci		netif_err(jme, hw, jme->dev, "SMB Bus Busy\n");
27318c2ecf20Sopenharmony_ci		return 0xFF;
27328c2ecf20Sopenharmony_ci	}
27338c2ecf20Sopenharmony_ci
27348c2ecf20Sopenharmony_ci	jwrite32(jme, JME_SMBINTF,
27358c2ecf20Sopenharmony_ci		((addr << SMBINTF_HWADDR_SHIFT) & SMBINTF_HWADDR) |
27368c2ecf20Sopenharmony_ci		SMBINTF_HWRWN_READ |
27378c2ecf20Sopenharmony_ci		SMBINTF_HWCMD);
27388c2ecf20Sopenharmony_ci
27398c2ecf20Sopenharmony_ci	val = jread32(jme, JME_SMBINTF);
27408c2ecf20Sopenharmony_ci	to = JME_SMB_BUSY_TIMEOUT;
27418c2ecf20Sopenharmony_ci	while ((val & SMBINTF_HWCMD) && --to) {
27428c2ecf20Sopenharmony_ci		msleep(1);
27438c2ecf20Sopenharmony_ci		val = jread32(jme, JME_SMBINTF);
27448c2ecf20Sopenharmony_ci	}
27458c2ecf20Sopenharmony_ci	if (!to) {
27468c2ecf20Sopenharmony_ci		netif_err(jme, hw, jme->dev, "SMB Bus Busy\n");
27478c2ecf20Sopenharmony_ci		return 0xFF;
27488c2ecf20Sopenharmony_ci	}
27498c2ecf20Sopenharmony_ci
27508c2ecf20Sopenharmony_ci	return (val & SMBINTF_HWDATR) >> SMBINTF_HWDATR_SHIFT;
27518c2ecf20Sopenharmony_ci}
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_cistatic void
27548c2ecf20Sopenharmony_cijme_smb_write(struct jme_adapter *jme, unsigned int addr, u8 data)
27558c2ecf20Sopenharmony_ci{
27568c2ecf20Sopenharmony_ci	u32 val;
27578c2ecf20Sopenharmony_ci	int to;
27588c2ecf20Sopenharmony_ci
27598c2ecf20Sopenharmony_ci	val = jread32(jme, JME_SMBCSR);
27608c2ecf20Sopenharmony_ci	to = JME_SMB_BUSY_TIMEOUT;
27618c2ecf20Sopenharmony_ci	while ((val & SMBCSR_BUSY) && --to) {
27628c2ecf20Sopenharmony_ci		msleep(1);
27638c2ecf20Sopenharmony_ci		val = jread32(jme, JME_SMBCSR);
27648c2ecf20Sopenharmony_ci	}
27658c2ecf20Sopenharmony_ci	if (!to) {
27668c2ecf20Sopenharmony_ci		netif_err(jme, hw, jme->dev, "SMB Bus Busy\n");
27678c2ecf20Sopenharmony_ci		return;
27688c2ecf20Sopenharmony_ci	}
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci	jwrite32(jme, JME_SMBINTF,
27718c2ecf20Sopenharmony_ci		((data << SMBINTF_HWDATW_SHIFT) & SMBINTF_HWDATW) |
27728c2ecf20Sopenharmony_ci		((addr << SMBINTF_HWADDR_SHIFT) & SMBINTF_HWADDR) |
27738c2ecf20Sopenharmony_ci		SMBINTF_HWRWN_WRITE |
27748c2ecf20Sopenharmony_ci		SMBINTF_HWCMD);
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	val = jread32(jme, JME_SMBINTF);
27778c2ecf20Sopenharmony_ci	to = JME_SMB_BUSY_TIMEOUT;
27788c2ecf20Sopenharmony_ci	while ((val & SMBINTF_HWCMD) && --to) {
27798c2ecf20Sopenharmony_ci		msleep(1);
27808c2ecf20Sopenharmony_ci		val = jread32(jme, JME_SMBINTF);
27818c2ecf20Sopenharmony_ci	}
27828c2ecf20Sopenharmony_ci	if (!to) {
27838c2ecf20Sopenharmony_ci		netif_err(jme, hw, jme->dev, "SMB Bus Busy\n");
27848c2ecf20Sopenharmony_ci		return;
27858c2ecf20Sopenharmony_ci	}
27868c2ecf20Sopenharmony_ci
27878c2ecf20Sopenharmony_ci	mdelay(2);
27888c2ecf20Sopenharmony_ci}
27898c2ecf20Sopenharmony_ci
27908c2ecf20Sopenharmony_cistatic int
27918c2ecf20Sopenharmony_cijme_get_eeprom_len(struct net_device *netdev)
27928c2ecf20Sopenharmony_ci{
27938c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
27948c2ecf20Sopenharmony_ci	u32 val;
27958c2ecf20Sopenharmony_ci	val = jread32(jme, JME_SMBCSR);
27968c2ecf20Sopenharmony_ci	return (val & SMBCSR_EEPROMD) ? JME_SMB_LEN : 0;
27978c2ecf20Sopenharmony_ci}
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_cistatic int
28008c2ecf20Sopenharmony_cijme_get_eeprom(struct net_device *netdev,
28018c2ecf20Sopenharmony_ci		struct ethtool_eeprom *eeprom, u8 *data)
28028c2ecf20Sopenharmony_ci{
28038c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
28048c2ecf20Sopenharmony_ci	int i, offset = eeprom->offset, len = eeprom->len;
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_ci	/*
28078c2ecf20Sopenharmony_ci	 * ethtool will check the boundary for us
28088c2ecf20Sopenharmony_ci	 */
28098c2ecf20Sopenharmony_ci	eeprom->magic = JME_EEPROM_MAGIC;
28108c2ecf20Sopenharmony_ci	for (i = 0 ; i < len ; ++i)
28118c2ecf20Sopenharmony_ci		data[i] = jme_smb_read(jme, i + offset);
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_ci	return 0;
28148c2ecf20Sopenharmony_ci}
28158c2ecf20Sopenharmony_ci
28168c2ecf20Sopenharmony_cistatic int
28178c2ecf20Sopenharmony_cijme_set_eeprom(struct net_device *netdev,
28188c2ecf20Sopenharmony_ci		struct ethtool_eeprom *eeprom, u8 *data)
28198c2ecf20Sopenharmony_ci{
28208c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
28218c2ecf20Sopenharmony_ci	int i, offset = eeprom->offset, len = eeprom->len;
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_ci	if (eeprom->magic != JME_EEPROM_MAGIC)
28248c2ecf20Sopenharmony_ci		return -EINVAL;
28258c2ecf20Sopenharmony_ci
28268c2ecf20Sopenharmony_ci	/*
28278c2ecf20Sopenharmony_ci	 * ethtool will check the boundary for us
28288c2ecf20Sopenharmony_ci	 */
28298c2ecf20Sopenharmony_ci	for (i = 0 ; i < len ; ++i)
28308c2ecf20Sopenharmony_ci		jme_smb_write(jme, i + offset, data[i]);
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci	return 0;
28338c2ecf20Sopenharmony_ci}
28348c2ecf20Sopenharmony_ci
28358c2ecf20Sopenharmony_cistatic const struct ethtool_ops jme_ethtool_ops = {
28368c2ecf20Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
28378c2ecf20Sopenharmony_ci				     ETHTOOL_COALESCE_MAX_FRAMES |
28388c2ecf20Sopenharmony_ci				     ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
28398c2ecf20Sopenharmony_ci	.get_drvinfo            = jme_get_drvinfo,
28408c2ecf20Sopenharmony_ci	.get_regs_len		= jme_get_regs_len,
28418c2ecf20Sopenharmony_ci	.get_regs		= jme_get_regs,
28428c2ecf20Sopenharmony_ci	.get_coalesce		= jme_get_coalesce,
28438c2ecf20Sopenharmony_ci	.set_coalesce		= jme_set_coalesce,
28448c2ecf20Sopenharmony_ci	.get_pauseparam		= jme_get_pauseparam,
28458c2ecf20Sopenharmony_ci	.set_pauseparam		= jme_set_pauseparam,
28468c2ecf20Sopenharmony_ci	.get_wol		= jme_get_wol,
28478c2ecf20Sopenharmony_ci	.set_wol		= jme_set_wol,
28488c2ecf20Sopenharmony_ci	.get_link		= jme_get_link,
28498c2ecf20Sopenharmony_ci	.get_msglevel           = jme_get_msglevel,
28508c2ecf20Sopenharmony_ci	.set_msglevel           = jme_set_msglevel,
28518c2ecf20Sopenharmony_ci	.nway_reset             = jme_nway_reset,
28528c2ecf20Sopenharmony_ci	.get_eeprom_len		= jme_get_eeprom_len,
28538c2ecf20Sopenharmony_ci	.get_eeprom		= jme_get_eeprom,
28548c2ecf20Sopenharmony_ci	.set_eeprom		= jme_set_eeprom,
28558c2ecf20Sopenharmony_ci	.get_link_ksettings	= jme_get_link_ksettings,
28568c2ecf20Sopenharmony_ci	.set_link_ksettings	= jme_set_link_ksettings,
28578c2ecf20Sopenharmony_ci};
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_cistatic int
28608c2ecf20Sopenharmony_cijme_pci_dma64(struct pci_dev *pdev)
28618c2ecf20Sopenharmony_ci{
28628c2ecf20Sopenharmony_ci	if (pdev->device == PCI_DEVICE_ID_JMICRON_JMC250 &&
28638c2ecf20Sopenharmony_ci	    !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
28648c2ecf20Sopenharmony_ci		if (!pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
28658c2ecf20Sopenharmony_ci			return 1;
28668c2ecf20Sopenharmony_ci
28678c2ecf20Sopenharmony_ci	if (pdev->device == PCI_DEVICE_ID_JMICRON_JMC250 &&
28688c2ecf20Sopenharmony_ci	    !pci_set_dma_mask(pdev, DMA_BIT_MASK(40)))
28698c2ecf20Sopenharmony_ci		if (!pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(40)))
28708c2ecf20Sopenharmony_ci			return 1;
28718c2ecf20Sopenharmony_ci
28728c2ecf20Sopenharmony_ci	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
28738c2ecf20Sopenharmony_ci		if (!pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
28748c2ecf20Sopenharmony_ci			return 0;
28758c2ecf20Sopenharmony_ci
28768c2ecf20Sopenharmony_ci	return -1;
28778c2ecf20Sopenharmony_ci}
28788c2ecf20Sopenharmony_ci
28798c2ecf20Sopenharmony_cistatic inline void
28808c2ecf20Sopenharmony_cijme_phy_init(struct jme_adapter *jme)
28818c2ecf20Sopenharmony_ci{
28828c2ecf20Sopenharmony_ci	u16 reg26;
28838c2ecf20Sopenharmony_ci
28848c2ecf20Sopenharmony_ci	reg26 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, 26);
28858c2ecf20Sopenharmony_ci	jme_mdio_write(jme->dev, jme->mii_if.phy_id, 26, reg26 | 0x1000);
28868c2ecf20Sopenharmony_ci}
28878c2ecf20Sopenharmony_ci
28888c2ecf20Sopenharmony_cistatic inline void
28898c2ecf20Sopenharmony_cijme_check_hw_ver(struct jme_adapter *jme)
28908c2ecf20Sopenharmony_ci{
28918c2ecf20Sopenharmony_ci	u32 chipmode;
28928c2ecf20Sopenharmony_ci
28938c2ecf20Sopenharmony_ci	chipmode = jread32(jme, JME_CHIPMODE);
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci	jme->fpgaver = (chipmode & CM_FPGAVER_MASK) >> CM_FPGAVER_SHIFT;
28968c2ecf20Sopenharmony_ci	jme->chiprev = (chipmode & CM_CHIPREV_MASK) >> CM_CHIPREV_SHIFT;
28978c2ecf20Sopenharmony_ci	jme->chip_main_rev = jme->chiprev & 0xF;
28988c2ecf20Sopenharmony_ci	jme->chip_sub_rev = (jme->chiprev >> 4) & 0xF;
28998c2ecf20Sopenharmony_ci}
29008c2ecf20Sopenharmony_ci
29018c2ecf20Sopenharmony_cistatic const struct net_device_ops jme_netdev_ops = {
29028c2ecf20Sopenharmony_ci	.ndo_open		= jme_open,
29038c2ecf20Sopenharmony_ci	.ndo_stop		= jme_close,
29048c2ecf20Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
29058c2ecf20Sopenharmony_ci	.ndo_do_ioctl		= jme_ioctl,
29068c2ecf20Sopenharmony_ci	.ndo_start_xmit		= jme_start_xmit,
29078c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= jme_set_macaddr,
29088c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	= jme_set_multi,
29098c2ecf20Sopenharmony_ci	.ndo_change_mtu		= jme_change_mtu,
29108c2ecf20Sopenharmony_ci	.ndo_tx_timeout		= jme_tx_timeout,
29118c2ecf20Sopenharmony_ci	.ndo_fix_features       = jme_fix_features,
29128c2ecf20Sopenharmony_ci	.ndo_set_features       = jme_set_features,
29138c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
29148c2ecf20Sopenharmony_ci	.ndo_poll_controller	= jme_netpoll,
29158c2ecf20Sopenharmony_ci#endif
29168c2ecf20Sopenharmony_ci};
29178c2ecf20Sopenharmony_ci
29188c2ecf20Sopenharmony_cistatic int
29198c2ecf20Sopenharmony_cijme_init_one(struct pci_dev *pdev,
29208c2ecf20Sopenharmony_ci	     const struct pci_device_id *ent)
29218c2ecf20Sopenharmony_ci{
29228c2ecf20Sopenharmony_ci	int rc = 0, using_dac, i;
29238c2ecf20Sopenharmony_ci	struct net_device *netdev;
29248c2ecf20Sopenharmony_ci	struct jme_adapter *jme;
29258c2ecf20Sopenharmony_ci	u16 bmcr, bmsr;
29268c2ecf20Sopenharmony_ci	u32 apmc;
29278c2ecf20Sopenharmony_ci
29288c2ecf20Sopenharmony_ci	/*
29298c2ecf20Sopenharmony_ci	 * set up PCI device basics
29308c2ecf20Sopenharmony_ci	 */
29318c2ecf20Sopenharmony_ci	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
29328c2ecf20Sopenharmony_ci			       PCIE_LINK_STATE_CLKPM);
29338c2ecf20Sopenharmony_ci
29348c2ecf20Sopenharmony_ci	rc = pci_enable_device(pdev);
29358c2ecf20Sopenharmony_ci	if (rc) {
29368c2ecf20Sopenharmony_ci		pr_err("Cannot enable PCI device\n");
29378c2ecf20Sopenharmony_ci		goto err_out;
29388c2ecf20Sopenharmony_ci	}
29398c2ecf20Sopenharmony_ci
29408c2ecf20Sopenharmony_ci	using_dac = jme_pci_dma64(pdev);
29418c2ecf20Sopenharmony_ci	if (using_dac < 0) {
29428c2ecf20Sopenharmony_ci		pr_err("Cannot set PCI DMA Mask\n");
29438c2ecf20Sopenharmony_ci		rc = -EIO;
29448c2ecf20Sopenharmony_ci		goto err_out_disable_pdev;
29458c2ecf20Sopenharmony_ci	}
29468c2ecf20Sopenharmony_ci
29478c2ecf20Sopenharmony_ci	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
29488c2ecf20Sopenharmony_ci		pr_err("No PCI resource region found\n");
29498c2ecf20Sopenharmony_ci		rc = -ENOMEM;
29508c2ecf20Sopenharmony_ci		goto err_out_disable_pdev;
29518c2ecf20Sopenharmony_ci	}
29528c2ecf20Sopenharmony_ci
29538c2ecf20Sopenharmony_ci	rc = pci_request_regions(pdev, DRV_NAME);
29548c2ecf20Sopenharmony_ci	if (rc) {
29558c2ecf20Sopenharmony_ci		pr_err("Cannot obtain PCI resource region\n");
29568c2ecf20Sopenharmony_ci		goto err_out_disable_pdev;
29578c2ecf20Sopenharmony_ci	}
29588c2ecf20Sopenharmony_ci
29598c2ecf20Sopenharmony_ci	pci_set_master(pdev);
29608c2ecf20Sopenharmony_ci
29618c2ecf20Sopenharmony_ci	/*
29628c2ecf20Sopenharmony_ci	 * alloc and init net device
29638c2ecf20Sopenharmony_ci	 */
29648c2ecf20Sopenharmony_ci	netdev = alloc_etherdev(sizeof(*jme));
29658c2ecf20Sopenharmony_ci	if (!netdev) {
29668c2ecf20Sopenharmony_ci		rc = -ENOMEM;
29678c2ecf20Sopenharmony_ci		goto err_out_release_regions;
29688c2ecf20Sopenharmony_ci	}
29698c2ecf20Sopenharmony_ci	netdev->netdev_ops = &jme_netdev_ops;
29708c2ecf20Sopenharmony_ci	netdev->ethtool_ops		= &jme_ethtool_ops;
29718c2ecf20Sopenharmony_ci	netdev->watchdog_timeo		= TX_TIMEOUT;
29728c2ecf20Sopenharmony_ci	netdev->hw_features		=	NETIF_F_IP_CSUM |
29738c2ecf20Sopenharmony_ci						NETIF_F_IPV6_CSUM |
29748c2ecf20Sopenharmony_ci						NETIF_F_SG |
29758c2ecf20Sopenharmony_ci						NETIF_F_TSO |
29768c2ecf20Sopenharmony_ci						NETIF_F_TSO6 |
29778c2ecf20Sopenharmony_ci						NETIF_F_RXCSUM;
29788c2ecf20Sopenharmony_ci	netdev->features		=	NETIF_F_IP_CSUM |
29798c2ecf20Sopenharmony_ci						NETIF_F_IPV6_CSUM |
29808c2ecf20Sopenharmony_ci						NETIF_F_SG |
29818c2ecf20Sopenharmony_ci						NETIF_F_TSO |
29828c2ecf20Sopenharmony_ci						NETIF_F_TSO6 |
29838c2ecf20Sopenharmony_ci						NETIF_F_HW_VLAN_CTAG_TX |
29848c2ecf20Sopenharmony_ci						NETIF_F_HW_VLAN_CTAG_RX;
29858c2ecf20Sopenharmony_ci	if (using_dac)
29868c2ecf20Sopenharmony_ci		netdev->features	|=	NETIF_F_HIGHDMA;
29878c2ecf20Sopenharmony_ci
29888c2ecf20Sopenharmony_ci	/* MTU range: 1280 - 9202*/
29898c2ecf20Sopenharmony_ci	netdev->min_mtu = IPV6_MIN_MTU;
29908c2ecf20Sopenharmony_ci	netdev->max_mtu = MAX_ETHERNET_JUMBO_PACKET_SIZE - ETH_HLEN;
29918c2ecf20Sopenharmony_ci
29928c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(netdev, &pdev->dev);
29938c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, netdev);
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_ci	/*
29968c2ecf20Sopenharmony_ci	 * init adapter info
29978c2ecf20Sopenharmony_ci	 */
29988c2ecf20Sopenharmony_ci	jme = netdev_priv(netdev);
29998c2ecf20Sopenharmony_ci	jme->pdev = pdev;
30008c2ecf20Sopenharmony_ci	jme->dev = netdev;
30018c2ecf20Sopenharmony_ci	jme->jme_rx = netif_rx;
30028c2ecf20Sopenharmony_ci	jme->old_mtu = netdev->mtu = 1500;
30038c2ecf20Sopenharmony_ci	jme->phylink = 0;
30048c2ecf20Sopenharmony_ci	jme->tx_ring_size = 1 << 10;
30058c2ecf20Sopenharmony_ci	jme->tx_ring_mask = jme->tx_ring_size - 1;
30068c2ecf20Sopenharmony_ci	jme->tx_wake_threshold = 1 << 9;
30078c2ecf20Sopenharmony_ci	jme->rx_ring_size = 1 << 9;
30088c2ecf20Sopenharmony_ci	jme->rx_ring_mask = jme->rx_ring_size - 1;
30098c2ecf20Sopenharmony_ci	jme->msg_enable = JME_DEF_MSG_ENABLE;
30108c2ecf20Sopenharmony_ci	jme->regs = ioremap(pci_resource_start(pdev, 0),
30118c2ecf20Sopenharmony_ci			     pci_resource_len(pdev, 0));
30128c2ecf20Sopenharmony_ci	if (!(jme->regs)) {
30138c2ecf20Sopenharmony_ci		pr_err("Mapping PCI resource region error\n");
30148c2ecf20Sopenharmony_ci		rc = -ENOMEM;
30158c2ecf20Sopenharmony_ci		goto err_out_free_netdev;
30168c2ecf20Sopenharmony_ci	}
30178c2ecf20Sopenharmony_ci
30188c2ecf20Sopenharmony_ci	if (no_pseudohp) {
30198c2ecf20Sopenharmony_ci		apmc = jread32(jme, JME_APMC) & ~JME_APMC_PSEUDO_HP_EN;
30208c2ecf20Sopenharmony_ci		jwrite32(jme, JME_APMC, apmc);
30218c2ecf20Sopenharmony_ci	} else if (force_pseudohp) {
30228c2ecf20Sopenharmony_ci		apmc = jread32(jme, JME_APMC) | JME_APMC_PSEUDO_HP_EN;
30238c2ecf20Sopenharmony_ci		jwrite32(jme, JME_APMC, apmc);
30248c2ecf20Sopenharmony_ci	}
30258c2ecf20Sopenharmony_ci
30268c2ecf20Sopenharmony_ci	NETIF_NAPI_SET(netdev, &jme->napi, jme_poll, NAPI_POLL_WEIGHT)
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci	spin_lock_init(&jme->phy_lock);
30298c2ecf20Sopenharmony_ci	spin_lock_init(&jme->macaddr_lock);
30308c2ecf20Sopenharmony_ci	spin_lock_init(&jme->rxmcs_lock);
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_ci	atomic_set(&jme->link_changing, 1);
30338c2ecf20Sopenharmony_ci	atomic_set(&jme->rx_cleaning, 1);
30348c2ecf20Sopenharmony_ci	atomic_set(&jme->tx_cleaning, 1);
30358c2ecf20Sopenharmony_ci	atomic_set(&jme->rx_empty, 1);
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci	tasklet_setup(&jme->pcc_task, jme_pcc_tasklet);
30388c2ecf20Sopenharmony_ci	jme->dpi.cur = PCC_P1;
30398c2ecf20Sopenharmony_ci
30408c2ecf20Sopenharmony_ci	jme->reg_ghc = 0;
30418c2ecf20Sopenharmony_ci	jme->reg_rxcs = RXCS_DEFAULT;
30428c2ecf20Sopenharmony_ci	jme->reg_rxmcs = RXMCS_DEFAULT;
30438c2ecf20Sopenharmony_ci	jme->reg_txpfc = 0;
30448c2ecf20Sopenharmony_ci	jme->reg_pmcs = PMCS_MFEN;
30458c2ecf20Sopenharmony_ci	jme->reg_gpreg1 = GPREG1_DEFAULT;
30468c2ecf20Sopenharmony_ci
30478c2ecf20Sopenharmony_ci	if (jme->reg_rxmcs & RXMCS_CHECKSUM)
30488c2ecf20Sopenharmony_ci		netdev->features |= NETIF_F_RXCSUM;
30498c2ecf20Sopenharmony_ci
30508c2ecf20Sopenharmony_ci	/*
30518c2ecf20Sopenharmony_ci	 * Get Max Read Req Size from PCI Config Space
30528c2ecf20Sopenharmony_ci	 */
30538c2ecf20Sopenharmony_ci	pci_read_config_byte(pdev, PCI_DCSR_MRRS, &jme->mrrs);
30548c2ecf20Sopenharmony_ci	jme->mrrs &= PCI_DCSR_MRRS_MASK;
30558c2ecf20Sopenharmony_ci	switch (jme->mrrs) {
30568c2ecf20Sopenharmony_ci	case MRRS_128B:
30578c2ecf20Sopenharmony_ci		jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_128B;
30588c2ecf20Sopenharmony_ci		break;
30598c2ecf20Sopenharmony_ci	case MRRS_256B:
30608c2ecf20Sopenharmony_ci		jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_256B;
30618c2ecf20Sopenharmony_ci		break;
30628c2ecf20Sopenharmony_ci	default:
30638c2ecf20Sopenharmony_ci		jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_512B;
30648c2ecf20Sopenharmony_ci		break;
30658c2ecf20Sopenharmony_ci	}
30668c2ecf20Sopenharmony_ci
30678c2ecf20Sopenharmony_ci	/*
30688c2ecf20Sopenharmony_ci	 * Must check before reset_mac_processor
30698c2ecf20Sopenharmony_ci	 */
30708c2ecf20Sopenharmony_ci	jme_check_hw_ver(jme);
30718c2ecf20Sopenharmony_ci	jme->mii_if.dev = netdev;
30728c2ecf20Sopenharmony_ci	if (jme->fpgaver) {
30738c2ecf20Sopenharmony_ci		jme->mii_if.phy_id = 0;
30748c2ecf20Sopenharmony_ci		for (i = 1 ; i < 32 ; ++i) {
30758c2ecf20Sopenharmony_ci			bmcr = jme_mdio_read(netdev, i, MII_BMCR);
30768c2ecf20Sopenharmony_ci			bmsr = jme_mdio_read(netdev, i, MII_BMSR);
30778c2ecf20Sopenharmony_ci			if (bmcr != 0xFFFFU && (bmcr != 0 || bmsr != 0)) {
30788c2ecf20Sopenharmony_ci				jme->mii_if.phy_id = i;
30798c2ecf20Sopenharmony_ci				break;
30808c2ecf20Sopenharmony_ci			}
30818c2ecf20Sopenharmony_ci		}
30828c2ecf20Sopenharmony_ci
30838c2ecf20Sopenharmony_ci		if (!jme->mii_if.phy_id) {
30848c2ecf20Sopenharmony_ci			rc = -EIO;
30858c2ecf20Sopenharmony_ci			pr_err("Can not find phy_id\n");
30868c2ecf20Sopenharmony_ci			goto err_out_unmap;
30878c2ecf20Sopenharmony_ci		}
30888c2ecf20Sopenharmony_ci
30898c2ecf20Sopenharmony_ci		jme->reg_ghc |= GHC_LINK_POLL;
30908c2ecf20Sopenharmony_ci	} else {
30918c2ecf20Sopenharmony_ci		jme->mii_if.phy_id = 1;
30928c2ecf20Sopenharmony_ci	}
30938c2ecf20Sopenharmony_ci	if (pdev->device == PCI_DEVICE_ID_JMICRON_JMC250)
30948c2ecf20Sopenharmony_ci		jme->mii_if.supports_gmii = true;
30958c2ecf20Sopenharmony_ci	else
30968c2ecf20Sopenharmony_ci		jme->mii_if.supports_gmii = false;
30978c2ecf20Sopenharmony_ci	jme->mii_if.phy_id_mask = 0x1F;
30988c2ecf20Sopenharmony_ci	jme->mii_if.reg_num_mask = 0x1F;
30998c2ecf20Sopenharmony_ci	jme->mii_if.mdio_read = jme_mdio_read;
31008c2ecf20Sopenharmony_ci	jme->mii_if.mdio_write = jme_mdio_write;
31018c2ecf20Sopenharmony_ci
31028c2ecf20Sopenharmony_ci	jme_clear_pm_disable_wol(jme);
31038c2ecf20Sopenharmony_ci	device_init_wakeup(&pdev->dev, true);
31048c2ecf20Sopenharmony_ci
31058c2ecf20Sopenharmony_ci	jme_set_phyfifo_5level(jme);
31068c2ecf20Sopenharmony_ci	jme->pcirev = pdev->revision;
31078c2ecf20Sopenharmony_ci	if (!jme->fpgaver)
31088c2ecf20Sopenharmony_ci		jme_phy_init(jme);
31098c2ecf20Sopenharmony_ci	jme_phy_off(jme);
31108c2ecf20Sopenharmony_ci
31118c2ecf20Sopenharmony_ci	/*
31128c2ecf20Sopenharmony_ci	 * Reset MAC processor and reload EEPROM for MAC Address
31138c2ecf20Sopenharmony_ci	 */
31148c2ecf20Sopenharmony_ci	jme_reset_mac_processor(jme);
31158c2ecf20Sopenharmony_ci	rc = jme_reload_eeprom(jme);
31168c2ecf20Sopenharmony_ci	if (rc) {
31178c2ecf20Sopenharmony_ci		pr_err("Reload eeprom for reading MAC Address error\n");
31188c2ecf20Sopenharmony_ci		goto err_out_unmap;
31198c2ecf20Sopenharmony_ci	}
31208c2ecf20Sopenharmony_ci	jme_load_macaddr(netdev);
31218c2ecf20Sopenharmony_ci
31228c2ecf20Sopenharmony_ci	/*
31238c2ecf20Sopenharmony_ci	 * Tell stack that we are not ready to work until open()
31248c2ecf20Sopenharmony_ci	 */
31258c2ecf20Sopenharmony_ci	netif_carrier_off(netdev);
31268c2ecf20Sopenharmony_ci
31278c2ecf20Sopenharmony_ci	rc = register_netdev(netdev);
31288c2ecf20Sopenharmony_ci	if (rc) {
31298c2ecf20Sopenharmony_ci		pr_err("Cannot register net device\n");
31308c2ecf20Sopenharmony_ci		goto err_out_unmap;
31318c2ecf20Sopenharmony_ci	}
31328c2ecf20Sopenharmony_ci
31338c2ecf20Sopenharmony_ci	netif_info(jme, probe, jme->dev, "%s%s chiprev:%x pcirev:%x macaddr:%pM\n",
31348c2ecf20Sopenharmony_ci		   (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) ?
31358c2ecf20Sopenharmony_ci		   "JMC250 Gigabit Ethernet" :
31368c2ecf20Sopenharmony_ci		   (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC260) ?
31378c2ecf20Sopenharmony_ci		   "JMC260 Fast Ethernet" : "Unknown",
31388c2ecf20Sopenharmony_ci		   (jme->fpgaver != 0) ? " (FPGA)" : "",
31398c2ecf20Sopenharmony_ci		   (jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev,
31408c2ecf20Sopenharmony_ci		   jme->pcirev, netdev->dev_addr);
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci	return 0;
31438c2ecf20Sopenharmony_ci
31448c2ecf20Sopenharmony_cierr_out_unmap:
31458c2ecf20Sopenharmony_ci	iounmap(jme->regs);
31468c2ecf20Sopenharmony_cierr_out_free_netdev:
31478c2ecf20Sopenharmony_ci	free_netdev(netdev);
31488c2ecf20Sopenharmony_cierr_out_release_regions:
31498c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
31508c2ecf20Sopenharmony_cierr_out_disable_pdev:
31518c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
31528c2ecf20Sopenharmony_cierr_out:
31538c2ecf20Sopenharmony_ci	return rc;
31548c2ecf20Sopenharmony_ci}
31558c2ecf20Sopenharmony_ci
31568c2ecf20Sopenharmony_cistatic void
31578c2ecf20Sopenharmony_cijme_remove_one(struct pci_dev *pdev)
31588c2ecf20Sopenharmony_ci{
31598c2ecf20Sopenharmony_ci	struct net_device *netdev = pci_get_drvdata(pdev);
31608c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
31618c2ecf20Sopenharmony_ci
31628c2ecf20Sopenharmony_ci	unregister_netdev(netdev);
31638c2ecf20Sopenharmony_ci	iounmap(jme->regs);
31648c2ecf20Sopenharmony_ci	free_netdev(netdev);
31658c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
31668c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
31678c2ecf20Sopenharmony_ci
31688c2ecf20Sopenharmony_ci}
31698c2ecf20Sopenharmony_ci
31708c2ecf20Sopenharmony_cistatic void
31718c2ecf20Sopenharmony_cijme_shutdown(struct pci_dev *pdev)
31728c2ecf20Sopenharmony_ci{
31738c2ecf20Sopenharmony_ci	struct net_device *netdev = pci_get_drvdata(pdev);
31748c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	jme_powersave_phy(jme);
31778c2ecf20Sopenharmony_ci	pci_pme_active(pdev, true);
31788c2ecf20Sopenharmony_ci}
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
31818c2ecf20Sopenharmony_cistatic int
31828c2ecf20Sopenharmony_cijme_suspend(struct device *dev)
31838c2ecf20Sopenharmony_ci{
31848c2ecf20Sopenharmony_ci	struct net_device *netdev = dev_get_drvdata(dev);
31858c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
31868c2ecf20Sopenharmony_ci
31878c2ecf20Sopenharmony_ci	if (!netif_running(netdev))
31888c2ecf20Sopenharmony_ci		return 0;
31898c2ecf20Sopenharmony_ci
31908c2ecf20Sopenharmony_ci	atomic_dec(&jme->link_changing);
31918c2ecf20Sopenharmony_ci
31928c2ecf20Sopenharmony_ci	netif_device_detach(netdev);
31938c2ecf20Sopenharmony_ci	netif_stop_queue(netdev);
31948c2ecf20Sopenharmony_ci	jme_stop_irq(jme);
31958c2ecf20Sopenharmony_ci
31968c2ecf20Sopenharmony_ci	tasklet_disable(&jme->txclean_task);
31978c2ecf20Sopenharmony_ci	tasklet_disable(&jme->rxclean_task);
31988c2ecf20Sopenharmony_ci	tasklet_disable(&jme->rxempty_task);
31998c2ecf20Sopenharmony_ci
32008c2ecf20Sopenharmony_ci	if (netif_carrier_ok(netdev)) {
32018c2ecf20Sopenharmony_ci		if (test_bit(JME_FLAG_POLL, &jme->flags))
32028c2ecf20Sopenharmony_ci			jme_polling_mode(jme);
32038c2ecf20Sopenharmony_ci
32048c2ecf20Sopenharmony_ci		jme_stop_pcc_timer(jme);
32058c2ecf20Sopenharmony_ci		jme_disable_rx_engine(jme);
32068c2ecf20Sopenharmony_ci		jme_disable_tx_engine(jme);
32078c2ecf20Sopenharmony_ci		jme_reset_mac_processor(jme);
32088c2ecf20Sopenharmony_ci		jme_free_rx_resources(jme);
32098c2ecf20Sopenharmony_ci		jme_free_tx_resources(jme);
32108c2ecf20Sopenharmony_ci		netif_carrier_off(netdev);
32118c2ecf20Sopenharmony_ci		jme->phylink = 0;
32128c2ecf20Sopenharmony_ci	}
32138c2ecf20Sopenharmony_ci
32148c2ecf20Sopenharmony_ci	tasklet_enable(&jme->txclean_task);
32158c2ecf20Sopenharmony_ci	tasklet_enable(&jme->rxclean_task);
32168c2ecf20Sopenharmony_ci	tasklet_enable(&jme->rxempty_task);
32178c2ecf20Sopenharmony_ci
32188c2ecf20Sopenharmony_ci	jme_powersave_phy(jme);
32198c2ecf20Sopenharmony_ci
32208c2ecf20Sopenharmony_ci	return 0;
32218c2ecf20Sopenharmony_ci}
32228c2ecf20Sopenharmony_ci
32238c2ecf20Sopenharmony_cistatic int
32248c2ecf20Sopenharmony_cijme_resume(struct device *dev)
32258c2ecf20Sopenharmony_ci{
32268c2ecf20Sopenharmony_ci	struct net_device *netdev = dev_get_drvdata(dev);
32278c2ecf20Sopenharmony_ci	struct jme_adapter *jme = netdev_priv(netdev);
32288c2ecf20Sopenharmony_ci
32298c2ecf20Sopenharmony_ci	if (!netif_running(netdev))
32308c2ecf20Sopenharmony_ci		return 0;
32318c2ecf20Sopenharmony_ci
32328c2ecf20Sopenharmony_ci	jme_clear_pm_disable_wol(jme);
32338c2ecf20Sopenharmony_ci	jme_phy_on(jme);
32348c2ecf20Sopenharmony_ci	if (test_bit(JME_FLAG_SSET, &jme->flags))
32358c2ecf20Sopenharmony_ci		jme_set_link_ksettings(netdev, &jme->old_cmd);
32368c2ecf20Sopenharmony_ci	else
32378c2ecf20Sopenharmony_ci		jme_reset_phy_processor(jme);
32388c2ecf20Sopenharmony_ci	jme_phy_calibration(jme);
32398c2ecf20Sopenharmony_ci	jme_phy_setEA(jme);
32408c2ecf20Sopenharmony_ci	netif_device_attach(netdev);
32418c2ecf20Sopenharmony_ci
32428c2ecf20Sopenharmony_ci	atomic_inc(&jme->link_changing);
32438c2ecf20Sopenharmony_ci
32448c2ecf20Sopenharmony_ci	jme_reset_link(jme);
32458c2ecf20Sopenharmony_ci
32468c2ecf20Sopenharmony_ci	jme_start_irq(jme);
32478c2ecf20Sopenharmony_ci
32488c2ecf20Sopenharmony_ci	return 0;
32498c2ecf20Sopenharmony_ci}
32508c2ecf20Sopenharmony_ci
32518c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(jme_pm_ops, jme_suspend, jme_resume);
32528c2ecf20Sopenharmony_ci#define JME_PM_OPS (&jme_pm_ops)
32538c2ecf20Sopenharmony_ci
32548c2ecf20Sopenharmony_ci#else
32558c2ecf20Sopenharmony_ci
32568c2ecf20Sopenharmony_ci#define JME_PM_OPS NULL
32578c2ecf20Sopenharmony_ci#endif
32588c2ecf20Sopenharmony_ci
32598c2ecf20Sopenharmony_cistatic const struct pci_device_id jme_pci_tbl[] = {
32608c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC250) },
32618c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC260) },
32628c2ecf20Sopenharmony_ci	{ }
32638c2ecf20Sopenharmony_ci};
32648c2ecf20Sopenharmony_ci
32658c2ecf20Sopenharmony_cistatic struct pci_driver jme_driver = {
32668c2ecf20Sopenharmony_ci	.name           = DRV_NAME,
32678c2ecf20Sopenharmony_ci	.id_table       = jme_pci_tbl,
32688c2ecf20Sopenharmony_ci	.probe          = jme_init_one,
32698c2ecf20Sopenharmony_ci	.remove         = jme_remove_one,
32708c2ecf20Sopenharmony_ci	.shutdown       = jme_shutdown,
32718c2ecf20Sopenharmony_ci	.driver.pm	= JME_PM_OPS,
32728c2ecf20Sopenharmony_ci};
32738c2ecf20Sopenharmony_ci
32748c2ecf20Sopenharmony_cistatic int __init
32758c2ecf20Sopenharmony_cijme_init_module(void)
32768c2ecf20Sopenharmony_ci{
32778c2ecf20Sopenharmony_ci	pr_info("JMicron JMC2XX ethernet driver version %s\n", DRV_VERSION);
32788c2ecf20Sopenharmony_ci	return pci_register_driver(&jme_driver);
32798c2ecf20Sopenharmony_ci}
32808c2ecf20Sopenharmony_ci
32818c2ecf20Sopenharmony_cistatic void __exit
32828c2ecf20Sopenharmony_cijme_cleanup_module(void)
32838c2ecf20Sopenharmony_ci{
32848c2ecf20Sopenharmony_ci	pci_unregister_driver(&jme_driver);
32858c2ecf20Sopenharmony_ci}
32868c2ecf20Sopenharmony_ci
32878c2ecf20Sopenharmony_cimodule_init(jme_init_module);
32888c2ecf20Sopenharmony_cimodule_exit(jme_cleanup_module);
32898c2ecf20Sopenharmony_ci
32908c2ecf20Sopenharmony_ciMODULE_AUTHOR("Guo-Fu Tseng <cooldavid@cooldavid.org>");
32918c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("JMicron JMC2x0 PCI Express Ethernet driver");
32928c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
32938c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION);
32948c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, jme_pci_tbl);
3295