Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce85e13a authored by Woojung.Huh@microchip.com's avatar Woojung.Huh@microchip.com Committed by David S. Miller
Browse files

lan78xx: Update to use phylib instead of mii_if_info.



Update to use phylib instead of mii_if_info.

Signed-off-by: default avatarWoojung Huh <woojung.huh@microchip.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 05fe68c0
Loading
Loading
Loading
Loading
+256 −362
Original line number Original line Diff line number Diff line
@@ -19,7 +19,6 @@
#include <linux/netdevice.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/usb.h>
#include <linux/crc32.h>
#include <linux/crc32.h>
#include <linux/signal.h>
#include <linux/signal.h>
@@ -36,7 +35,7 @@
#define DRIVER_AUTHOR	"WOOJUNG HUH <woojung.huh@microchip.com>"
#define DRIVER_AUTHOR	"WOOJUNG HUH <woojung.huh@microchip.com>"
#define DRIVER_DESC	"LAN78XX USB 3.0 Gigabit Ethernet Devices"
#define DRIVER_DESC	"LAN78XX USB 3.0 Gigabit Ethernet Devices"
#define DRIVER_NAME	"lan78xx"
#define DRIVER_NAME	"lan78xx"
#define DRIVER_VERSION	"1.0.0"
#define DRIVER_VERSION	"1.0.1"


#define TX_TIMEOUT_JIFFIES		(5 * HZ)
#define TX_TIMEOUT_JIFFIES		(5 * HZ)
#define THROTTLE_JIFFIES		(HZ / 8)
#define THROTTLE_JIFFIES		(HZ / 8)
@@ -57,7 +56,6 @@
#define DEFAULT_RX_CSUM_ENABLE		(true)
#define DEFAULT_RX_CSUM_ENABLE		(true)
#define DEFAULT_TSO_CSUM_ENABLE		(true)
#define DEFAULT_TSO_CSUM_ENABLE		(true)
#define DEFAULT_VLAN_FILTER_ENABLE	(true)
#define DEFAULT_VLAN_FILTER_ENABLE	(true)
#define INTERNAL_PHY_ID			(2)	/* 2: GMII */
#define TX_OVERHEAD			(8)
#define TX_OVERHEAD			(8)
#define RXW_PADDING			2
#define RXW_PADDING			2


@@ -275,10 +273,12 @@ struct lan78xx_net {
	struct timer_list	delay;
	struct timer_list	delay;


	unsigned long		data[5];
	unsigned long		data[5];
	struct mii_if_info	mii;


	int			link_on;
	int			link_on;
	u8			mdix_ctrl;
	u8			mdix_ctrl;

	u32			devid;
	struct mii_bus		*mdiobus;
};
};


/* use ethtool to change the level for any given device */
/* use ethtool to change the level for any given device */
@@ -411,222 +411,6 @@ static inline u32 mii_access(int id, int index, int read)
	return ret;
	return ret;
}
}


static int lan78xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
{
	struct lan78xx_net *dev = netdev_priv(netdev);
	u32 val, addr;
	int ret;

	ret = usb_autopm_get_interface(dev->intf);
	if (ret < 0)
		return ret;

	mutex_lock(&dev->phy_mutex);

	/* confirm MII not busy */
	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	/* set the address, index & direction (read from PHY) */
	phy_id &= dev->mii.phy_id_mask;
	idx &= dev->mii.reg_num_mask;
	addr = mii_access(phy_id, idx, MII_READ);
	ret = lan78xx_write_reg(dev, MII_ACC, addr);

	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	ret = lan78xx_read_reg(dev, MII_DATA, &val);

	ret = (int)(val & 0xFFFF);

done:
	mutex_unlock(&dev->phy_mutex);
	usb_autopm_put_interface(dev->intf);
	return ret;
}

static void lan78xx_mdio_write(struct net_device *netdev, int phy_id,
			       int idx, int regval)
{
	struct lan78xx_net *dev = netdev_priv(netdev);
	u32 val, addr;
	int ret;

	if (usb_autopm_get_interface(dev->intf) < 0)
		return;

	mutex_lock(&dev->phy_mutex);

	/* confirm MII not busy */
	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	val = regval;
	ret = lan78xx_write_reg(dev, MII_DATA, val);

	/* set the address, index & direction (write to PHY) */
	phy_id &= dev->mii.phy_id_mask;
	idx &= dev->mii.reg_num_mask;
	addr = mii_access(phy_id, idx, MII_WRITE);
	ret = lan78xx_write_reg(dev, MII_ACC, addr);

	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

done:
	mutex_unlock(&dev->phy_mutex);
	usb_autopm_put_interface(dev->intf);
}

static void lan78xx_mmd_write(struct net_device *netdev, int phy_id,
			      int mmddev, int mmdidx, int regval)
{
	struct lan78xx_net *dev = netdev_priv(netdev);
	u32 val, addr;
	int ret;

	if (usb_autopm_get_interface(dev->intf) < 0)
		return;

	mutex_lock(&dev->phy_mutex);

	/* confirm MII not busy */
	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	mmddev &= 0x1F;

	/* set up device address for MMD */
	ret = lan78xx_write_reg(dev, MII_DATA, mmddev);

	phy_id &= dev->mii.phy_id_mask;
	addr = mii_access(phy_id, PHY_MMD_CTL, MII_WRITE);
	ret = lan78xx_write_reg(dev, MII_ACC, addr);

	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	/* select register of MMD */
	val = mmdidx;
	ret = lan78xx_write_reg(dev, MII_DATA, val);

	phy_id &= dev->mii.phy_id_mask;
	addr = mii_access(phy_id, PHY_MMD_REG_DATA, MII_WRITE);
	ret = lan78xx_write_reg(dev, MII_ACC, addr);

	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	/* select register data for MMD */
	val = PHY_MMD_CTRL_OP_DNI_ | mmddev;
	ret = lan78xx_write_reg(dev, MII_DATA, val);

	phy_id &= dev->mii.phy_id_mask;
	addr = mii_access(phy_id, PHY_MMD_CTL, MII_WRITE);
	ret = lan78xx_write_reg(dev, MII_ACC, addr);

	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	/* write to MMD */
	val = regval;
	ret = lan78xx_write_reg(dev, MII_DATA, val);

	phy_id &= dev->mii.phy_id_mask;
	addr = mii_access(phy_id, PHY_MMD_REG_DATA, MII_WRITE);
	ret = lan78xx_write_reg(dev, MII_ACC, addr);

	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

done:
	mutex_unlock(&dev->phy_mutex);
	usb_autopm_put_interface(dev->intf);
}

static int lan78xx_mmd_read(struct net_device *netdev, int phy_id,
			    int mmddev, int mmdidx)
{
	struct lan78xx_net *dev = netdev_priv(netdev);
	u32 val, addr;
	int ret;

	ret = usb_autopm_get_interface(dev->intf);
	if (ret < 0)
		return ret;

	mutex_lock(&dev->phy_mutex);

	/* confirm MII not busy */
	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	/* set up device address for MMD */
	ret = lan78xx_write_reg(dev, MII_DATA, mmddev);

	phy_id &= dev->mii.phy_id_mask;
	addr = mii_access(phy_id, PHY_MMD_CTL, MII_WRITE);
	ret = lan78xx_write_reg(dev, MII_ACC, addr);

	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	/* select register of MMD */
	val = mmdidx;
	ret = lan78xx_write_reg(dev, MII_DATA, val);

	phy_id &= dev->mii.phy_id_mask;
	addr = mii_access(phy_id, PHY_MMD_REG_DATA, MII_WRITE);
	ret = lan78xx_write_reg(dev, MII_ACC, addr);

	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	/* select register data for MMD */
	val = PHY_MMD_CTRL_OP_DNI_ | mmddev;
	ret = lan78xx_write_reg(dev, MII_DATA, val);

	phy_id &= dev->mii.phy_id_mask;
	addr = mii_access(phy_id, PHY_MMD_CTL, MII_WRITE);
	ret = lan78xx_write_reg(dev, MII_ACC, addr);

	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	/* set the address, index & direction (read from PHY) */
	phy_id &= dev->mii.phy_id_mask;
	addr = mii_access(phy_id, PHY_MMD_REG_DATA, MII_READ);
	ret = lan78xx_write_reg(dev, MII_ACC, addr);

	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	/* read from MMD */
	ret = lan78xx_read_reg(dev, MII_DATA, &val);

	ret = (int)(val & 0xFFFF);

done:
	mutex_unlock(&dev->phy_mutex);
	usb_autopm_put_interface(dev->intf);
	return ret;
}

static int lan78xx_wait_eeprom(struct lan78xx_net *dev)
static int lan78xx_wait_eeprom(struct lan78xx_net *dev)
{
{
	unsigned long start_time = jiffies;
	unsigned long start_time = jiffies;
@@ -1047,14 +831,14 @@ static int lan78xx_update_flowcontrol(struct lan78xx_net *dev, u8 duplex,


static int lan78xx_link_reset(struct lan78xx_net *dev)
static int lan78xx_link_reset(struct lan78xx_net *dev)
{
{
	struct mii_if_info *mii = &dev->mii;
	struct phy_device *phydev = dev->net->phydev;
	struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
	struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
	int ladv, radv, ret;
	int ladv, radv, ret;
	u32 buf;
	u32 buf;


	/* clear PHY interrupt status */
	/* clear PHY interrupt status */
	/* VTSE PHY */
	/* VTSE PHY */
	ret = lan78xx_mdio_read(dev->net, mii->phy_id, PHY_VTSE_INT_STS);
	ret = phy_read(phydev, PHY_VTSE_INT_STS);
	if (unlikely(ret < 0))
	if (unlikely(ret < 0))
		return -EIO;
		return -EIO;


@@ -1063,7 +847,9 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
	if (unlikely(ret < 0))
	if (unlikely(ret < 0))
		return -EIO;
		return -EIO;


	if (!mii_link_ok(mii) && dev->link_on) {
	phy_read_status(phydev);

	if (!phydev->link && dev->link_on) {
		dev->link_on = false;
		dev->link_on = false;
		netif_carrier_off(dev->net);
		netif_carrier_off(dev->net);


@@ -1075,13 +861,12 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
		ret = lan78xx_write_reg(dev, MAC_CR, buf);
		ret = lan78xx_write_reg(dev, MAC_CR, buf);
		if (unlikely(ret < 0))
		if (unlikely(ret < 0))
			return -EIO;
			return -EIO;
	} else if (mii_link_ok(mii) && !dev->link_on) {
	} else if (phydev->link && !dev->link_on) {
		dev->link_on = true;
		dev->link_on = true;


		mii_check_media(mii, 1, 1);
		phy_ethtool_gset(phydev, &ecmd);
		mii_ethtool_gset(&dev->mii, &ecmd);


		mii->mdio_read(mii->dev, mii->phy_id, PHY_VTSE_INT_STS);
		ret = phy_read(phydev, PHY_VTSE_INT_STS);


		if (dev->udev->speed == USB_SPEED_SUPER) {
		if (dev->udev->speed == USB_SPEED_SUPER) {
			if (ethtool_cmd_speed(&ecmd) == 1000) {
			if (ethtool_cmd_speed(&ecmd) == 1000) {
@@ -1102,11 +887,11 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
			}
			}
		}
		}


		ladv = lan78xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
		ladv = phy_read(phydev, MII_ADVERTISE);
		if (ladv < 0)
		if (ladv < 0)
			return ladv;
			return ladv;


		radv = lan78xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
		radv = phy_read(phydev, MII_LPA);
		if (radv < 0)
		if (radv < 0)
			return radv;
			return radv;


@@ -1279,6 +1064,8 @@ static int lan78xx_set_wol(struct net_device *netdev,


	device_set_wakeup_enable(&dev->udev->dev, (bool)wol->wolopts);
	device_set_wakeup_enable(&dev->udev->dev, (bool)wol->wolopts);


	phy_ethtool_set_wol(netdev->phydev, wol);

	usb_autopm_put_interface(dev->intf);
	usb_autopm_put_interface(dev->intf);


	return ret;
	return ret;
@@ -1287,49 +1074,39 @@ static int lan78xx_set_wol(struct net_device *netdev,
static int lan78xx_get_eee(struct net_device *net, struct ethtool_eee *edata)
static int lan78xx_get_eee(struct net_device *net, struct ethtool_eee *edata)
{
{
	struct lan78xx_net *dev = netdev_priv(net);
	struct lan78xx_net *dev = netdev_priv(net);
	struct phy_device *phydev = net->phydev;
	int ret;
	int ret;
	u32 buf;
	u32 buf;
	u32 adv, lpadv;


	ret = usb_autopm_get_interface(dev->intf);
	ret = usb_autopm_get_interface(dev->intf);
	if (ret < 0)
	if (ret < 0)
		return ret;
		return ret;


	ret = phy_ethtool_get_eee(phydev, edata);
	if (ret < 0)
		goto exit;

	ret = lan78xx_read_reg(dev, MAC_CR, &buf);
	ret = lan78xx_read_reg(dev, MAC_CR, &buf);
	if (buf & MAC_CR_EEE_EN_) {
	if (buf & MAC_CR_EEE_EN_) {
		buf = lan78xx_mmd_read(dev->net, dev->mii.phy_id,
				       PHY_MMD_DEV_7, PHY_EEE_ADVERTISEMENT);
		adv = mmd_eee_adv_to_ethtool_adv_t(buf);
		buf = lan78xx_mmd_read(dev->net, dev->mii.phy_id,
				       PHY_MMD_DEV_7, PHY_EEE_LP_ADVERTISEMENT);
		lpadv = mmd_eee_adv_to_ethtool_adv_t(buf);

		edata->eee_enabled = true;
		edata->eee_enabled = true;
		edata->supported = true;
		edata->eee_active = !!(edata->advertised &
		edata->eee_active = !!(adv & lpadv);
				       edata->lp_advertised);
		edata->advertised = adv;
		edata->lp_advertised = lpadv;
		edata->tx_lpi_enabled = true;
		edata->tx_lpi_enabled = true;
		/* EEE_TX_LPI_REQ_DLY & tx_lpi_timer are same uSec unit */
		/* EEE_TX_LPI_REQ_DLY & tx_lpi_timer are same uSec unit */
		ret = lan78xx_read_reg(dev, EEE_TX_LPI_REQ_DLY, &buf);
		ret = lan78xx_read_reg(dev, EEE_TX_LPI_REQ_DLY, &buf);
		edata->tx_lpi_timer = buf;
		edata->tx_lpi_timer = buf;
	} else {
	} else {
		buf = lan78xx_mmd_read(dev->net, dev->mii.phy_id,
				       PHY_MMD_DEV_7, PHY_EEE_LP_ADVERTISEMENT);
		lpadv = mmd_eee_adv_to_ethtool_adv_t(buf);

		edata->eee_enabled = false;
		edata->eee_enabled = false;
		edata->eee_active = false;
		edata->eee_active = false;
		edata->supported = false;
		edata->advertised = 0;
		edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(lpadv);
		edata->tx_lpi_enabled = false;
		edata->tx_lpi_enabled = false;
		edata->tx_lpi_timer = 0;
		edata->tx_lpi_timer = 0;
	}
	}


	ret = 0;
exit:
	usb_autopm_put_interface(dev->intf);
	usb_autopm_put_interface(dev->intf);


	return 0;
	return ret;
}
}


static int lan78xx_set_eee(struct net_device *net, struct ethtool_eee *edata)
static int lan78xx_set_eee(struct net_device *net, struct ethtool_eee *edata)
@@ -1347,9 +1124,10 @@ static int lan78xx_set_eee(struct net_device *net, struct ethtool_eee *edata)
		buf |= MAC_CR_EEE_EN_;
		buf |= MAC_CR_EEE_EN_;
		ret = lan78xx_write_reg(dev, MAC_CR, buf);
		ret = lan78xx_write_reg(dev, MAC_CR, buf);


		buf = ethtool_adv_to_mmd_eee_adv_t(edata->advertised);
		phy_ethtool_set_eee(net->phydev, edata);
		lan78xx_mmd_write(dev->net, dev->mii.phy_id,

				  PHY_MMD_DEV_7, PHY_EEE_ADVERTISEMENT, buf);
		buf = (u32)edata->tx_lpi_timer;
		ret = lan78xx_write_reg(dev, EEE_TX_LPI_REQ_DLY, buf);
	} else {
	} else {
		ret = lan78xx_read_reg(dev, MAC_CR, &buf);
		ret = lan78xx_read_reg(dev, MAC_CR, &buf);
		buf &= ~MAC_CR_EEE_EN_;
		buf &= ~MAC_CR_EEE_EN_;
@@ -1363,19 +1141,14 @@ static int lan78xx_set_eee(struct net_device *net, struct ethtool_eee *edata)


static u32 lan78xx_get_link(struct net_device *net)
static u32 lan78xx_get_link(struct net_device *net)
{
{
	struct lan78xx_net *dev = netdev_priv(net);
	phy_read_status(net->phydev);


	return mii_link_ok(&dev->mii);
	return net->phydev->link;
}
}


int lan78xx_nway_reset(struct net_device *net)
int lan78xx_nway_reset(struct net_device *net)
{
{
	struct lan78xx_net *dev = netdev_priv(net);
	return phy_start_aneg(net->phydev);

	if ((!dev->mii.mdio_read) || (!dev->mii.mdio_write))
		return -EOPNOTSUPP;

	return mii_nway_restart(&dev->mii);
}
}


static void lan78xx_get_drvinfo(struct net_device *net,
static void lan78xx_get_drvinfo(struct net_device *net,
@@ -1405,24 +1178,19 @@ static void lan78xx_set_msglevel(struct net_device *net, u32 level)
static int lan78xx_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
static int lan78xx_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
{
{
	struct lan78xx_net *dev = netdev_priv(net);
	struct lan78xx_net *dev = netdev_priv(net);
	struct mii_if_info *mii = &dev->mii;
	struct phy_device *phydev = net->phydev;
	int ret;
	int ret;
	int buf;
	int buf;


	if ((!dev->mii.mdio_read) || (!dev->mii.mdio_write))
		return -EOPNOTSUPP;

	ret = usb_autopm_get_interface(dev->intf);
	ret = usb_autopm_get_interface(dev->intf);
	if (ret < 0)
	if (ret < 0)
		return ret;
		return ret;


	ret = mii_ethtool_gset(&dev->mii, cmd);
	ret = phy_ethtool_gset(phydev, cmd);


	mii->mdio_write(mii->dev, mii->phy_id,
	phy_write(phydev, PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_1);
			PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_1);
	buf = phy_read(phydev, PHY_EXT_MODE_CTRL);
	buf = mii->mdio_read(mii->dev, mii->phy_id, PHY_EXT_MODE_CTRL);
	phy_write(phydev, PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_0);
	mii->mdio_write(mii->dev, mii->phy_id,
			PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_0);


	buf &= PHY_EXT_MODE_CTRL_MDIX_MASK_;
	buf &= PHY_EXT_MODE_CTRL_MDIX_MASK_;
	if (buf == PHY_EXT_MODE_CTRL_AUTO_MDIX_) {
	if (buf == PHY_EXT_MODE_CTRL_AUTO_MDIX_) {
@@ -1444,70 +1212,54 @@ static int lan78xx_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
static int lan78xx_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
static int lan78xx_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
{
{
	struct lan78xx_net *dev = netdev_priv(net);
	struct lan78xx_net *dev = netdev_priv(net);
	struct mii_if_info *mii = &dev->mii;
	struct phy_device *phydev = net->phydev;
	int ret = 0;
	int ret = 0;
	int temp;
	int temp;


	if ((!dev->mii.mdio_read) || (!dev->mii.mdio_write))
		return -EOPNOTSUPP;

	ret = usb_autopm_get_interface(dev->intf);
	ret = usb_autopm_get_interface(dev->intf);
	if (ret < 0)
	if (ret < 0)
		return ret;
		return ret;


	if (dev->mdix_ctrl != cmd->eth_tp_mdix_ctrl) {
	if (dev->mdix_ctrl != cmd->eth_tp_mdix_ctrl) {
		if (cmd->eth_tp_mdix_ctrl == ETH_TP_MDI) {
		if (cmd->eth_tp_mdix_ctrl == ETH_TP_MDI) {
			mii->mdio_write(mii->dev, mii->phy_id,
			phy_write(phydev, PHY_EXT_GPIO_PAGE,
					PHY_EXT_GPIO_PAGE,
				  PHY_EXT_GPIO_PAGE_SPACE_1);
				  PHY_EXT_GPIO_PAGE_SPACE_1);
			temp = mii->mdio_read(mii->dev, mii->phy_id,
			temp = phy_read(phydev, PHY_EXT_MODE_CTRL);
					PHY_EXT_MODE_CTRL);
			temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_;
			temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_;
			mii->mdio_write(mii->dev, mii->phy_id,
			phy_write(phydev, PHY_EXT_MODE_CTRL,
					PHY_EXT_MODE_CTRL,
				  temp | PHY_EXT_MODE_CTRL_MDI_);
				  temp | PHY_EXT_MODE_CTRL_MDI_);
			mii->mdio_write(mii->dev, mii->phy_id,
			phy_write(phydev, PHY_EXT_GPIO_PAGE,
					PHY_EXT_GPIO_PAGE,
				  PHY_EXT_GPIO_PAGE_SPACE_0);
				  PHY_EXT_GPIO_PAGE_SPACE_0);
		} else if (cmd->eth_tp_mdix_ctrl == ETH_TP_MDI_X) {
		} else if (cmd->eth_tp_mdix_ctrl == ETH_TP_MDI_X) {
			mii->mdio_write(mii->dev, mii->phy_id,
			phy_write(phydev, PHY_EXT_GPIO_PAGE,
					PHY_EXT_GPIO_PAGE,
				  PHY_EXT_GPIO_PAGE_SPACE_1);
				  PHY_EXT_GPIO_PAGE_SPACE_1);
			temp = mii->mdio_read(mii->dev, mii->phy_id,
			temp = phy_read(phydev, PHY_EXT_MODE_CTRL);
					PHY_EXT_MODE_CTRL);
			temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_;
			temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_;
			mii->mdio_write(mii->dev, mii->phy_id,
			phy_write(phydev, PHY_EXT_MODE_CTRL,
					PHY_EXT_MODE_CTRL,
				  temp | PHY_EXT_MODE_CTRL_MDI_X_);
				  temp | PHY_EXT_MODE_CTRL_MDI_X_);
			mii->mdio_write(mii->dev, mii->phy_id,
			phy_write(phydev, PHY_EXT_GPIO_PAGE,
					PHY_EXT_GPIO_PAGE,
				  PHY_EXT_GPIO_PAGE_SPACE_0);
				  PHY_EXT_GPIO_PAGE_SPACE_0);
		} else if (cmd->eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO) {
		} else if (cmd->eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO) {
			mii->mdio_write(mii->dev, mii->phy_id,
			phy_write(phydev, PHY_EXT_GPIO_PAGE,
					PHY_EXT_GPIO_PAGE,
				  PHY_EXT_GPIO_PAGE_SPACE_1);
				  PHY_EXT_GPIO_PAGE_SPACE_1);
			temp = mii->mdio_read(mii->dev, mii->phy_id,
			temp = phy_read(phydev, PHY_EXT_MODE_CTRL);
							PHY_EXT_MODE_CTRL);
			temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_;
			temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_;
			mii->mdio_write(mii->dev, mii->phy_id,
			phy_write(phydev, PHY_EXT_MODE_CTRL,
					PHY_EXT_MODE_CTRL,
				  temp | PHY_EXT_MODE_CTRL_AUTO_MDIX_);
				  temp | PHY_EXT_MODE_CTRL_AUTO_MDIX_);
			mii->mdio_write(mii->dev, mii->phy_id,
			phy_write(phydev, PHY_EXT_GPIO_PAGE,
					PHY_EXT_GPIO_PAGE,
				  PHY_EXT_GPIO_PAGE_SPACE_0);
				  PHY_EXT_GPIO_PAGE_SPACE_0);
		}
		}
	}
	}


	/* change speed & duplex */
	/* change speed & duplex */
	ret = mii_ethtool_sset(&dev->mii, cmd);
	ret = phy_ethtool_sset(phydev, cmd);


	if (!cmd->autoneg) {
	if (!cmd->autoneg) {
		/* force link down */
		/* force link down */
		temp = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
		temp = phy_read(phydev, MII_BMCR);
		mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR,
		phy_write(phydev, MII_BMCR, temp | BMCR_LOOPBACK);
				temp | BMCR_LOOPBACK);
		mdelay(1);
		mdelay(1);
		mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, temp);
		phy_write(phydev, MII_BMCR, temp);
	}
	}


	usb_autopm_put_interface(dev->intf);
	usb_autopm_put_interface(dev->intf);
@@ -1537,12 +1289,10 @@ static const struct ethtool_ops lan78xx_ethtool_ops = {


static int lan78xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
static int lan78xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
{
	struct lan78xx_net *dev = netdev_priv(netdev);

	if (!netif_running(netdev))
	if (!netif_running(netdev))
		return -EINVAL;
		return -EINVAL;


	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
	return phy_mii_ioctl(netdev->phydev, rq, cmd);
}
}


static void lan78xx_init_mac_address(struct lan78xx_net *dev)
static void lan78xx_init_mac_address(struct lan78xx_net *dev)
@@ -1598,53 +1348,189 @@ static void lan78xx_init_mac_address(struct lan78xx_net *dev)
	ether_addr_copy(dev->net->dev_addr, addr);
	ether_addr_copy(dev->net->dev_addr, addr);
}
}


static void lan78xx_mii_init(struct lan78xx_net *dev)
/* MDIO read and write wrappers for phylib */
static int lan78xx_mdiobus_read(struct mii_bus *bus, int phy_id, int idx)
{
{
	/* Initialize MII structure */
	struct lan78xx_net *dev = bus->priv;
	dev->mii.dev = dev->net;
	u32 val, addr;
	dev->mii.mdio_read = lan78xx_mdio_read;
	int ret;
	dev->mii.mdio_write = lan78xx_mdio_write;

	dev->mii.phy_id_mask = 0x1f;
	ret = usb_autopm_get_interface(dev->intf);
	dev->mii.reg_num_mask = 0x1f;
	if (ret < 0)
	dev->mii.phy_id = INTERNAL_PHY_ID;
		return ret;
	dev->mii.supports_gmii = true;

	mutex_lock(&dev->phy_mutex);

	/* confirm MII not busy */
	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	/* set the address, index & direction (read from PHY) */
	addr = mii_access(phy_id, idx, MII_READ);
	ret = lan78xx_write_reg(dev, MII_ACC, addr);

	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	ret = lan78xx_read_reg(dev, MII_DATA, &val);

	ret = (int)(val & 0xFFFF);

done:
	mutex_unlock(&dev->phy_mutex);
	usb_autopm_put_interface(dev->intf);
	return ret;
}

static int lan78xx_mdiobus_write(struct mii_bus *bus, int phy_id, int idx,
				 u16 regval)
{
	struct lan78xx_net *dev = bus->priv;
	u32 val, addr;
	int ret;

	ret = usb_autopm_get_interface(dev->intf);
	if (ret < 0)
		return ret;

	mutex_lock(&dev->phy_mutex);

	/* confirm MII not busy */
	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

	val = (u32)regval;
	ret = lan78xx_write_reg(dev, MII_DATA, val);

	/* set the address, index & direction (write to PHY) */
	addr = mii_access(phy_id, idx, MII_WRITE);
	ret = lan78xx_write_reg(dev, MII_ACC, addr);

	ret = lan78xx_phy_wait_not_busy(dev);
	if (ret < 0)
		goto done;

done:
	mutex_unlock(&dev->phy_mutex);
	usb_autopm_put_interface(dev->intf);
	return 0;
}

static int lan78xx_mdio_init(struct lan78xx_net *dev)
{
	int ret;
	int i;

	dev->mdiobus = mdiobus_alloc();
	if (!dev->mdiobus) {
		netdev_err(dev->net, "can't allocate MDIO bus\n");
		return -ENOMEM;
	}

	dev->mdiobus->priv = (void *)dev;
	dev->mdiobus->read = lan78xx_mdiobus_read;
	dev->mdiobus->write = lan78xx_mdiobus_write;
	dev->mdiobus->name = "lan78xx-mdiobus";

	snprintf(dev->mdiobus->id, MII_BUS_ID_SIZE, "usb-%03d:%03d",
		 dev->udev->bus->busnum, dev->udev->devnum);

	dev->mdiobus->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
	if (!dev->mdiobus->irq) {
		ret = -ENOMEM;
		goto exit1;
	}

	/* handle our own interrupt */
	for (i = 0; i < PHY_MAX_ADDR; i++)
		dev->mdiobus->irq[i] = PHY_IGNORE_INTERRUPT;

	switch (dev->devid & ID_REV_CHIP_ID_MASK_) {
	case 0x78000000:
	case 0x78500000:
		/* set to internal PHY id */
		dev->mdiobus->phy_mask = ~(1 << 1);
		break;
	}

	ret = mdiobus_register(dev->mdiobus);
	if (ret) {
		netdev_err(dev->net, "can't register MDIO bus\n");
		goto exit2;
	}

	netdev_dbg(dev->net, "registered mdiobus bus %s\n", dev->mdiobus->id);
	return 0;
exit2:
	kfree(dev->mdiobus->irq);
exit1:
	mdiobus_free(dev->mdiobus);
	return ret;
}

static void lan78xx_remove_mdio(struct lan78xx_net *dev)
{
	mdiobus_unregister(dev->mdiobus);
	kfree(dev->mdiobus->irq);
	mdiobus_free(dev->mdiobus);
}

static void lan78xx_link_status_change(struct net_device *net)
{
	/* nothing to do */
}
}


static int lan78xx_phy_init(struct lan78xx_net *dev)
static int lan78xx_phy_init(struct lan78xx_net *dev)
{
{
	int temp;
	int ret;
	struct mii_if_info *mii = &dev->mii;
	struct phy_device *phydev = dev->net->phydev;


	if ((!mii->mdio_write) || (!mii->mdio_read))
	phydev = phy_find_first(dev->mdiobus);
		return -EOPNOTSUPP;
	if (!phydev) {
		netdev_err(dev->net, "no PHY found\n");
		return -EIO;
	}


	temp = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
	ret = phy_connect_direct(dev->net, phydev,
	temp |= ADVERTISE_ALL;
				 lan78xx_link_status_change,
	mii->mdio_write(mii->dev, mii->phy_id, MII_ADVERTISE,
				 PHY_INTERFACE_MODE_GMII);
			temp | ADVERTISE_CSMA |
	if (ret) {
			ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
		netdev_err(dev->net, "can't attach PHY to %s\n",
			   dev->mdiobus->id);
		return -EIO;
	}


	/* set to AUTOMDIX */
	/* set to AUTOMDIX */
	mii->mdio_write(mii->dev, mii->phy_id,
	phy_write(phydev, PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_1);
			PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_1);
	ret = phy_read(phydev, PHY_EXT_MODE_CTRL);
	temp = mii->mdio_read(mii->dev, mii->phy_id, PHY_EXT_MODE_CTRL);
	ret &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_;
	temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_;
	phy_write(phydev, PHY_EXT_MODE_CTRL,
	mii->mdio_write(mii->dev, mii->phy_id, PHY_EXT_MODE_CTRL,
		  ret | PHY_EXT_MODE_CTRL_AUTO_MDIX_);
			temp | PHY_EXT_MODE_CTRL_AUTO_MDIX_);
	phy_write(phydev, PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_0);
	mii->mdio_write(mii->dev, mii->phy_id,
			PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_0);
	dev->mdix_ctrl = ETH_TP_MDI_AUTO;
	dev->mdix_ctrl = ETH_TP_MDI_AUTO;


	/* MAC doesn't support 1000HD */
	/* MAC doesn't support 1000T Half */
	temp = mii->mdio_read(mii->dev, mii->phy_id, MII_CTRL1000);
	phydev->supported &= ~SUPPORTED_1000baseT_Half;
	mii->mdio_write(mii->dev, mii->phy_id, MII_CTRL1000,
	phydev->supported |= (SUPPORTED_10baseT_Half |
			temp & ~ADVERTISE_1000HALF);
			      SUPPORTED_10baseT_Full |

			      SUPPORTED_100baseT_Half |
	/* clear interrupt */
			      SUPPORTED_100baseT_Full |
	mii->mdio_read(mii->dev, mii->phy_id, PHY_VTSE_INT_STS);
			      SUPPORTED_1000baseT_Full |
	mii->mdio_write(mii->dev, mii->phy_id, PHY_VTSE_INT_MASK,
			      SUPPORTED_Pause | SUPPORTED_Asym_Pause);
			PHY_VTSE_INT_MASK_MDINTPIN_EN_ |
	genphy_config_aneg(phydev);
			PHY_VTSE_INT_MASK_LINK_CHANGE_);

	/* Workaround to enable PHY interrupt.
	 * phy_start_interrupts() is API for requesting and enabling
	 * PHY interrupt. However, USB-to-Ethernet device can't use
	 * request_irq() called in phy_start_interrupts().
	 * Set PHY to PHY_HALTED and call phy_start()
	 * to make a call to phy_enable_interrupts()
	 */
	phy_stop(phydev);
	phy_start(phydev);


	netif_dbg(dev, ifup, dev->net, "phy initialised successfully");
	netif_dbg(dev, ifup, dev->net, "phy initialised successfully");


@@ -1930,6 +1816,10 @@ static int lan78xx_reset(struct lan78xx_net *dev)


	lan78xx_init_mac_address(dev);
	lan78xx_init_mac_address(dev);


	/* save DEVID for later usage */
	ret = lan78xx_read_reg(dev, ID_REV, &buf);
	dev->devid = buf;

	/* Respond to the IN token with a NAK */
	/* Respond to the IN token with a NAK */
	ret = lan78xx_read_reg(dev, USB_CFG0, &buf);
	ret = lan78xx_read_reg(dev, USB_CFG0, &buf);
	buf |= USB_CFG_BIR_;
	buf |= USB_CFG_BIR_;
@@ -2004,10 +1894,6 @@ static int lan78xx_reset(struct lan78xx_net *dev)
		}
		}
	} while ((buf & PMT_CTL_PHY_RST_) || !(buf & PMT_CTL_READY_));
	} while ((buf & PMT_CTL_PHY_RST_) || !(buf & PMT_CTL_READY_));


	lan78xx_mii_init(dev);

	ret = lan78xx_phy_init(dev);

	ret = lan78xx_read_reg(dev, MAC_CR, &buf);
	ret = lan78xx_read_reg(dev, MAC_CR, &buf);


	buf |= MAC_CR_GMII_EN_;
	buf |= MAC_CR_GMII_EN_;
@@ -2015,10 +1901,6 @@ static int lan78xx_reset(struct lan78xx_net *dev)


	ret = lan78xx_write_reg(dev, MAC_CR, buf);
	ret = lan78xx_write_reg(dev, MAC_CR, buf);


	/* enable on PHY */
	if (buf & MAC_CR_EEE_EN_)
		lan78xx_mmd_write(dev->net, dev->mii.phy_id, 0x07, 0x3C, 0x06);

	/* enable PHY interrupts */
	/* enable PHY interrupts */
	ret = lan78xx_read_reg(dev, INT_EP_CTL, &buf);
	ret = lan78xx_read_reg(dev, INT_EP_CTL, &buf);
	buf |= INT_ENP_PHY_INT;
	buf |= INT_ENP_PHY_INT;
@@ -2042,9 +1924,6 @@ static int lan78xx_reset(struct lan78xx_net *dev)
	buf |= FCT_RX_CTL_EN_;
	buf |= FCT_RX_CTL_EN_;
	ret = lan78xx_write_reg(dev, FCT_RX_CTL, buf);
	ret = lan78xx_write_reg(dev, FCT_RX_CTL, buf);


	if (!mii_nway_restart(&dev->mii))
		netif_dbg(dev, link, dev->net, "autoneg initiated");

	return 0;
	return 0;
}
}


@@ -2061,6 +1940,10 @@ static int lan78xx_open(struct net_device *net)
	if (ret < 0)
	if (ret < 0)
		goto done;
		goto done;


	ret = lan78xx_phy_init(dev);
	if (ret < 0)
		goto done;

	/* for Link Check */
	/* for Link Check */
	if (dev->urb_intr) {
	if (dev->urb_intr) {
		ret = usb_submit_urb(dev->urb_intr, GFP_KERNEL);
		ret = usb_submit_urb(dev->urb_intr, GFP_KERNEL);
@@ -2115,6 +1998,10 @@ int lan78xx_stop(struct net_device *net)
{
{
	struct lan78xx_net		*dev = netdev_priv(net);
	struct lan78xx_net		*dev = netdev_priv(net);


	phy_stop(net->phydev);
	phy_disconnect(net->phydev);
	net->phydev = NULL;

	clear_bit(EVENT_DEV_OPEN, &dev->flags);
	clear_bit(EVENT_DEV_OPEN, &dev->flags);
	netif_stop_queue(net);
	netif_stop_queue(net);


@@ -2395,6 +2282,8 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf)
	/* Init all registers */
	/* Init all registers */
	ret = lan78xx_reset(dev);
	ret = lan78xx_reset(dev);


	lan78xx_mdio_init(dev);

	dev->net->flags |= IFF_MULTICAST;
	dev->net->flags |= IFF_MULTICAST;


	pdata->wol = WAKE_MAGIC;
	pdata->wol = WAKE_MAGIC;
@@ -2406,6 +2295,8 @@ static void lan78xx_unbind(struct lan78xx_net *dev, struct usb_interface *intf)
{
{
	struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]);
	struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]);


	lan78xx_remove_mdio(dev);

	if (pdata) {
	if (pdata) {
		netif_dbg(dev, ifdown, dev->net, "free pdata");
		netif_dbg(dev, ifdown, dev->net, "free pdata");
		kfree(pdata);
		kfree(pdata);
@@ -3459,6 +3350,9 @@ int lan78xx_reset_resume(struct usb_interface *intf)
	struct lan78xx_net *dev = usb_get_intfdata(intf);
	struct lan78xx_net *dev = usb_get_intfdata(intf);


	lan78xx_reset(dev);
	lan78xx_reset(dev);

	lan78xx_phy_init(dev);

	return lan78xx_resume(intf);
	return lan78xx_resume(intf);
}
}