diff options
author | Francois Romieu <romieu@fr.zoreil.com> | 2008-07-26 08:26:06 -0400 |
---|---|---|
committer | Francois Romieu <romieu@fr.zoreil.com> | 2008-08-17 09:53:04 -0400 |
commit | ccdffb9a88b2907b159538d7bfd6256621db4f84 (patch) | |
tree | e6d91e453d0db635089804b7bd023d18135abed5 /drivers/net/r8169.c | |
parent | d6f8aa8586dabe605454f3c98a5c1a577c3e0cfb (diff) |
r8169: get ethtool settings through the generic mii helper
It avoids to report unsupported link capabilities with
the fast-ethernet only 8101/8102.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Tested-by: Martin Capitanio <martin@capitanio.org>
Fixed-by: Ivan Vecera <ivecera@redhat.com>
Cc: Edward Hsu <edward_hsu@realtek.com.tw>
Diffstat (limited to 'drivers/net/r8169.c')
-rw-r--r-- | drivers/net/r8169.c | 99 |
1 files changed, 46 insertions, 53 deletions
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index a3e3895e5032..dac2677eeede 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c | |||
@@ -370,8 +370,9 @@ struct ring_info { | |||
370 | }; | 370 | }; |
371 | 371 | ||
372 | enum features { | 372 | enum features { |
373 | RTL_FEATURE_WOL = (1 << 0), | 373 | RTL_FEATURE_WOL = (1 << 0), |
374 | RTL_FEATURE_MSI = (1 << 1), | 374 | RTL_FEATURE_MSI = (1 << 1), |
375 | RTL_FEATURE_GMII = (1 << 2), | ||
375 | }; | 376 | }; |
376 | 377 | ||
377 | struct rtl8169_private { | 378 | struct rtl8169_private { |
@@ -406,13 +407,15 @@ struct rtl8169_private { | |||
406 | struct vlan_group *vlgrp; | 407 | struct vlan_group *vlgrp; |
407 | #endif | 408 | #endif |
408 | int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex); | 409 | int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex); |
409 | void (*get_settings)(struct net_device *, struct ethtool_cmd *); | 410 | int (*get_settings)(struct net_device *, struct ethtool_cmd *); |
410 | void (*phy_reset_enable)(void __iomem *); | 411 | void (*phy_reset_enable)(void __iomem *); |
411 | void (*hw_start)(struct net_device *); | 412 | void (*hw_start)(struct net_device *); |
412 | unsigned int (*phy_reset_pending)(void __iomem *); | 413 | unsigned int (*phy_reset_pending)(void __iomem *); |
413 | unsigned int (*link_ok)(void __iomem *); | 414 | unsigned int (*link_ok)(void __iomem *); |
414 | struct delayed_work task; | 415 | struct delayed_work task; |
415 | unsigned features; | 416 | unsigned features; |
417 | |||
418 | struct mii_if_info mii; | ||
416 | }; | 419 | }; |
417 | 420 | ||
418 | MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); | 421 | MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); |
@@ -482,6 +485,23 @@ static int mdio_read(void __iomem *ioaddr, int reg_addr) | |||
482 | return value; | 485 | return value; |
483 | } | 486 | } |
484 | 487 | ||
488 | static void rtl_mdio_write(struct net_device *dev, int phy_id, int location, | ||
489 | int val) | ||
490 | { | ||
491 | struct rtl8169_private *tp = netdev_priv(dev); | ||
492 | void __iomem *ioaddr = tp->mmio_addr; | ||
493 | |||
494 | mdio_write(ioaddr, location, val); | ||
495 | } | ||
496 | |||
497 | static int rtl_mdio_read(struct net_device *dev, int phy_id, int location) | ||
498 | { | ||
499 | struct rtl8169_private *tp = netdev_priv(dev); | ||
500 | void __iomem *ioaddr = tp->mmio_addr; | ||
501 | |||
502 | return mdio_read(ioaddr, location); | ||
503 | } | ||
504 | |||
485 | static void rtl8169_irq_mask_and_ack(void __iomem *ioaddr) | 505 | static void rtl8169_irq_mask_and_ack(void __iomem *ioaddr) |
486 | { | 506 | { |
487 | RTL_W16(IntrMask, 0x0000); | 507 | RTL_W16(IntrMask, 0x0000); |
@@ -850,7 +870,7 @@ static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, | |||
850 | 870 | ||
851 | #endif | 871 | #endif |
852 | 872 | ||
853 | static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd) | 873 | static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd) |
854 | { | 874 | { |
855 | struct rtl8169_private *tp = netdev_priv(dev); | 875 | struct rtl8169_private *tp = netdev_priv(dev); |
856 | void __iomem *ioaddr = tp->mmio_addr; | 876 | void __iomem *ioaddr = tp->mmio_addr; |
@@ -867,65 +887,29 @@ static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd) | |||
867 | 887 | ||
868 | cmd->speed = SPEED_1000; | 888 | cmd->speed = SPEED_1000; |
869 | cmd->duplex = DUPLEX_FULL; /* Always set */ | 889 | cmd->duplex = DUPLEX_FULL; /* Always set */ |
890 | |||
891 | return 0; | ||
870 | } | 892 | } |
871 | 893 | ||
872 | static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd) | 894 | static int rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd) |
873 | { | 895 | { |
874 | struct rtl8169_private *tp = netdev_priv(dev); | 896 | struct rtl8169_private *tp = netdev_priv(dev); |
875 | void __iomem *ioaddr = tp->mmio_addr; | 897 | |
876 | u8 status; | 898 | return mii_ethtool_gset(&tp->mii, cmd); |
877 | |||
878 | cmd->supported = SUPPORTED_10baseT_Half | | ||
879 | SUPPORTED_10baseT_Full | | ||
880 | SUPPORTED_100baseT_Half | | ||
881 | SUPPORTED_100baseT_Full | | ||
882 | SUPPORTED_1000baseT_Full | | ||
883 | SUPPORTED_Autoneg | | ||
884 | SUPPORTED_TP; | ||
885 | |||
886 | cmd->autoneg = 1; | ||
887 | cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg; | ||
888 | |||
889 | if (tp->phy_auto_nego_reg & ADVERTISE_10HALF) | ||
890 | cmd->advertising |= ADVERTISED_10baseT_Half; | ||
891 | if (tp->phy_auto_nego_reg & ADVERTISE_10FULL) | ||
892 | cmd->advertising |= ADVERTISED_10baseT_Full; | ||
893 | if (tp->phy_auto_nego_reg & ADVERTISE_100HALF) | ||
894 | cmd->advertising |= ADVERTISED_100baseT_Half; | ||
895 | if (tp->phy_auto_nego_reg & ADVERTISE_100FULL) | ||
896 | cmd->advertising |= ADVERTISED_100baseT_Full; | ||
897 | if (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL) | ||
898 | cmd->advertising |= ADVERTISED_1000baseT_Full; | ||
899 | |||
900 | status = RTL_R8(PHYstatus); | ||
901 | |||
902 | if (status & _1000bpsF) | ||
903 | cmd->speed = SPEED_1000; | ||
904 | else if (status & _100bps) | ||
905 | cmd->speed = SPEED_100; | ||
906 | else if (status & _10bps) | ||
907 | cmd->speed = SPEED_10; | ||
908 | |||
909 | if (status & TxFlowCtrl) | ||
910 | cmd->advertising |= ADVERTISED_Asym_Pause; | ||
911 | if (status & RxFlowCtrl) | ||
912 | cmd->advertising |= ADVERTISED_Pause; | ||
913 | |||
914 | cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ? | ||
915 | DUPLEX_FULL : DUPLEX_HALF; | ||
916 | } | 899 | } |
917 | 900 | ||
918 | static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 901 | static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
919 | { | 902 | { |
920 | struct rtl8169_private *tp = netdev_priv(dev); | 903 | struct rtl8169_private *tp = netdev_priv(dev); |
921 | unsigned long flags; | 904 | unsigned long flags; |
905 | int rc; | ||
922 | 906 | ||
923 | spin_lock_irqsave(&tp->lock, flags); | 907 | spin_lock_irqsave(&tp->lock, flags); |
924 | 908 | ||
925 | tp->get_settings(dev, cmd); | 909 | rc = tp->get_settings(dev, cmd); |
926 | 910 | ||
927 | spin_unlock_irqrestore(&tp->lock, flags); | 911 | spin_unlock_irqrestore(&tp->lock, flags); |
928 | return 0; | 912 | return rc; |
929 | } | 913 | } |
930 | 914 | ||
931 | static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs, | 915 | static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs, |
@@ -1513,7 +1497,7 @@ static const struct rtl_cfg_info { | |||
1513 | unsigned int align; | 1497 | unsigned int align; |
1514 | u16 intr_event; | 1498 | u16 intr_event; |
1515 | u16 napi_event; | 1499 | u16 napi_event; |
1516 | unsigned msi; | 1500 | unsigned features; |
1517 | } rtl_cfg_infos [] = { | 1501 | } rtl_cfg_infos [] = { |
1518 | [RTL_CFG_0] = { | 1502 | [RTL_CFG_0] = { |
1519 | .hw_start = rtl_hw_start_8169, | 1503 | .hw_start = rtl_hw_start_8169, |
@@ -1522,7 +1506,7 @@ static const struct rtl_cfg_info { | |||
1522 | .intr_event = SYSErr | LinkChg | RxOverflow | | 1506 | .intr_event = SYSErr | LinkChg | RxOverflow | |
1523 | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, | 1507 | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, |
1524 | .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, | 1508 | .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, |
1525 | .msi = 0 | 1509 | .features = RTL_FEATURE_GMII |
1526 | }, | 1510 | }, |
1527 | [RTL_CFG_1] = { | 1511 | [RTL_CFG_1] = { |
1528 | .hw_start = rtl_hw_start_8168, | 1512 | .hw_start = rtl_hw_start_8168, |
@@ -1531,7 +1515,7 @@ static const struct rtl_cfg_info { | |||
1531 | .intr_event = SYSErr | LinkChg | RxOverflow | | 1515 | .intr_event = SYSErr | LinkChg | RxOverflow | |
1532 | TxErr | TxOK | RxOK | RxErr, | 1516 | TxErr | TxOK | RxOK | RxErr, |
1533 | .napi_event = TxErr | TxOK | RxOK | RxOverflow, | 1517 | .napi_event = TxErr | TxOK | RxOK | RxOverflow, |
1534 | .msi = RTL_FEATURE_MSI | 1518 | .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI |
1535 | }, | 1519 | }, |
1536 | [RTL_CFG_2] = { | 1520 | [RTL_CFG_2] = { |
1537 | .hw_start = rtl_hw_start_8101, | 1521 | .hw_start = rtl_hw_start_8101, |
@@ -1540,7 +1524,7 @@ static const struct rtl_cfg_info { | |||
1540 | .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout | | 1524 | .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout | |
1541 | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, | 1525 | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, |
1542 | .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, | 1526 | .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, |
1543 | .msi = RTL_FEATURE_MSI | 1527 | .features = RTL_FEATURE_MSI |
1544 | } | 1528 | } |
1545 | }; | 1529 | }; |
1546 | 1530 | ||
@@ -1552,7 +1536,7 @@ static unsigned rtl_try_msi(struct pci_dev *pdev, void __iomem *ioaddr, | |||
1552 | u8 cfg2; | 1536 | u8 cfg2; |
1553 | 1537 | ||
1554 | cfg2 = RTL_R8(Config2) & ~MSIEnable; | 1538 | cfg2 = RTL_R8(Config2) & ~MSIEnable; |
1555 | if (cfg->msi) { | 1539 | if (cfg->features & RTL_FEATURE_MSI) { |
1556 | if (pci_enable_msi(pdev)) { | 1540 | if (pci_enable_msi(pdev)) { |
1557 | dev_info(&pdev->dev, "no MSI. Back to INTx.\n"); | 1541 | dev_info(&pdev->dev, "no MSI. Back to INTx.\n"); |
1558 | } else { | 1542 | } else { |
@@ -1578,6 +1562,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1578 | const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data; | 1562 | const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data; |
1579 | const unsigned int region = cfg->region; | 1563 | const unsigned int region = cfg->region; |
1580 | struct rtl8169_private *tp; | 1564 | struct rtl8169_private *tp; |
1565 | struct mii_if_info *mii; | ||
1581 | struct net_device *dev; | 1566 | struct net_device *dev; |
1582 | void __iomem *ioaddr; | 1567 | void __iomem *ioaddr; |
1583 | unsigned int i; | 1568 | unsigned int i; |
@@ -1602,6 +1587,14 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1602 | tp->pci_dev = pdev; | 1587 | tp->pci_dev = pdev; |
1603 | tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT); | 1588 | tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT); |
1604 | 1589 | ||
1590 | mii = &tp->mii; | ||
1591 | mii->dev = dev; | ||
1592 | mii->mdio_read = rtl_mdio_read; | ||
1593 | mii->mdio_write = rtl_mdio_write; | ||
1594 | mii->phy_id_mask = 0x1f; | ||
1595 | mii->reg_num_mask = 0x1f; | ||
1596 | mii->supports_gmii = !!(cfg->features & RTL_FEATURE_GMII); | ||
1597 | |||
1605 | /* enable device (incl. PCI PM wakeup and hotplug setup) */ | 1598 | /* enable device (incl. PCI PM wakeup and hotplug setup) */ |
1606 | rc = pci_enable_device(pdev); | 1599 | rc = pci_enable_device(pdev); |
1607 | if (rc < 0) { | 1600 | if (rc < 0) { |