aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFreddy Xin <freddy@asix.com.tw>2014-07-31 07:06:35 -0400
committerDavid S. Miller <davem@davemloft.net>2014-08-01 01:07:38 -0400
commite98d69ba464868a5d6b0b43730658810a29ff825 (patch)
tree2335182f6c800f3e72d0a68265cd687d0e550c37
parent74e83b23f2619db057c9e3c3ec4b7090f883bc5e (diff)
AX88179_178A: Add ethtool ops for EEE support
Add functions to support ethtool EEE manipulating, and the EEE is disabled in default setting to enhance the compatibility with certain switch. Signed-off-by: Freddy Xin <freddy@asix.com.tw> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/usb/ax88179_178a.c264
1 files changed, 264 insertions, 0 deletions
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index 054e59ca6946..be4275721039 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -23,6 +23,8 @@
23#include <linux/usb.h> 23#include <linux/usb.h>
24#include <linux/crc32.h> 24#include <linux/crc32.h>
25#include <linux/usb/usbnet.h> 25#include <linux/usb/usbnet.h>
26#include <uapi/linux/mdio.h>
27#include <linux/mdio.h>
26 28
27#define AX88179_PHY_ID 0x03 29#define AX88179_PHY_ID 0x03
28#define AX_EEPROM_LEN 0x100 30#define AX_EEPROM_LEN 0x100
@@ -170,8 +172,12 @@
170#define GMII_PHY_PAGE_SELECT 0x1f 172#define GMII_PHY_PAGE_SELECT 0x1f
171 #define GMII_PHY_PGSEL_EXT 0x0007 173 #define GMII_PHY_PGSEL_EXT 0x0007
172 #define GMII_PHY_PGSEL_PAGE0 0x0000 174 #define GMII_PHY_PGSEL_PAGE0 0x0000
175 #define GMII_PHY_PGSEL_PAGE3 0x0003
176 #define GMII_PHY_PGSEL_PAGE5 0x0005
173 177
174struct ax88179_data { 178struct ax88179_data {
179 u8 eee_enabled;
180 u8 eee_active;
175 u16 rxctl; 181 u16 rxctl;
176 u16 reserved; 182 u16 reserved;
177}; 183};
@@ -373,6 +379,60 @@ static void ax88179_mdio_write(struct net_device *netdev, int phy_id, int loc,
373 ax88179_write_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res); 379 ax88179_write_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res);
374} 380}
375 381
382static inline int ax88179_phy_mmd_indirect(struct usbnet *dev, u16 prtad,
383 u16 devad)
384{
385 u16 tmp16;
386 int ret;
387
388 tmp16 = devad;
389 ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
390 MII_MMD_CTRL, 2, &tmp16);
391
392 tmp16 = prtad;
393 ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
394 MII_MMD_DATA, 2, &tmp16);
395
396 tmp16 = devad | MII_MMD_CTRL_NOINCR;
397 ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
398 MII_MMD_CTRL, 2, &tmp16);
399
400 return ret;
401}
402
403static int
404ax88179_phy_read_mmd_indirect(struct usbnet *dev, u16 prtad, u16 devad)
405{
406 int ret;
407 u16 tmp16;
408
409 ax88179_phy_mmd_indirect(dev, prtad, devad);
410
411 ret = ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
412 MII_MMD_DATA, 2, &tmp16);
413 if (ret < 0)
414 return ret;
415
416 return tmp16;
417}
418
419static int
420ax88179_phy_write_mmd_indirect(struct usbnet *dev, u16 prtad, u16 devad,
421 u16 data)
422{
423 int ret;
424
425 ax88179_phy_mmd_indirect(dev, prtad, devad);
426
427 ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
428 MII_MMD_DATA, 2, &data);
429
430 if (ret < 0)
431 return ret;
432
433 return 0;
434}
435
376static int ax88179_suspend(struct usb_interface *intf, pm_message_t message) 436static int ax88179_suspend(struct usb_interface *intf, pm_message_t message)
377{ 437{
378 struct usbnet *dev = usb_get_intfdata(intf); 438 struct usbnet *dev = usb_get_intfdata(intf);
@@ -572,6 +632,185 @@ static int ax88179_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
572 return mii_ethtool_sset(&dev->mii, cmd); 632 return mii_ethtool_sset(&dev->mii, cmd);
573} 633}
574 634
635static int
636ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_eee *data)
637{
638 int val;
639
640 /* Get Supported EEE */
641 val = ax88179_phy_read_mmd_indirect(dev, MDIO_PCS_EEE_ABLE,
642 MDIO_MMD_PCS);
643 if (val < 0)
644 return val;
645 data->supported = mmd_eee_cap_to_ethtool_sup_t(val);
646
647 /* Get advertisement EEE */
648 val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_ADV,
649 MDIO_MMD_AN);
650 if (val < 0)
651 return val;
652 data->advertised = mmd_eee_adv_to_ethtool_adv_t(val);
653
654 /* Get LP advertisement EEE */
655 val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_LPABLE,
656 MDIO_MMD_AN);
657 if (val < 0)
658 return val;
659 data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val);
660
661 return 0;
662}
663
664static int
665ax88179_ethtool_set_eee(struct usbnet *dev, struct ethtool_eee *data)
666{
667 u16 tmp16 = ethtool_adv_to_mmd_eee_adv_t(data->advertised);
668
669 return ax88179_phy_write_mmd_indirect(dev, MDIO_AN_EEE_ADV,
670 MDIO_MMD_AN, tmp16);
671}
672
673static int ax88179_chk_eee(struct usbnet *dev)
674{
675 struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
676 struct ax88179_data *priv = (struct ax88179_data *)dev->data;
677
678 mii_ethtool_gset(&dev->mii, &ecmd);
679
680 if (ecmd.duplex & DUPLEX_FULL) {
681 int eee_lp, eee_cap, eee_adv;
682 u32 lp, cap, adv, supported = 0;
683
684 eee_cap = ax88179_phy_read_mmd_indirect(dev,
685 MDIO_PCS_EEE_ABLE,
686 MDIO_MMD_PCS);
687 if (eee_cap < 0) {
688 priv->eee_active = 0;
689 return false;
690 }
691
692 cap = mmd_eee_cap_to_ethtool_sup_t(eee_cap);
693 if (!cap) {
694 priv->eee_active = 0;
695 return false;
696 }
697
698 eee_lp = ax88179_phy_read_mmd_indirect(dev,
699 MDIO_AN_EEE_LPABLE,
700 MDIO_MMD_AN);
701 if (eee_lp < 0) {
702 priv->eee_active = 0;
703 return false;
704 }
705
706 eee_adv = ax88179_phy_read_mmd_indirect(dev,
707 MDIO_AN_EEE_ADV,
708 MDIO_MMD_AN);
709
710 if (eee_adv < 0) {
711 priv->eee_active = 0;
712 return false;
713 }
714
715 adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv);
716 lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp);
717 supported = (ecmd.speed == SPEED_1000) ?
718 SUPPORTED_1000baseT_Full :
719 SUPPORTED_100baseT_Full;
720
721 if (!(lp & adv & supported)) {
722 priv->eee_active = 0;
723 return false;
724 }
725
726 priv->eee_active = 1;
727 return true;
728 }
729
730 priv->eee_active = 0;
731 return false;
732}
733
734static void ax88179_disable_eee(struct usbnet *dev)
735{
736 u16 tmp16;
737
738 tmp16 = GMII_PHY_PGSEL_PAGE3;
739 ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
740 GMII_PHY_PAGE_SELECT, 2, &tmp16);
741
742 tmp16 = 0x3246;
743 ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
744 MII_PHYADDR, 2, &tmp16);
745
746 tmp16 = GMII_PHY_PGSEL_PAGE0;
747 ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
748 GMII_PHY_PAGE_SELECT, 2, &tmp16);
749}
750
751static void ax88179_enable_eee(struct usbnet *dev)
752{
753 u16 tmp16;
754
755 tmp16 = GMII_PHY_PGSEL_PAGE3;
756 ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
757 GMII_PHY_PAGE_SELECT, 2, &tmp16);
758
759 tmp16 = 0x3247;
760 ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
761 MII_PHYADDR, 2, &tmp16);
762
763 tmp16 = GMII_PHY_PGSEL_PAGE5;
764 ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
765 GMII_PHY_PAGE_SELECT, 2, &tmp16);
766
767 tmp16 = 0x0680;
768 ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
769 MII_BMSR, 2, &tmp16);
770
771 tmp16 = GMII_PHY_PGSEL_PAGE0;
772 ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
773 GMII_PHY_PAGE_SELECT, 2, &tmp16);
774}
775
776static int ax88179_get_eee(struct net_device *net, struct ethtool_eee *edata)
777{
778 struct usbnet *dev = netdev_priv(net);
779 struct ax88179_data *priv = (struct ax88179_data *)dev->data;
780
781 edata->eee_enabled = priv->eee_enabled;
782 edata->eee_active = priv->eee_active;
783
784 return ax88179_ethtool_get_eee(dev, edata);
785}
786
787static int ax88179_set_eee(struct net_device *net, struct ethtool_eee *edata)
788{
789 struct usbnet *dev = netdev_priv(net);
790 struct ax88179_data *priv = (struct ax88179_data *)dev->data;
791 int ret = -EOPNOTSUPP;
792
793 priv->eee_enabled = edata->eee_enabled;
794 if (!priv->eee_enabled) {
795 ax88179_disable_eee(dev);
796 } else {
797 priv->eee_enabled = ax88179_chk_eee(dev);
798 if (!priv->eee_enabled)
799 return -EOPNOTSUPP;
800
801 ax88179_enable_eee(dev);
802 }
803
804 ret = ax88179_ethtool_set_eee(dev, edata);
805 if (ret)
806 return ret;
807
808 mii_nway_restart(&dev->mii);
809
810 usbnet_link_change(dev, 0, 0);
811
812 return ret;
813}
575 814
576static int ax88179_ioctl(struct net_device *net, struct ifreq *rq, int cmd) 815static int ax88179_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
577{ 816{
@@ -589,6 +828,8 @@ static const struct ethtool_ops ax88179_ethtool_ops = {
589 .get_eeprom = ax88179_get_eeprom, 828 .get_eeprom = ax88179_get_eeprom,
590 .get_settings = ax88179_get_settings, 829 .get_settings = ax88179_get_settings,
591 .set_settings = ax88179_set_settings, 830 .set_settings = ax88179_set_settings,
831 .get_eee = ax88179_get_eee,
832 .set_eee = ax88179_set_eee,
592 .nway_reset = usbnet_nway_reset, 833 .nway_reset = usbnet_nway_reset,
593}; 834};
594 835
@@ -980,6 +1221,7 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
980 u16 *tmp16; 1221 u16 *tmp16;
981 u8 *tmp; 1222 u8 *tmp;
982 struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data; 1223 struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
1224 struct ethtool_eee eee_data;
983 1225
984 usbnet_get_endpoints(dev, intf); 1226 usbnet_get_endpoints(dev, intf);
985 1227
@@ -1062,6 +1304,15 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
1062 1304
1063 ax88179_led_setting(dev); 1305 ax88179_led_setting(dev);
1064 1306
1307 ax179_data->eee_enabled = 0;
1308 ax179_data->eee_active = 0;
1309
1310 ax88179_disable_eee(dev);
1311
1312 ax88179_ethtool_get_eee(dev, &eee_data);
1313 eee_data.advertised = 0;
1314 ax88179_ethtool_set_eee(dev, &eee_data);
1315
1065 /* Restart autoneg */ 1316 /* Restart autoneg */
1066 mii_nway_restart(&dev->mii); 1317 mii_nway_restart(&dev->mii);
1067 1318
@@ -1261,6 +1512,8 @@ static int ax88179_link_reset(struct usbnet *dev)
1261 ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, 1512 ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
1262 2, 2, &mode); 1513 2, 2, &mode);
1263 1514
1515 ax179_data->eee_enabled = ax88179_chk_eee(dev);
1516
1264 netif_carrier_on(dev->net); 1517 netif_carrier_on(dev->net);
1265 1518
1266 return 0; 1519 return 0;
@@ -1271,6 +1524,8 @@ static int ax88179_reset(struct usbnet *dev)
1271 u8 buf[5]; 1524 u8 buf[5];
1272 u16 *tmp16; 1525 u16 *tmp16;
1273 u8 *tmp; 1526 u8 *tmp;
1527 struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
1528 struct ethtool_eee eee_data;
1274 1529
1275 tmp16 = (u16 *)buf; 1530 tmp16 = (u16 *)buf;
1276 tmp = (u8 *)buf; 1531 tmp = (u8 *)buf;
@@ -1340,6 +1595,15 @@ static int ax88179_reset(struct usbnet *dev)
1340 1595
1341 ax88179_led_setting(dev); 1596 ax88179_led_setting(dev);
1342 1597
1598 ax179_data->eee_enabled = 0;
1599 ax179_data->eee_active = 0;
1600
1601 ax88179_disable_eee(dev);
1602
1603 ax88179_ethtool_get_eee(dev, &eee_data);
1604 eee_data.advertised = 0;
1605 ax88179_ethtool_set_eee(dev, &eee_data);
1606
1343 /* Restart autoneg */ 1607 /* Restart autoneg */
1344 mii_nway_restart(&dev->mii); 1608 mii_nway_restart(&dev->mii);
1345 1609