Skip to content

Commit e532a09

Browse files
oleremdavem330
authored andcommitted
net: usb: asix: ax88772: add phylib support
To be able to use ax88772 with external PHYs and use advantage of existing PHY drivers, we need to port at least ax88772 part of asix driver to the phylib framework. Signed-off-by: Oleksij Rempel <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent dde2584 commit e532a09

File tree

4 files changed

+122
-58
lines changed

4 files changed

+122
-58
lines changed

drivers/net/usb/asix.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <linux/usb/usbnet.h>
2626
#include <linux/slab.h>
2727
#include <linux/if_vlan.h>
28+
#include <linux/phy.h>
2829

2930
#define DRIVER_VERSION "22-Dec-2011"
3031
#define DRIVER_NAME "asix"
@@ -178,6 +179,10 @@ struct asix_common_private {
178179
u16 presvd_phy_advertise;
179180
u16 presvd_phy_bmcr;
180181
struct asix_rx_fixup_info rx_fixup_info;
182+
struct mii_bus *mdio;
183+
struct phy_device *phydev;
184+
u16 phy_addr;
185+
char phy_name[20];
181186
};
182187

183188
extern const struct driver_info ax88172a_info;
@@ -214,6 +219,7 @@ int asix_write_rx_ctl(struct usbnet *dev, u16 mode, int in_pm);
214219

215220
u16 asix_read_medium_status(struct usbnet *dev, int in_pm);
216221
int asix_write_medium_mode(struct usbnet *dev, u16 mode, int in_pm);
222+
void asix_adjust_link(struct net_device *netdev);
217223

218224
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm);
219225

@@ -222,6 +228,9 @@ void asix_set_multicast(struct net_device *net);
222228
int asix_mdio_read(struct net_device *netdev, int phy_id, int loc);
223229
void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val);
224230

231+
int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum);
232+
int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val);
233+
225234
int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc);
226235
void asix_mdio_write_nopm(struct net_device *netdev, int phy_id, int loc,
227236
int val);

drivers/net/usb/asix_common.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,27 @@ int asix_write_medium_mode(struct usbnet *dev, u16 mode, int in_pm)
384384
return ret;
385385
}
386386

387+
/* set MAC link settings according to information from phylib */
388+
void asix_adjust_link(struct net_device *netdev)
389+
{
390+
struct phy_device *phydev = netdev->phydev;
391+
struct usbnet *dev = netdev_priv(netdev);
392+
u16 mode = 0;
393+
394+
if (phydev->link) {
395+
mode = AX88772_MEDIUM_DEFAULT;
396+
397+
if (phydev->duplex == DUPLEX_HALF)
398+
mode &= ~AX_MEDIUM_FD;
399+
400+
if (phydev->speed != SPEED_100)
401+
mode &= ~AX_MEDIUM_PS;
402+
}
403+
404+
asix_write_medium_mode(dev, mode, 0);
405+
phy_print_status(phydev);
406+
}
407+
387408
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm)
388409
{
389410
int ret;
@@ -506,6 +527,22 @@ void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
506527
mutex_unlock(&dev->phy_mutex);
507528
}
508529

530+
/* MDIO read and write wrappers for phylib */
531+
int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum)
532+
{
533+
struct usbnet *priv = bus->priv;
534+
535+
return asix_mdio_read(priv->net, phy_id, regnum);
536+
}
537+
538+
int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)
539+
{
540+
struct usbnet *priv = bus->priv;
541+
542+
asix_mdio_write(priv->net, phy_id, regnum, val);
543+
return 0;
544+
}
545+
509546
int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc)
510547
{
511548
struct usbnet *dev = netdev_priv(netdev);

drivers/net/usb/asix_devices.c

Lines changed: 76 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -285,45 +285,23 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
285285

286286
static const struct ethtool_ops ax88772_ethtool_ops = {
287287
.get_drvinfo = asix_get_drvinfo,
288-
.get_link = asix_get_link,
288+
.get_link = usbnet_get_link,
289289
.get_msglevel = usbnet_get_msglevel,
290290
.set_msglevel = usbnet_set_msglevel,
291291
.get_wol = asix_get_wol,
292292
.set_wol = asix_set_wol,
293293
.get_eeprom_len = asix_get_eeprom_len,
294294
.get_eeprom = asix_get_eeprom,
295295
.set_eeprom = asix_set_eeprom,
296-
.nway_reset = usbnet_nway_reset,
297-
.get_link_ksettings = usbnet_get_link_ksettings_mii,
298-
.set_link_ksettings = usbnet_set_link_ksettings_mii,
296+
.nway_reset = phy_ethtool_nway_reset,
297+
.get_link_ksettings = phy_ethtool_get_link_ksettings,
298+
.set_link_ksettings = phy_ethtool_set_link_ksettings,
299299
};
300300

301-
static int ax88772_link_reset(struct usbnet *dev)
302-
{
303-
u16 mode;
304-
struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
305-
306-
mii_check_media(&dev->mii, 1, 1);
307-
mii_ethtool_gset(&dev->mii, &ecmd);
308-
mode = AX88772_MEDIUM_DEFAULT;
309-
310-
if (ethtool_cmd_speed(&ecmd) != SPEED_100)
311-
mode &= ~AX_MEDIUM_PS;
312-
313-
if (ecmd.duplex != DUPLEX_FULL)
314-
mode &= ~AX_MEDIUM_FD;
315-
316-
netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
317-
ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
318-
319-
asix_write_medium_mode(dev, mode, 0);
320-
321-
return 0;
322-
}
323-
324301
static int ax88772_reset(struct usbnet *dev)
325302
{
326303
struct asix_data *data = (struct asix_data *)&dev->data;
304+
struct asix_common_private *priv = dev->driver_priv;
327305
int ret;
328306

329307
/* Rewrite MAC address */
@@ -342,6 +320,8 @@ static int ax88772_reset(struct usbnet *dev)
342320
if (ret < 0)
343321
goto out;
344322

323+
phy_start(priv->phydev);
324+
345325
return 0;
346326

347327
out:
@@ -586,7 +566,7 @@ static const struct net_device_ops ax88772_netdev_ops = {
586566
.ndo_get_stats64 = dev_get_tstats64,
587567
.ndo_set_mac_address = asix_set_mac_address,
588568
.ndo_validate_addr = eth_validate_addr,
589-
.ndo_do_ioctl = asix_ioctl,
569+
.ndo_do_ioctl = phy_do_ioctl_running,
590570
.ndo_set_rx_mode = asix_set_multicast,
591571
};
592572

@@ -677,12 +657,57 @@ static int asix_resume(struct usb_interface *intf)
677657
return usbnet_resume(intf);
678658
}
679659

660+
static int ax88772_init_mdio(struct usbnet *dev)
661+
{
662+
struct asix_common_private *priv = dev->driver_priv;
663+
664+
priv->mdio = devm_mdiobus_alloc(&dev->udev->dev);
665+
if (!priv->mdio)
666+
return -ENOMEM;
667+
668+
priv->mdio->priv = dev;
669+
priv->mdio->read = &asix_mdio_bus_read;
670+
priv->mdio->write = &asix_mdio_bus_write;
671+
priv->mdio->name = "Asix MDIO Bus";
672+
/* mii bus name is usb-<usb bus number>-<usb device number> */
673+
snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "usb-%03d:%03d",
674+
dev->udev->bus->busnum, dev->udev->devnum);
675+
676+
return devm_mdiobus_register(&dev->udev->dev, priv->mdio);
677+
}
678+
679+
static int ax88772_init_phy(struct usbnet *dev)
680+
{
681+
struct asix_common_private *priv = dev->driver_priv;
682+
int ret;
683+
684+
priv->phy_addr = asix_read_phy_addr(dev, true);
685+
if (priv->phy_addr < 0)
686+
return priv->phy_addr;
687+
688+
snprintf(priv->phy_name, sizeof(priv->phy_name), PHY_ID_FMT,
689+
priv->mdio->id, priv->phy_addr);
690+
691+
priv->phydev = phy_connect(dev->net, priv->phy_name, &asix_adjust_link,
692+
PHY_INTERFACE_MODE_INTERNAL);
693+
if (IS_ERR(priv->phydev)) {
694+
netdev_err(dev->net, "Could not connect to PHY device %s\n",
695+
priv->phy_name);
696+
ret = PTR_ERR(priv->phydev);
697+
return ret;
698+
}
699+
700+
phy_attached_info(priv->phydev);
701+
702+
return 0;
703+
}
704+
680705
static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
681706
{
682-
int ret, i;
683707
u8 buf[ETH_ALEN] = {0}, chipcode = 0;
684-
u32 phyid;
685708
struct asix_common_private *priv;
709+
int ret, i;
710+
u32 phyid;
686711

687712
usbnet_get_endpoints(dev, intf);
688713

@@ -714,17 +739,6 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
714739

715740
asix_set_netdev_dev_addr(dev, buf);
716741

717-
/* Initialize MII structure */
718-
dev->mii.dev = dev->net;
719-
dev->mii.mdio_read = asix_mdio_read;
720-
dev->mii.mdio_write = asix_mdio_write;
721-
dev->mii.phy_id_mask = 0x1f;
722-
dev->mii.reg_num_mask = 0x1f;
723-
724-
dev->mii.phy_id = asix_read_phy_addr(dev, true);
725-
if (dev->mii.phy_id < 0)
726-
return dev->mii.phy_id;
727-
728742
dev->net->netdev_ops = &ax88772_netdev_ops;
729743
dev->net->ethtool_ops = &ax88772_ethtool_ops;
730744
dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */
@@ -768,11 +782,31 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
768782
priv->suspend = ax88772_suspend;
769783
}
770784

785+
ret = ax88772_init_mdio(dev);
786+
if (ret)
787+
return ret;
788+
789+
return ax88772_init_phy(dev);
790+
}
791+
792+
static int ax88772_stop(struct usbnet *dev)
793+
{
794+
struct asix_common_private *priv = dev->driver_priv;
795+
796+
/* On unplugged USB, we will get MDIO communication errors and the
797+
* PHY will be set in to PHY_HALTED state.
798+
*/
799+
if (priv->phydev->state != PHY_HALTED)
800+
phy_stop(priv->phydev);
801+
771802
return 0;
772803
}
773804

774805
static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
775806
{
807+
struct asix_common_private *priv = dev->driver_priv;
808+
809+
phy_disconnect(priv->phydev);
776810
asix_rx_fixup_common_free(dev->driver_priv);
777811
}
778812

@@ -1161,8 +1195,8 @@ static const struct driver_info ax88772_info = {
11611195
.bind = ax88772_bind,
11621196
.unbind = ax88772_unbind,
11631197
.status = asix_status,
1164-
.link_reset = ax88772_link_reset,
11651198
.reset = ax88772_reset,
1199+
.stop = ax88772_stop,
11661200
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
11671201
.rx_fixup = asix_rx_fixup_common,
11681202
.tx_fixup = asix_tx_fixup,
@@ -1173,7 +1207,6 @@ static const struct driver_info ax88772b_info = {
11731207
.bind = ax88772_bind,
11741208
.unbind = ax88772_unbind,
11751209
.status = asix_status,
1176-
.link_reset = ax88772_link_reset,
11771210
.reset = ax88772_reset,
11781211
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
11791212
FLAG_MULTI_PACKET,
@@ -1209,7 +1242,6 @@ static const struct driver_info hg20f9_info = {
12091242
.bind = ax88772_bind,
12101243
.unbind = ax88772_unbind,
12111244
.status = asix_status,
1212-
.link_reset = ax88772_link_reset,
12131245
.reset = ax88772_reset,
12141246
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
12151247
FLAG_MULTI_PACKET,

drivers/net/usb/ax88172a.c

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,6 @@ struct ax88172a_private {
2525
struct asix_rx_fixup_info rx_fixup_info;
2626
};
2727

28-
/* MDIO read and write wrappers for phylib */
29-
static int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum)
30-
{
31-
return asix_mdio_read(((struct usbnet *)bus->priv)->net, phy_id,
32-
regnum);
33-
}
34-
35-
static int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum,
36-
u16 val)
37-
{
38-
asix_mdio_write(((struct usbnet *)bus->priv)->net, phy_id, regnum, val);
39-
return 0;
40-
}
41-
4228
/* set MAC link settings according to information from phylib */
4329
static void ax88172a_adjust_link(struct net_device *netdev)
4430
{

0 commit comments

Comments
 (0)