Skip to content

Commit

Permalink
net: asix: ax88772: migrate to phylink
Browse files Browse the repository at this point in the history
There are some exotic ax88772 based devices which may require
functionality provide by the phylink framework. For example:
- US100A20SFP, USB 2.0 auf LWL Converter with SFP Cage
- AX88772B USB to 100Base-TX Ethernet (with RMII) demo board, where it
  is possible to switch between internal PHY and external RMII based
  connection.

So, convert this driver to phylink as soon as possible.

Tested with:
- AX88772A + internal PHY
- AX88772B + external DP83TD510E T1L PHY

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Oleksij Rempel authored and David S. Miller committed Aug 26, 2022
1 parent 057062a commit e0bffe3
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 11 deletions.
2 changes: 1 addition & 1 deletion drivers/net/usb/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ config USB_NET_AX8817X
tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters"
depends on USB_USBNET
select CRC32
select PHYLIB
select PHYLINK
select AX88796B_PHY
imply NET_SELFTESTS
default y
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/usb/asix.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <linux/if_vlan.h>
#include <linux/phy.h>
#include <net/selftests.h>
#include <linux/phylink.h>

#define DRIVER_VERSION "22-Dec-2011"
#define DRIVER_NAME "asix"
Expand Down Expand Up @@ -185,6 +186,8 @@ struct asix_common_private {
struct mii_bus *mdio;
struct phy_device *phydev;
struct phy_device *phydev_int;
struct phylink *phylink;
struct phylink_config phylink_config;
u16 phy_addr;
bool embd_phy;
u8 chipcode;
Expand Down
122 changes: 112 additions & 10 deletions drivers/net/usb/asix_devices.c
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ static int ax88772_reset(struct usbnet *dev)
if (ret < 0)
goto out;

phy_start(priv->phydev);
phylink_start(priv->phylink);

return 0;

Expand Down Expand Up @@ -590,8 +590,11 @@ static void ax88772_suspend(struct usbnet *dev)
struct asix_common_private *priv = dev->driver_priv;
u16 medium;

if (netif_running(dev->net))
phy_stop(priv->phydev);
if (netif_running(dev->net)) {
rtnl_lock();
phylink_suspend(priv->phylink, false);
rtnl_unlock();
}

/* Stop MAC operation */
medium = asix_read_medium_status(dev, 1);
Expand Down Expand Up @@ -622,8 +625,11 @@ static void ax88772_resume(struct usbnet *dev)
if (!priv->reset(dev, 1))
break;

if (netif_running(dev->net))
phy_start(priv->phydev);
if (netif_running(dev->net)) {
rtnl_lock();
phylink_resume(priv->phylink);
rtnl_unlock();
}
}

static int asix_resume(struct usb_interface *intf)
Expand Down Expand Up @@ -667,8 +673,7 @@ static int ax88772_init_phy(struct usbnet *dev)
return -ENODEV;
}

ret = phy_connect_direct(dev->net, priv->phydev, &asix_adjust_link,
PHY_INTERFACE_MODE_INTERNAL);
ret = phylink_connect_phy(priv->phylink, priv->phydev);
if (ret) {
netdev_err(dev->net, "Could not connect PHY\n");
return ret;
Expand All @@ -688,6 +693,9 @@ static int ax88772_init_phy(struct usbnet *dev)
*/
priv->phydev_int = mdiobus_get_phy(priv->mdio, AX_EMBD_PHY_ADDR);
if (!priv->phydev_int) {
rtnl_lock();
phylink_disconnect_phy(priv->phylink);
rtnl_unlock();
netdev_err(dev->net, "Could not find internal PHY\n");
return -ENODEV;
}
Expand All @@ -698,6 +706,89 @@ static int ax88772_init_phy(struct usbnet *dev)
return 0;
}

static void ax88772_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state)
{
/* Nothing to do */
}

static void ax88772_mac_link_down(struct phylink_config *config,
unsigned int mode, phy_interface_t interface)
{
struct usbnet *dev = netdev_priv(to_net_dev(config->dev));

asix_write_medium_mode(dev, 0, 0);
usbnet_link_change(dev, false, false);
}

static void ax88772_mac_link_up(struct phylink_config *config,
struct phy_device *phy,
unsigned int mode, phy_interface_t interface,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
struct usbnet *dev = netdev_priv(to_net_dev(config->dev));
u16 m = AX_MEDIUM_AC | AX_MEDIUM_RE;

m |= duplex ? AX_MEDIUM_FD : 0;

switch (speed) {
case SPEED_100:
m |= AX_MEDIUM_PS;
break;
case SPEED_10:
break;
default:
return;
}

if (tx_pause)
m |= AX_MEDIUM_TFC;

if (rx_pause)
m |= AX_MEDIUM_RFC;

asix_write_medium_mode(dev, m, 0);
usbnet_link_change(dev, true, false);
}

static const struct phylink_mac_ops ax88772_phylink_mac_ops = {
.validate = phylink_generic_validate,
.mac_config = ax88772_mac_config,
.mac_link_down = ax88772_mac_link_down,
.mac_link_up = ax88772_mac_link_up,
};

static int ax88772_phylink_setup(struct usbnet *dev)
{
struct asix_common_private *priv = dev->driver_priv;
phy_interface_t phy_if_mode;
struct phylink *phylink;

priv->phylink_config.dev = &dev->net->dev;
priv->phylink_config.type = PHYLINK_NETDEV;
priv->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE |
MAC_10 | MAC_100;

__set_bit(PHY_INTERFACE_MODE_INTERNAL,
priv->phylink_config.supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_RMII,
priv->phylink_config.supported_interfaces);

if (priv->embd_phy)
phy_if_mode = PHY_INTERFACE_MODE_INTERNAL;
else
phy_if_mode = PHY_INTERFACE_MODE_RMII;

phylink = phylink_create(&priv->phylink_config, dev->net->dev.fwnode,
phy_if_mode, &ax88772_phylink_mac_ops);
if (IS_ERR(phylink))
return PTR_ERR(phylink);

priv->phylink = phylink;
return 0;
}

static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
{
struct asix_common_private *priv;
Expand Down Expand Up @@ -788,14 +879,22 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
if (ret)
return ret;

return ax88772_init_phy(dev);
ret = ax88772_phylink_setup(dev);
if (ret)
return ret;

ret = ax88772_init_phy(dev);
if (ret)
phylink_destroy(priv->phylink);

return ret;
}

static int ax88772_stop(struct usbnet *dev)
{
struct asix_common_private *priv = dev->driver_priv;

phy_stop(priv->phydev);
phylink_stop(priv->phylink);

return 0;
}
Expand All @@ -804,7 +903,10 @@ static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
{
struct asix_common_private *priv = dev->driver_priv;

phy_disconnect(priv->phydev);
rtnl_lock();
phylink_disconnect_phy(priv->phylink);
rtnl_unlock();
phylink_destroy(priv->phylink);
asix_rx_fixup_common_free(dev->driver_priv);
}

Expand Down

0 comments on commit e0bffe3

Please sign in to comment.