Merge branch 'ax88772-phylib'
Oleksij Rempel says: ==================== port asix ax88772 to the PHYlib changes v2: - add Reviewed-by: Andrew Lunn <andrew@lunn.ch> to some patches - refactor asix_read_phy_addr() and add error handling for all callers - refactor asix_mdio_bus_read() Port ax88772 part of asix driver to the phylib to be able to use more advanced external PHY attached to this controller. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
8c3f3362cd
@ -10,6 +10,8 @@
|
||||
#include <linux/mii.h>
|
||||
#include <linux/phy.h>
|
||||
|
||||
#define PHY_ID_ASIX_AX88772A 0x003b1861
|
||||
#define PHY_ID_ASIX_AX88772C 0x003b1881
|
||||
#define PHY_ID_ASIX_AX88796B 0x003b1841
|
||||
|
||||
MODULE_DESCRIPTION("Asix PHY driver");
|
||||
@ -39,7 +41,75 @@ static int asix_soft_reset(struct phy_device *phydev)
|
||||
return genphy_soft_reset(phydev);
|
||||
}
|
||||
|
||||
static struct phy_driver asix_driver[] = { {
|
||||
/* AX88772A is not working properly with some old switches (NETGEAR EN 108TP):
|
||||
* after autoneg is done and the link status is reported as active, the MII_LPA
|
||||
* register is 0. This issue is not reproducible on AX88772C.
|
||||
*/
|
||||
static int asix_ax88772a_read_status(struct phy_device *phydev)
|
||||
{
|
||||
int ret, val;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!phydev->link)
|
||||
return 0;
|
||||
|
||||
/* If MII_LPA is 0, phy_resolve_aneg_linkmode() will fail to resolve
|
||||
* linkmode so use MII_BMCR as default values.
|
||||
*/
|
||||
val = phy_read(phydev, MII_BMCR);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if (val & BMCR_SPEED100)
|
||||
phydev->speed = SPEED_100;
|
||||
else
|
||||
phydev->speed = SPEED_10;
|
||||
|
||||
if (val & BMCR_FULLDPLX)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
ret = genphy_read_lpa(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
|
||||
phy_resolve_aneg_linkmode(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void asix_ax88772a_link_change_notify(struct phy_device *phydev)
|
||||
{
|
||||
/* Reset PHY, otherwise MII_LPA will provide outdated information.
|
||||
* This issue is reproducible only with some link partner PHYs
|
||||
*/
|
||||
if (phydev->state == PHY_NOLINK && phydev->drv->soft_reset)
|
||||
phydev->drv->soft_reset(phydev);
|
||||
}
|
||||
|
||||
static struct phy_driver asix_driver[] = {
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772A),
|
||||
.name = "Asix Electronics AX88772A",
|
||||
.flags = PHY_IS_INTERNAL,
|
||||
.read_status = asix_ax88772a_read_status,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = genphy_resume,
|
||||
.soft_reset = asix_soft_reset,
|
||||
.link_change_notify = asix_ax88772a_link_change_notify,
|
||||
}, {
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772C),
|
||||
.name = "Asix Electronics AX88772C",
|
||||
.flags = PHY_IS_INTERNAL,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = genphy_resume,
|
||||
.soft_reset = asix_soft_reset,
|
||||
}, {
|
||||
.phy_id = PHY_ID_ASIX_AX88796B,
|
||||
.name = "Asix Electronics AX88796B",
|
||||
.phy_id_mask = 0xfffffff0,
|
||||
@ -50,6 +120,8 @@ static struct phy_driver asix_driver[] = { {
|
||||
module_phy_driver(asix_driver);
|
||||
|
||||
static struct mdio_device_id __maybe_unused asix_tbl[] = {
|
||||
{ PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772A) },
|
||||
{ PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772C) },
|
||||
{ PHY_ID_ASIX_AX88796B, 0xfffffff0 },
|
||||
{ }
|
||||
};
|
||||
|
@ -1136,6 +1136,9 @@ void phy_state_machine(struct work_struct *work)
|
||||
else if (do_suspend)
|
||||
phy_suspend(phydev);
|
||||
|
||||
if (err == -ENODEV)
|
||||
return;
|
||||
|
||||
if (err < 0)
|
||||
phy_error(phydev);
|
||||
|
||||
|
@ -164,6 +164,8 @@ config USB_NET_AX8817X
|
||||
depends on USB_USBNET
|
||||
select CRC32
|
||||
select PHYLIB
|
||||
select AX88796B_PHY
|
||||
imply NET_SELFTESTS
|
||||
default y
|
||||
help
|
||||
This option adds support for ASIX AX88xxx based USB 2.0
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include <linux/usb/usbnet.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/phy.h>
|
||||
#include <net/selftests.h>
|
||||
|
||||
#define DRIVER_VERSION "22-Dec-2011"
|
||||
#define DRIVER_NAME "asix"
|
||||
@ -178,6 +180,10 @@ struct asix_common_private {
|
||||
u16 presvd_phy_advertise;
|
||||
u16 presvd_phy_bmcr;
|
||||
struct asix_rx_fixup_info rx_fixup_info;
|
||||
struct mii_bus *mdio;
|
||||
struct phy_device *phydev;
|
||||
u16 phy_addr;
|
||||
char phy_name[20];
|
||||
};
|
||||
|
||||
extern const struct driver_info ax88172a_info;
|
||||
@ -205,8 +211,7 @@ struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
|
||||
int asix_set_sw_mii(struct usbnet *dev, int in_pm);
|
||||
int asix_set_hw_mii(struct usbnet *dev, int in_pm);
|
||||
|
||||
int asix_read_phy_addr(struct usbnet *dev, int internal);
|
||||
int asix_get_phy_addr(struct usbnet *dev);
|
||||
int asix_read_phy_addr(struct usbnet *dev, bool internal);
|
||||
|
||||
int asix_sw_reset(struct usbnet *dev, u8 flags, int in_pm);
|
||||
|
||||
@ -215,6 +220,7 @@ int asix_write_rx_ctl(struct usbnet *dev, u16 mode, int in_pm);
|
||||
|
||||
u16 asix_read_medium_status(struct usbnet *dev, int in_pm);
|
||||
int asix_write_medium_mode(struct usbnet *dev, u16 mode, int in_pm);
|
||||
void asix_adjust_link(struct net_device *netdev);
|
||||
|
||||
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm);
|
||||
|
||||
@ -223,6 +229,9 @@ void asix_set_multicast(struct net_device *net);
|
||||
int asix_mdio_read(struct net_device *netdev, int phy_id, int loc);
|
||||
void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val);
|
||||
|
||||
int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum);
|
||||
int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val);
|
||||
|
||||
int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc);
|
||||
void asix_mdio_write_nopm(struct net_device *netdev, int phy_id, int loc,
|
||||
int val);
|
||||
|
@ -288,33 +288,34 @@ int asix_set_hw_mii(struct usbnet *dev, int in_pm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int asix_read_phy_addr(struct usbnet *dev, int internal)
|
||||
int asix_read_phy_addr(struct usbnet *dev, bool internal)
|
||||
{
|
||||
int offset = (internal ? 1 : 0);
|
||||
int ret, offset;
|
||||
u8 buf[2];
|
||||
int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf, 0);
|
||||
|
||||
netdev_dbg(dev->net, "asix_get_phy_addr()\n");
|
||||
ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
if (ret < 2) {
|
||||
netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret);
|
||||
goto out;
|
||||
ret = -EIO;
|
||||
goto error;
|
||||
}
|
||||
netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n",
|
||||
*((__le16 *)buf));
|
||||
|
||||
offset = (internal ? 1 : 0);
|
||||
ret = buf[offset];
|
||||
|
||||
out:
|
||||
netdev_dbg(dev->net, "%s PHY address 0x%x\n",
|
||||
internal ? "internal" : "external", ret);
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
netdev_err(dev->net, "Error reading PHY_ID register: %02x\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int asix_get_phy_addr(struct usbnet *dev)
|
||||
{
|
||||
/* return the address of the internal phy */
|
||||
return asix_read_phy_addr(dev, 1);
|
||||
}
|
||||
|
||||
|
||||
int asix_sw_reset(struct usbnet *dev, u8 flags, int in_pm)
|
||||
{
|
||||
int ret;
|
||||
@ -383,6 +384,27 @@ int asix_write_medium_mode(struct usbnet *dev, u16 mode, int in_pm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set MAC link settings according to information from phylib */
|
||||
void asix_adjust_link(struct net_device *netdev)
|
||||
{
|
||||
struct phy_device *phydev = netdev->phydev;
|
||||
struct usbnet *dev = netdev_priv(netdev);
|
||||
u16 mode = 0;
|
||||
|
||||
if (phydev->link) {
|
||||
mode = AX88772_MEDIUM_DEFAULT;
|
||||
|
||||
if (phydev->duplex == DUPLEX_HALF)
|
||||
mode &= ~AX_MEDIUM_FD;
|
||||
|
||||
if (phydev->speed != SPEED_100)
|
||||
mode &= ~AX_MEDIUM_PS;
|
||||
}
|
||||
|
||||
asix_write_medium_mode(dev, mode, 0);
|
||||
phy_print_status(phydev);
|
||||
}
|
||||
|
||||
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm)
|
||||
{
|
||||
int ret;
|
||||
@ -463,18 +485,23 @@ int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
|
||||
return ret;
|
||||
}
|
||||
|
||||
asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
|
||||
(__u16)loc, 2, &res, 0);
|
||||
asix_set_hw_mii(dev, 0);
|
||||
ret = asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2,
|
||||
&res, 0);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = asix_set_hw_mii(dev, 0);
|
||||
out:
|
||||
mutex_unlock(&dev->phy_mutex);
|
||||
|
||||
netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
|
||||
phy_id, loc, le16_to_cpu(res));
|
||||
|
||||
return le16_to_cpu(res);
|
||||
return ret < 0 ? ret : le16_to_cpu(res);
|
||||
}
|
||||
|
||||
void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
|
||||
static int __asix_mdio_write(struct net_device *netdev, int phy_id, int loc,
|
||||
int val)
|
||||
{
|
||||
struct usbnet *dev = netdev_priv(netdev);
|
||||
__le16 res = cpu_to_le16(val);
|
||||
@ -494,15 +521,40 @@ void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
|
||||
ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG,
|
||||
0, 0, 1, &smsr, 0);
|
||||
} while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV));
|
||||
if (ret == -ENODEV) {
|
||||
mutex_unlock(&dev->phy_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
|
||||
(__u16)loc, 2, &res, 0);
|
||||
asix_set_hw_mii(dev, 0);
|
||||
if (ret == -ENODEV)
|
||||
goto out;
|
||||
|
||||
ret = asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2,
|
||||
&res, 0);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = asix_set_hw_mii(dev, 0);
|
||||
out:
|
||||
mutex_unlock(&dev->phy_mutex);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
|
||||
{
|
||||
__asix_mdio_write(netdev, phy_id, loc, val);
|
||||
}
|
||||
|
||||
/* MDIO read and write wrappers for phylib */
|
||||
int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum)
|
||||
{
|
||||
struct usbnet *priv = bus->priv;
|
||||
|
||||
return asix_mdio_read(priv->net, phy_id, regnum);
|
||||
}
|
||||
|
||||
int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)
|
||||
{
|
||||
struct usbnet *priv = bus->priv;
|
||||
|
||||
return __asix_mdio_write(priv->net, phy_id, regnum, val);
|
||||
}
|
||||
|
||||
int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc)
|
||||
|
@ -262,7 +262,10 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
|
||||
dev->mii.mdio_write = asix_mdio_write;
|
||||
dev->mii.phy_id_mask = 0x3f;
|
||||
dev->mii.reg_num_mask = 0x1f;
|
||||
dev->mii.phy_id = asix_get_phy_addr(dev);
|
||||
|
||||
dev->mii.phy_id = asix_read_phy_addr(dev, true);
|
||||
if (dev->mii.phy_id < 0)
|
||||
return dev->mii.phy_id;
|
||||
|
||||
dev->net->netdev_ops = &ax88172_netdev_ops;
|
||||
dev->net->ethtool_ops = &ax88172_ethtool_ops;
|
||||
@ -280,9 +283,29 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ax88772_ethtool_get_strings(struct net_device *netdev, u32 sset,
|
||||
u8 *data)
|
||||
{
|
||||
switch (sset) {
|
||||
case ETH_SS_TEST:
|
||||
net_selftest_get_strings(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int ax88772_ethtool_get_sset_count(struct net_device *ndev, int sset)
|
||||
{
|
||||
switch (sset) {
|
||||
case ETH_SS_TEST:
|
||||
return net_selftest_get_count();
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct ethtool_ops ax88772_ethtool_ops = {
|
||||
.get_drvinfo = asix_get_drvinfo,
|
||||
.get_link = asix_get_link,
|
||||
.get_link = usbnet_get_link,
|
||||
.get_msglevel = usbnet_get_msglevel,
|
||||
.set_msglevel = usbnet_set_msglevel,
|
||||
.get_wol = asix_get_wol,
|
||||
@ -290,37 +313,18 @@ static const struct ethtool_ops ax88772_ethtool_ops = {
|
||||
.get_eeprom_len = asix_get_eeprom_len,
|
||||
.get_eeprom = asix_get_eeprom,
|
||||
.set_eeprom = asix_set_eeprom,
|
||||
.nway_reset = usbnet_nway_reset,
|
||||
.get_link_ksettings = usbnet_get_link_ksettings_mii,
|
||||
.set_link_ksettings = usbnet_set_link_ksettings_mii,
|
||||
.nway_reset = phy_ethtool_nway_reset,
|
||||
.get_link_ksettings = phy_ethtool_get_link_ksettings,
|
||||
.set_link_ksettings = phy_ethtool_set_link_ksettings,
|
||||
.self_test = net_selftest,
|
||||
.get_strings = ax88772_ethtool_get_strings,
|
||||
.get_sset_count = ax88772_ethtool_get_sset_count,
|
||||
};
|
||||
|
||||
static int ax88772_link_reset(struct usbnet *dev)
|
||||
{
|
||||
u16 mode;
|
||||
struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
|
||||
|
||||
mii_check_media(&dev->mii, 1, 1);
|
||||
mii_ethtool_gset(&dev->mii, &ecmd);
|
||||
mode = AX88772_MEDIUM_DEFAULT;
|
||||
|
||||
if (ethtool_cmd_speed(&ecmd) != SPEED_100)
|
||||
mode &= ~AX_MEDIUM_PS;
|
||||
|
||||
if (ecmd.duplex != DUPLEX_FULL)
|
||||
mode &= ~AX_MEDIUM_FD;
|
||||
|
||||
netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
|
||||
ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
|
||||
|
||||
asix_write_medium_mode(dev, mode, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ax88772_reset(struct usbnet *dev)
|
||||
{
|
||||
struct asix_data *data = (struct asix_data *)&dev->data;
|
||||
struct asix_common_private *priv = dev->driver_priv;
|
||||
int ret;
|
||||
|
||||
/* Rewrite MAC address */
|
||||
@ -339,6 +343,8 @@ static int ax88772_reset(struct usbnet *dev)
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
phy_start(priv->phydev);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
@ -583,7 +589,7 @@ static const struct net_device_ops ax88772_netdev_ops = {
|
||||
.ndo_get_stats64 = dev_get_tstats64,
|
||||
.ndo_set_mac_address = asix_set_mac_address,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_do_ioctl = asix_ioctl,
|
||||
.ndo_do_ioctl = phy_do_ioctl_running,
|
||||
.ndo_set_rx_mode = asix_set_multicast,
|
||||
};
|
||||
|
||||
@ -674,12 +680,57 @@ static int asix_resume(struct usb_interface *intf)
|
||||
return usbnet_resume(intf);
|
||||
}
|
||||
|
||||
static int ax88772_init_mdio(struct usbnet *dev)
|
||||
{
|
||||
struct asix_common_private *priv = dev->driver_priv;
|
||||
|
||||
priv->mdio = devm_mdiobus_alloc(&dev->udev->dev);
|
||||
if (!priv->mdio)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->mdio->priv = dev;
|
||||
priv->mdio->read = &asix_mdio_bus_read;
|
||||
priv->mdio->write = &asix_mdio_bus_write;
|
||||
priv->mdio->name = "Asix MDIO Bus";
|
||||
/* mii bus name is usb-<usb bus number>-<usb device number> */
|
||||
snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "usb-%03d:%03d",
|
||||
dev->udev->bus->busnum, dev->udev->devnum);
|
||||
|
||||
return devm_mdiobus_register(&dev->udev->dev, priv->mdio);
|
||||
}
|
||||
|
||||
static int ax88772_init_phy(struct usbnet *dev)
|
||||
{
|
||||
struct asix_common_private *priv = dev->driver_priv;
|
||||
int ret;
|
||||
|
||||
priv->phy_addr = asix_read_phy_addr(dev, true);
|
||||
if (priv->phy_addr < 0)
|
||||
return priv->phy_addr;
|
||||
|
||||
snprintf(priv->phy_name, sizeof(priv->phy_name), PHY_ID_FMT,
|
||||
priv->mdio->id, priv->phy_addr);
|
||||
|
||||
priv->phydev = phy_connect(dev->net, priv->phy_name, &asix_adjust_link,
|
||||
PHY_INTERFACE_MODE_INTERNAL);
|
||||
if (IS_ERR(priv->phydev)) {
|
||||
netdev_err(dev->net, "Could not connect to PHY device %s\n",
|
||||
priv->phy_name);
|
||||
ret = PTR_ERR(priv->phydev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
phy_attached_info(priv->phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
|
||||
{
|
||||
int ret, i;
|
||||
u8 buf[ETH_ALEN] = {0}, chipcode = 0;
|
||||
u32 phyid;
|
||||
struct asix_common_private *priv;
|
||||
int ret, i;
|
||||
u32 phyid;
|
||||
|
||||
usbnet_get_endpoints(dev, intf);
|
||||
|
||||
@ -711,14 +762,6 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
|
||||
|
||||
asix_set_netdev_dev_addr(dev, buf);
|
||||
|
||||
/* Initialize MII structure */
|
||||
dev->mii.dev = dev->net;
|
||||
dev->mii.mdio_read = asix_mdio_read;
|
||||
dev->mii.mdio_write = asix_mdio_write;
|
||||
dev->mii.phy_id_mask = 0x1f;
|
||||
dev->mii.reg_num_mask = 0x1f;
|
||||
dev->mii.phy_id = asix_get_phy_addr(dev);
|
||||
|
||||
dev->net->netdev_ops = &ax88772_netdev_ops;
|
||||
dev->net->ethtool_ops = &ax88772_ethtool_ops;
|
||||
dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */
|
||||
@ -746,11 +789,11 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
|
||||
dev->rx_urb_size = 2048;
|
||||
}
|
||||
|
||||
dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL);
|
||||
if (!dev->driver_priv)
|
||||
priv = devm_kzalloc(&dev->udev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = dev->driver_priv;
|
||||
dev->driver_priv = priv;
|
||||
|
||||
priv->presvd_phy_bmcr = 0;
|
||||
priv->presvd_phy_advertise = 0;
|
||||
@ -762,13 +805,32 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
|
||||
priv->suspend = ax88772_suspend;
|
||||
}
|
||||
|
||||
ret = ax88772_init_mdio(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ax88772_init_phy(dev);
|
||||
}
|
||||
|
||||
static int ax88772_stop(struct usbnet *dev)
|
||||
{
|
||||
struct asix_common_private *priv = dev->driver_priv;
|
||||
|
||||
/* On unplugged USB, we will get MDIO communication errors and the
|
||||
* PHY will be set in to PHY_HALTED state.
|
||||
*/
|
||||
if (priv->phydev->state != PHY_HALTED)
|
||||
phy_stop(priv->phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
|
||||
{
|
||||
struct asix_common_private *priv = dev->driver_priv;
|
||||
|
||||
phy_disconnect(priv->phydev);
|
||||
asix_rx_fixup_common_free(dev->driver_priv);
|
||||
kfree(dev->driver_priv);
|
||||
}
|
||||
|
||||
static const struct ethtool_ops ax88178_ethtool_ops = {
|
||||
@ -1081,7 +1143,10 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
|
||||
dev->mii.phy_id_mask = 0x1f;
|
||||
dev->mii.reg_num_mask = 0xff;
|
||||
dev->mii.supports_gmii = 1;
|
||||
dev->mii.phy_id = asix_get_phy_addr(dev);
|
||||
|
||||
dev->mii.phy_id = asix_read_phy_addr(dev, true);
|
||||
if (dev->mii.phy_id < 0)
|
||||
return dev->mii.phy_id;
|
||||
|
||||
dev->net->netdev_ops = &ax88178_netdev_ops;
|
||||
dev->net->ethtool_ops = &ax88178_ethtool_ops;
|
||||
@ -1153,8 +1218,8 @@ static const struct driver_info ax88772_info = {
|
||||
.bind = ax88772_bind,
|
||||
.unbind = ax88772_unbind,
|
||||
.status = asix_status,
|
||||
.link_reset = ax88772_link_reset,
|
||||
.reset = ax88772_reset,
|
||||
.stop = ax88772_stop,
|
||||
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
|
||||
.rx_fixup = asix_rx_fixup_common,
|
||||
.tx_fixup = asix_tx_fixup,
|
||||
@ -1165,7 +1230,6 @@ static const struct driver_info ax88772b_info = {
|
||||
.bind = ax88772_bind,
|
||||
.unbind = ax88772_unbind,
|
||||
.status = asix_status,
|
||||
.link_reset = ax88772_link_reset,
|
||||
.reset = ax88772_reset,
|
||||
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
|
||||
FLAG_MULTI_PACKET,
|
||||
@ -1201,7 +1265,6 @@ static const struct driver_info hg20f9_info = {
|
||||
.bind = ax88772_bind,
|
||||
.unbind = ax88772_unbind,
|
||||
.status = asix_status,
|
||||
.link_reset = ax88772_link_reset,
|
||||
.reset = ax88772_reset,
|
||||
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
|
||||
FLAG_MULTI_PACKET,
|
||||
|
@ -25,20 +25,6 @@ struct ax88172a_private {
|
||||
struct asix_rx_fixup_info rx_fixup_info;
|
||||
};
|
||||
|
||||
/* MDIO read and write wrappers for phylib */
|
||||
static int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum)
|
||||
{
|
||||
return asix_mdio_read(((struct usbnet *)bus->priv)->net, phy_id,
|
||||
regnum);
|
||||
}
|
||||
|
||||
static int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum,
|
||||
u16 val)
|
||||
{
|
||||
asix_mdio_write(((struct usbnet *)bus->priv)->net, phy_id, regnum, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set MAC link settings according to information from phylib */
|
||||
static void ax88172a_adjust_link(struct net_device *netdev)
|
||||
{
|
||||
@ -220,6 +206,11 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf)
|
||||
}
|
||||
|
||||
priv->phy_addr = asix_read_phy_addr(dev, priv->use_embdphy);
|
||||
if (priv->phy_addr < 0) {
|
||||
ret = priv->phy_addr;
|
||||
goto free;
|
||||
}
|
||||
|
||||
ax88172a_reset_phy(dev, priv->use_embdphy);
|
||||
|
||||
/* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
|
||||
|
@ -1597,6 +1597,9 @@ void usbnet_disconnect (struct usb_interface *intf)
|
||||
xdev->bus->bus_name, xdev->devpath,
|
||||
dev->driver_info->description);
|
||||
|
||||
if (dev->driver_info->unbind)
|
||||
dev->driver_info->unbind(dev, intf);
|
||||
|
||||
net = dev->net;
|
||||
unregister_netdev (net);
|
||||
|
||||
@ -1604,9 +1607,6 @@ void usbnet_disconnect (struct usb_interface *intf)
|
||||
|
||||
usb_scuttle_anchored_urbs(&dev->deferred);
|
||||
|
||||
if (dev->driver_info->unbind)
|
||||
dev->driver_info->unbind (dev, intf);
|
||||
|
||||
usb_kill_urb(dev->interrupt);
|
||||
usb_free_urb(dev->interrupt);
|
||||
kfree(dev->padding_pkt);
|
||||
|
Loading…
x
Reference in New Issue
Block a user