mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
lan78xx: Update to use phylib instead of mii_if_info.
Update to use phylib instead of mii_if_info. Signed-off-by: Woojung Huh <woojung.huh@microchip.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
05fe68c008
commit
ce85e13ad6
1 changed files with 255 additions and 361 deletions
|
@ -19,7 +19,6 @@
|
|||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/signal.h>
|
||||
|
@ -36,7 +35,7 @@
|
|||
#define DRIVER_AUTHOR "WOOJUNG HUH <woojung.huh@microchip.com>"
|
||||
#define DRIVER_DESC "LAN78XX USB 3.0 Gigabit Ethernet Devices"
|
||||
#define DRIVER_NAME "lan78xx"
|
||||
#define DRIVER_VERSION "1.0.0"
|
||||
#define DRIVER_VERSION "1.0.1"
|
||||
|
||||
#define TX_TIMEOUT_JIFFIES (5 * HZ)
|
||||
#define THROTTLE_JIFFIES (HZ / 8)
|
||||
|
@ -57,7 +56,6 @@
|
|||
#define DEFAULT_RX_CSUM_ENABLE (true)
|
||||
#define DEFAULT_TSO_CSUM_ENABLE (true)
|
||||
#define DEFAULT_VLAN_FILTER_ENABLE (true)
|
||||
#define INTERNAL_PHY_ID (2) /* 2: GMII */
|
||||
#define TX_OVERHEAD (8)
|
||||
#define RXW_PADDING 2
|
||||
|
||||
|
@ -275,10 +273,12 @@ struct lan78xx_net {
|
|||
struct timer_list delay;
|
||||
|
||||
unsigned long data[5];
|
||||
struct mii_if_info mii;
|
||||
|
||||
int link_on;
|
||||
u8 mdix_ctrl;
|
||||
|
||||
u32 devid;
|
||||
struct mii_bus *mdiobus;
|
||||
};
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct mii_if_info *mii = &dev->mii;
|
||||
struct phy_device *phydev = dev->net->phydev;
|
||||
struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
|
||||
int ladv, radv, ret;
|
||||
u32 buf;
|
||||
|
||||
/* clear PHY interrupt status */
|
||||
/* 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))
|
||||
return -EIO;
|
||||
|
||||
|
@ -1063,7 +847,9 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
|
|||
if (unlikely(ret < 0))
|
||||
return -EIO;
|
||||
|
||||
if (!mii_link_ok(mii) && dev->link_on) {
|
||||
phy_read_status(phydev);
|
||||
|
||||
if (!phydev->link && dev->link_on) {
|
||||
dev->link_on = false;
|
||||
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);
|
||||
if (unlikely(ret < 0))
|
||||
return -EIO;
|
||||
} else if (mii_link_ok(mii) && !dev->link_on) {
|
||||
} else if (phydev->link && !dev->link_on) {
|
||||
dev->link_on = true;
|
||||
|
||||
mii_check_media(mii, 1, 1);
|
||||
mii_ethtool_gset(&dev->mii, &ecmd);
|
||||
phy_ethtool_gset(phydev, &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 (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)
|
||||
return ladv;
|
||||
|
||||
radv = lan78xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
|
||||
radv = phy_read(phydev, MII_LPA);
|
||||
if (radv < 0)
|
||||
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);
|
||||
|
||||
phy_ethtool_set_wol(netdev->phydev, wol);
|
||||
|
||||
usb_autopm_put_interface(dev->intf);
|
||||
|
||||
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)
|
||||
{
|
||||
struct lan78xx_net *dev = netdev_priv(net);
|
||||
struct phy_device *phydev = net->phydev;
|
||||
int ret;
|
||||
u32 buf;
|
||||
u32 adv, lpadv;
|
||||
|
||||
ret = usb_autopm_get_interface(dev->intf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = phy_ethtool_get_eee(phydev, edata);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
ret = lan78xx_read_reg(dev, MAC_CR, &buf);
|
||||
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->supported = true;
|
||||
edata->eee_active = !!(adv & lpadv);
|
||||
edata->advertised = adv;
|
||||
edata->lp_advertised = lpadv;
|
||||
edata->eee_active = !!(edata->advertised &
|
||||
edata->lp_advertised);
|
||||
edata->tx_lpi_enabled = true;
|
||||
/* EEE_TX_LPI_REQ_DLY & tx_lpi_timer are same uSec unit */
|
||||
ret = lan78xx_read_reg(dev, EEE_TX_LPI_REQ_DLY, &buf);
|
||||
edata->tx_lpi_timer = buf;
|
||||
} 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_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_timer = 0;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
exit:
|
||||
usb_autopm_put_interface(dev->intf);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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_;
|
||||
ret = lan78xx_write_reg(dev, MAC_CR, buf);
|
||||
|
||||
buf = ethtool_adv_to_mmd_eee_adv_t(edata->advertised);
|
||||
lan78xx_mmd_write(dev->net, dev->mii.phy_id,
|
||||
PHY_MMD_DEV_7, PHY_EEE_ADVERTISEMENT, buf);
|
||||
phy_ethtool_set_eee(net->phydev, edata);
|
||||
|
||||
buf = (u32)edata->tx_lpi_timer;
|
||||
ret = lan78xx_write_reg(dev, EEE_TX_LPI_REQ_DLY, buf);
|
||||
} else {
|
||||
ret = lan78xx_read_reg(dev, MAC_CR, &buf);
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct lan78xx_net *dev = netdev_priv(net);
|
||||
|
||||
if ((!dev->mii.mdio_read) || (!dev->mii.mdio_write))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return mii_nway_restart(&dev->mii);
|
||||
return phy_start_aneg(net->phydev);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct lan78xx_net *dev = netdev_priv(net);
|
||||
struct mii_if_info *mii = &dev->mii;
|
||||
struct phy_device *phydev = net->phydev;
|
||||
int ret;
|
||||
int buf;
|
||||
|
||||
if ((!dev->mii.mdio_read) || (!dev->mii.mdio_write))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = usb_autopm_get_interface(dev->intf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mii_ethtool_gset(&dev->mii, cmd);
|
||||
ret = phy_ethtool_gset(phydev, cmd);
|
||||
|
||||
mii->mdio_write(mii->dev, mii->phy_id,
|
||||
PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_1);
|
||||
buf = mii->mdio_read(mii->dev, mii->phy_id, PHY_EXT_MODE_CTRL);
|
||||
mii->mdio_write(mii->dev, mii->phy_id,
|
||||
PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_0);
|
||||
phy_write(phydev, PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_1);
|
||||
buf = phy_read(phydev, PHY_EXT_MODE_CTRL);
|
||||
phy_write(phydev, PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_0);
|
||||
|
||||
buf &= PHY_EXT_MODE_CTRL_MDIX_MASK_;
|
||||
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)
|
||||
{
|
||||
struct lan78xx_net *dev = netdev_priv(net);
|
||||
struct mii_if_info *mii = &dev->mii;
|
||||
struct phy_device *phydev = net->phydev;
|
||||
int ret = 0;
|
||||
int temp;
|
||||
|
||||
if ((!dev->mii.mdio_read) || (!dev->mii.mdio_write))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = usb_autopm_get_interface(dev->intf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (dev->mdix_ctrl != cmd->eth_tp_mdix_ctrl) {
|
||||
if (cmd->eth_tp_mdix_ctrl == ETH_TP_MDI) {
|
||||
mii->mdio_write(mii->dev, mii->phy_id,
|
||||
PHY_EXT_GPIO_PAGE,
|
||||
PHY_EXT_GPIO_PAGE_SPACE_1);
|
||||
temp = mii->mdio_read(mii->dev, mii->phy_id,
|
||||
PHY_EXT_MODE_CTRL);
|
||||
phy_write(phydev, PHY_EXT_GPIO_PAGE,
|
||||
PHY_EXT_GPIO_PAGE_SPACE_1);
|
||||
temp = phy_read(phydev, PHY_EXT_MODE_CTRL);
|
||||
temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_;
|
||||
mii->mdio_write(mii->dev, mii->phy_id,
|
||||
PHY_EXT_MODE_CTRL,
|
||||
temp | PHY_EXT_MODE_CTRL_MDI_);
|
||||
mii->mdio_write(mii->dev, mii->phy_id,
|
||||
PHY_EXT_GPIO_PAGE,
|
||||
PHY_EXT_GPIO_PAGE_SPACE_0);
|
||||
phy_write(phydev, PHY_EXT_MODE_CTRL,
|
||||
temp | PHY_EXT_MODE_CTRL_MDI_);
|
||||
phy_write(phydev, PHY_EXT_GPIO_PAGE,
|
||||
PHY_EXT_GPIO_PAGE_SPACE_0);
|
||||
} else if (cmd->eth_tp_mdix_ctrl == ETH_TP_MDI_X) {
|
||||
mii->mdio_write(mii->dev, mii->phy_id,
|
||||
PHY_EXT_GPIO_PAGE,
|
||||
PHY_EXT_GPIO_PAGE_SPACE_1);
|
||||
temp = mii->mdio_read(mii->dev, mii->phy_id,
|
||||
PHY_EXT_MODE_CTRL);
|
||||
phy_write(phydev, PHY_EXT_GPIO_PAGE,
|
||||
PHY_EXT_GPIO_PAGE_SPACE_1);
|
||||
temp = phy_read(phydev, PHY_EXT_MODE_CTRL);
|
||||
temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_;
|
||||
mii->mdio_write(mii->dev, mii->phy_id,
|
||||
PHY_EXT_MODE_CTRL,
|
||||
temp | PHY_EXT_MODE_CTRL_MDI_X_);
|
||||
mii->mdio_write(mii->dev, mii->phy_id,
|
||||
PHY_EXT_GPIO_PAGE,
|
||||
PHY_EXT_GPIO_PAGE_SPACE_0);
|
||||
phy_write(phydev, PHY_EXT_MODE_CTRL,
|
||||
temp | PHY_EXT_MODE_CTRL_MDI_X_);
|
||||
phy_write(phydev, PHY_EXT_GPIO_PAGE,
|
||||
PHY_EXT_GPIO_PAGE_SPACE_0);
|
||||
} else if (cmd->eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO) {
|
||||
mii->mdio_write(mii->dev, mii->phy_id,
|
||||
PHY_EXT_GPIO_PAGE,
|
||||
PHY_EXT_GPIO_PAGE_SPACE_1);
|
||||
temp = mii->mdio_read(mii->dev, mii->phy_id,
|
||||
PHY_EXT_MODE_CTRL);
|
||||
phy_write(phydev, PHY_EXT_GPIO_PAGE,
|
||||
PHY_EXT_GPIO_PAGE_SPACE_1);
|
||||
temp = phy_read(phydev, PHY_EXT_MODE_CTRL);
|
||||
temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_;
|
||||
mii->mdio_write(mii->dev, mii->phy_id,
|
||||
PHY_EXT_MODE_CTRL,
|
||||
temp | PHY_EXT_MODE_CTRL_AUTO_MDIX_);
|
||||
mii->mdio_write(mii->dev, mii->phy_id,
|
||||
PHY_EXT_GPIO_PAGE,
|
||||
PHY_EXT_GPIO_PAGE_SPACE_0);
|
||||
phy_write(phydev, PHY_EXT_MODE_CTRL,
|
||||
temp | PHY_EXT_MODE_CTRL_AUTO_MDIX_);
|
||||
phy_write(phydev, PHY_EXT_GPIO_PAGE,
|
||||
PHY_EXT_GPIO_PAGE_SPACE_0);
|
||||
}
|
||||
}
|
||||
|
||||
/* change speed & duplex */
|
||||
ret = mii_ethtool_sset(&dev->mii, cmd);
|
||||
ret = phy_ethtool_sset(phydev, cmd);
|
||||
|
||||
if (!cmd->autoneg) {
|
||||
/* force link down */
|
||||
temp = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
|
||||
mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR,
|
||||
temp | BMCR_LOOPBACK);
|
||||
temp = phy_read(phydev, MII_BMCR);
|
||||
phy_write(phydev, MII_BMCR, temp | BMCR_LOOPBACK);
|
||||
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);
|
||||
|
@ -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)
|
||||
{
|
||||
struct lan78xx_net *dev = netdev_priv(netdev);
|
||||
|
||||
if (!netif_running(netdev))
|
||||
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)
|
||||
|
@ -1598,53 +1348,189 @@ static void lan78xx_init_mac_address(struct lan78xx_net *dev)
|
|||
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 */
|
||||
dev->mii.dev = dev->net;
|
||||
dev->mii.mdio_read = lan78xx_mdio_read;
|
||||
dev->mii.mdio_write = lan78xx_mdio_write;
|
||||
dev->mii.phy_id_mask = 0x1f;
|
||||
dev->mii.reg_num_mask = 0x1f;
|
||||
dev->mii.phy_id = INTERNAL_PHY_ID;
|
||||
dev->mii.supports_gmii = true;
|
||||
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;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
int temp;
|
||||
struct mii_if_info *mii = &dev->mii;
|
||||
int ret;
|
||||
struct phy_device *phydev = dev->net->phydev;
|
||||
|
||||
if ((!mii->mdio_write) || (!mii->mdio_read))
|
||||
return -EOPNOTSUPP;
|
||||
phydev = phy_find_first(dev->mdiobus);
|
||||
if (!phydev) {
|
||||
netdev_err(dev->net, "no PHY found\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
temp = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
|
||||
temp |= ADVERTISE_ALL;
|
||||
mii->mdio_write(mii->dev, mii->phy_id, MII_ADVERTISE,
|
||||
temp | ADVERTISE_CSMA |
|
||||
ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
|
||||
ret = phy_connect_direct(dev->net, phydev,
|
||||
lan78xx_link_status_change,
|
||||
PHY_INTERFACE_MODE_GMII);
|
||||
if (ret) {
|
||||
netdev_err(dev->net, "can't attach PHY to %s\n",
|
||||
dev->mdiobus->id);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* set to AUTOMDIX */
|
||||
mii->mdio_write(mii->dev, mii->phy_id,
|
||||
PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_1);
|
||||
temp = mii->mdio_read(mii->dev, mii->phy_id, PHY_EXT_MODE_CTRL);
|
||||
temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_;
|
||||
mii->mdio_write(mii->dev, mii->phy_id, PHY_EXT_MODE_CTRL,
|
||||
temp | PHY_EXT_MODE_CTRL_AUTO_MDIX_);
|
||||
mii->mdio_write(mii->dev, mii->phy_id,
|
||||
PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_0);
|
||||
phy_write(phydev, PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_1);
|
||||
ret = phy_read(phydev, PHY_EXT_MODE_CTRL);
|
||||
ret &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_;
|
||||
phy_write(phydev, PHY_EXT_MODE_CTRL,
|
||||
ret | PHY_EXT_MODE_CTRL_AUTO_MDIX_);
|
||||
phy_write(phydev, PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_0);
|
||||
dev->mdix_ctrl = ETH_TP_MDI_AUTO;
|
||||
|
||||
/* MAC doesn't support 1000HD */
|
||||
temp = mii->mdio_read(mii->dev, mii->phy_id, MII_CTRL1000);
|
||||
mii->mdio_write(mii->dev, mii->phy_id, MII_CTRL1000,
|
||||
temp & ~ADVERTISE_1000HALF);
|
||||
/* MAC doesn't support 1000T Half */
|
||||
phydev->supported &= ~SUPPORTED_1000baseT_Half;
|
||||
phydev->supported |= (SUPPORTED_10baseT_Half |
|
||||
SUPPORTED_10baseT_Full |
|
||||
SUPPORTED_100baseT_Half |
|
||||
SUPPORTED_100baseT_Full |
|
||||
SUPPORTED_1000baseT_Full |
|
||||
SUPPORTED_Pause | SUPPORTED_Asym_Pause);
|
||||
genphy_config_aneg(phydev);
|
||||
|
||||
/* clear interrupt */
|
||||
mii->mdio_read(mii->dev, mii->phy_id, PHY_VTSE_INT_STS);
|
||||
mii->mdio_write(mii->dev, mii->phy_id, PHY_VTSE_INT_MASK,
|
||||
PHY_VTSE_INT_MASK_MDINTPIN_EN_ |
|
||||
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");
|
||||
|
||||
|
@ -1930,6 +1816,10 @@ static int lan78xx_reset(struct lan78xx_net *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 */
|
||||
ret = lan78xx_read_reg(dev, USB_CFG0, &buf);
|
||||
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_));
|
||||
|
||||
lan78xx_mii_init(dev);
|
||||
|
||||
ret = lan78xx_phy_init(dev);
|
||||
|
||||
ret = lan78xx_read_reg(dev, MAC_CR, &buf);
|
||||
|
||||
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);
|
||||
|
||||
/* enable on PHY */
|
||||
if (buf & MAC_CR_EEE_EN_)
|
||||
lan78xx_mmd_write(dev->net, dev->mii.phy_id, 0x07, 0x3C, 0x06);
|
||||
|
||||
/* enable PHY interrupts */
|
||||
ret = lan78xx_read_reg(dev, INT_EP_CTL, &buf);
|
||||
buf |= INT_ENP_PHY_INT;
|
||||
|
@ -2042,9 +1924,6 @@ static int lan78xx_reset(struct lan78xx_net *dev)
|
|||
buf |= FCT_RX_CTL_EN_;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2061,6 +1940,10 @@ static int lan78xx_open(struct net_device *net)
|
|||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
ret = lan78xx_phy_init(dev);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
/* for Link Check */
|
||||
if (dev->urb_intr) {
|
||||
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);
|
||||
|
||||
phy_stop(net->phydev);
|
||||
phy_disconnect(net->phydev);
|
||||
net->phydev = NULL;
|
||||
|
||||
clear_bit(EVENT_DEV_OPEN, &dev->flags);
|
||||
netif_stop_queue(net);
|
||||
|
||||
|
@ -2395,6 +2282,8 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf)
|
|||
/* Init all registers */
|
||||
ret = lan78xx_reset(dev);
|
||||
|
||||
lan78xx_mdio_init(dev);
|
||||
|
||||
dev->net->flags |= IFF_MULTICAST;
|
||||
|
||||
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]);
|
||||
|
||||
lan78xx_remove_mdio(dev);
|
||||
|
||||
if (pdata) {
|
||||
netif_dbg(dev, ifdown, dev->net, "free pdata");
|
||||
kfree(pdata);
|
||||
|
@ -3459,6 +3350,9 @@ int lan78xx_reset_resume(struct usb_interface *intf)
|
|||
struct lan78xx_net *dev = usb_get_intfdata(intf);
|
||||
|
||||
lan78xx_reset(dev);
|
||||
|
||||
lan78xx_phy_init(dev);
|
||||
|
||||
return lan78xx_resume(intf);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue