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

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
...@@ -19,7 +19,6 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 = { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment