mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
r8169: add support for phylink
Transfer old framework to phylink. Phylink can support fiber mode card which can not get link status or link speed from standard phy registers. Signed-off-by: Javen Xu <javen_xu@realsil.com.cn> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Link: https://patch.msgid.link/20260831053745.1197-4-javen_xu@realsil.com.cn Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
9f8cb9cbcd
commit
8a3c76523e
|
|
@ -86,8 +86,8 @@ config R8169
|
||||||
depends on PCI
|
depends on PCI
|
||||||
select FW_LOADER
|
select FW_LOADER
|
||||||
select CRC32
|
select CRC32
|
||||||
select PHYLIB
|
|
||||||
select REALTEK_PHY
|
select REALTEK_PHY
|
||||||
|
select PHYLINK
|
||||||
help
|
help
|
||||||
Say Y here if you have a Realtek Ethernet adapter belonging to
|
Say Y here if you have a Realtek Ethernet adapter belonging to
|
||||||
the following families:
|
the following families:
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/bitfield.h>
|
#include <linux/bitfield.h>
|
||||||
|
#include <linux/phylink.h>
|
||||||
#include <linux/prefetch.h>
|
#include <linux/prefetch.h>
|
||||||
#include <linux/ipv6.h>
|
#include <linux/ipv6.h>
|
||||||
#include <linux/unaligned.h>
|
#include <linux/unaligned.h>
|
||||||
|
|
@ -775,6 +776,8 @@ struct rtl8169_private {
|
||||||
struct r8169_led_classdev *leds;
|
struct r8169_led_classdev *leds;
|
||||||
|
|
||||||
u32 ocp_base;
|
u32 ocp_base;
|
||||||
|
struct phylink *phylink;
|
||||||
|
struct phylink_config phylink_config;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*rtl_generic_fct)(struct rtl8169_private *tp);
|
typedef void (*rtl_generic_fct)(struct rtl8169_private *tp);
|
||||||
|
|
@ -2253,7 +2256,7 @@ static int rtl8169_get_eee(struct net_device *dev, struct ethtool_keee *data)
|
||||||
if (!rtl_supports_eee(tp))
|
if (!rtl_supports_eee(tp))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
ret = phy_ethtool_get_eee(tp->phydev, data);
|
ret = phylink_ethtool_get_eee(tp->phylink, data);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
@ -2269,7 +2272,7 @@ static int rtl8169_set_eee(struct net_device *dev, struct ethtool_keee *data)
|
||||||
if (!rtl_supports_eee(tp))
|
if (!rtl_supports_eee(tp))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
return phy_ethtool_set_eee(tp->phydev, data);
|
return phylink_ethtool_set_eee(tp->phylink, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtl8169_get_ringparam(struct net_device *dev,
|
static void rtl8169_get_ringparam(struct net_device *dev,
|
||||||
|
|
@ -2300,13 +2303,8 @@ static void rtl8169_get_pauseparam(struct net_device *dev,
|
||||||
struct ethtool_pauseparam *data)
|
struct ethtool_pauseparam *data)
|
||||||
{
|
{
|
||||||
struct rtl8169_private *tp = netdev_priv(dev);
|
struct rtl8169_private *tp = netdev_priv(dev);
|
||||||
bool tx_pause, rx_pause;
|
|
||||||
|
|
||||||
phy_get_pause(tp->phydev, &tx_pause, &rx_pause);
|
phylink_ethtool_get_pauseparam(tp->phylink, data);
|
||||||
|
|
||||||
data->autoneg = tp->phydev->autoneg;
|
|
||||||
data->tx_pause = tx_pause ? 1 : 0;
|
|
||||||
data->rx_pause = rx_pause ? 1 : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rtl8169_set_pauseparam(struct net_device *dev,
|
static int rtl8169_set_pauseparam(struct net_device *dev,
|
||||||
|
|
@ -2314,12 +2312,10 @@ static int rtl8169_set_pauseparam(struct net_device *dev,
|
||||||
{
|
{
|
||||||
struct rtl8169_private *tp = netdev_priv(dev);
|
struct rtl8169_private *tp = netdev_priv(dev);
|
||||||
|
|
||||||
if (dev->mtu > ETH_DATA_LEN)
|
if (dev->mtu > ETH_DATA_LEN || data->autoneg == AUTONEG_DISABLE)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
phy_set_asym_pause(tp->phydev, data->rx_pause, data->tx_pause);
|
return phylink_ethtool_set_pauseparam(tp->phylink, data);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtl8169_get_eth_mac_stats(struct net_device *dev,
|
static void rtl8169_get_eth_mac_stats(struct net_device *dev,
|
||||||
|
|
@ -2385,6 +2381,14 @@ static void rtl8169_get_eth_ctrl_stats(struct net_device *dev,
|
||||||
le32_to_cpu(tp->counters->rx_unknown_opcode);
|
le32_to_cpu(tp->counters->rx_unknown_opcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rtl8169_get_link_ksettings(struct net_device *ndev,
|
||||||
|
struct ethtool_link_ksettings *cmd)
|
||||||
|
{
|
||||||
|
struct rtl8169_private *tp = netdev_priv(ndev);
|
||||||
|
|
||||||
|
return phylink_ethtool_ksettings_get(tp->phylink, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
static int rtl8169_set_link_ksettings(struct net_device *ndev,
|
static int rtl8169_set_link_ksettings(struct net_device *ndev,
|
||||||
const struct ethtool_link_ksettings *cmd)
|
const struct ethtool_link_ksettings *cmd)
|
||||||
{
|
{
|
||||||
|
|
@ -2394,7 +2398,7 @@ static int rtl8169_set_link_ksettings(struct net_device *ndev,
|
||||||
int speed = cmd->base.speed;
|
int speed = cmd->base.speed;
|
||||||
|
|
||||||
if (!tp->sfp_mode)
|
if (!tp->sfp_mode)
|
||||||
return phy_ethtool_ksettings_set(phydev, cmd);
|
return phylink_ethtool_ksettings_set(tp->phylink, cmd);
|
||||||
|
|
||||||
if (cmd->base.autoneg != AUTONEG_DISABLE)
|
if (cmd->base.autoneg != AUTONEG_DISABLE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
@ -2415,6 +2419,13 @@ static int rtl8169_set_link_ksettings(struct net_device *ndev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rtl8169_nway_reset(struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct rtl8169_private *tp = netdev_priv(dev);
|
||||||
|
|
||||||
|
return phylink_ethtool_nway_reset(tp->phylink);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct ethtool_ops rtl8169_ethtool_ops = {
|
static const struct ethtool_ops rtl8169_ethtool_ops = {
|
||||||
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
||||||
ETHTOOL_COALESCE_MAX_FRAMES,
|
ETHTOOL_COALESCE_MAX_FRAMES,
|
||||||
|
|
@ -2430,10 +2441,10 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
|
||||||
.get_sset_count = rtl8169_get_sset_count,
|
.get_sset_count = rtl8169_get_sset_count,
|
||||||
.get_ethtool_stats = rtl8169_get_ethtool_stats,
|
.get_ethtool_stats = rtl8169_get_ethtool_stats,
|
||||||
.get_ts_info = ethtool_op_get_ts_info,
|
.get_ts_info = ethtool_op_get_ts_info,
|
||||||
.nway_reset = phy_ethtool_nway_reset,
|
.nway_reset = rtl8169_nway_reset,
|
||||||
.get_eee = rtl8169_get_eee,
|
.get_eee = rtl8169_get_eee,
|
||||||
.set_eee = rtl8169_set_eee,
|
.set_eee = rtl8169_set_eee,
|
||||||
.get_link_ksettings = phy_ethtool_get_link_ksettings,
|
.get_link_ksettings = rtl8169_get_link_ksettings,
|
||||||
.set_link_ksettings = rtl8169_set_link_ksettings,
|
.set_link_ksettings = rtl8169_set_link_ksettings,
|
||||||
.get_ringparam = rtl8169_get_ringparam,
|
.get_ringparam = rtl8169_get_ringparam,
|
||||||
.get_pause_stats = rtl8169_get_pause_stats,
|
.get_pause_stats = rtl8169_get_pause_stats,
|
||||||
|
|
@ -2656,15 +2667,6 @@ static void rtl_jumbo_config(struct rtl8169_private *tp)
|
||||||
|
|
||||||
if (pci_is_pcie(tp->pci_dev) && tp->supports_gmii)
|
if (pci_is_pcie(tp->pci_dev) && tp->supports_gmii)
|
||||||
pcie_set_readrq(tp->pci_dev, readrq);
|
pcie_set_readrq(tp->pci_dev, readrq);
|
||||||
|
|
||||||
/* Chip doesn't support pause in jumbo mode */
|
|
||||||
if (jumbo) {
|
|
||||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
|
||||||
tp->phydev->advertising);
|
|
||||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
|
||||||
tp->phydev->advertising);
|
|
||||||
phy_start_aneg(tp->phydev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_RTL_COND(rtl_chipcmd_cond)
|
DECLARE_RTL_COND(rtl_chipcmd_cond)
|
||||||
|
|
@ -2779,7 +2781,7 @@ static void rtl_prepare_power_down(struct rtl8169_private *tp)
|
||||||
rtl_ephy_write(tp, 0x19, 0xff64);
|
rtl_ephy_write(tp, 0x19, 0xff64);
|
||||||
|
|
||||||
if (device_may_wakeup(tp_to_dev(tp))) {
|
if (device_may_wakeup(tp_to_dev(tp))) {
|
||||||
phy_speed_down(tp->phydev, false);
|
phylink_speed_down(tp->phylink, false);
|
||||||
rtl_wol_enable_rx(tp);
|
rtl_wol_enable_rx(tp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2831,6 +2833,16 @@ static void rtl8169_set_magic_reg(struct rtl8169_private *tp)
|
||||||
RTL_W32(tp, 0x7c, val);
|
RTL_W32(tp, 0x7c, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||||
|
{
|
||||||
|
struct rtl8169_private *tp = netdev_priv(dev);
|
||||||
|
|
||||||
|
if (!netif_running(dev))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
return phylink_mii_ioctl(tp->phylink, ifr, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
static void rtl_set_rx_mode(struct net_device *dev)
|
static void rtl_set_rx_mode(struct net_device *dev)
|
||||||
{
|
{
|
||||||
u32 rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;
|
u32 rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;
|
||||||
|
|
@ -4138,12 +4150,23 @@ static void rtl_hw_start(struct rtl8169_private *tp)
|
||||||
static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
|
static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
|
||||||
{
|
{
|
||||||
struct rtl8169_private *tp = netdev_priv(dev);
|
struct rtl8169_private *tp = netdev_priv(dev);
|
||||||
|
bool jumbo_before = dev->mtu > ETH_DATA_LEN;
|
||||||
|
bool jumbo_after = new_mtu > ETH_DATA_LEN;
|
||||||
|
|
||||||
WRITE_ONCE(dev->mtu, new_mtu);
|
WRITE_ONCE(dev->mtu, new_mtu);
|
||||||
netdev_update_features(dev);
|
netdev_update_features(dev);
|
||||||
rtl_jumbo_config(tp);
|
rtl_jumbo_config(tp);
|
||||||
rtl_set_eee_txidle_timer(tp);
|
rtl_set_eee_txidle_timer(tp);
|
||||||
|
|
||||||
|
if (jumbo_before != jumbo_after) {
|
||||||
|
unsigned long caps = 0;
|
||||||
|
|
||||||
|
if (!jumbo_after)
|
||||||
|
caps |= (MAC_SYM_PAUSE | MAC_ASYM_PAUSE);
|
||||||
|
|
||||||
|
phylink_update_mac_pause_capabilities(tp->phylink, caps);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4929,9 +4952,6 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
|
||||||
|
|
||||||
static void rtl_enable_tx_lpi(struct rtl8169_private *tp, bool enable)
|
static void rtl_enable_tx_lpi(struct rtl8169_private *tp, bool enable)
|
||||||
{
|
{
|
||||||
if (!rtl_supports_eee(tp))
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (tp->mac_version) {
|
switch (tp->mac_version) {
|
||||||
case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_52:
|
case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_52:
|
||||||
/* Adjust EEE LED frequency */
|
/* Adjust EEE LED frequency */
|
||||||
|
|
@ -4962,41 +4982,15 @@ static void rtl_enable_tx_lpi(struct rtl8169_private *tp, bool enable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void r8169_phylink_handler(struct net_device *ndev)
|
|
||||||
{
|
|
||||||
struct rtl8169_private *tp = netdev_priv(ndev);
|
|
||||||
struct device *d = tp_to_dev(tp);
|
|
||||||
|
|
||||||
tp->speed = tp->phydev->speed;
|
|
||||||
if (netif_carrier_ok(ndev)) {
|
|
||||||
rtl_link_chg_patch(tp, tp->speed);
|
|
||||||
rtl_enable_tx_lpi(tp, tp->phydev->enable_tx_lpi);
|
|
||||||
pm_request_resume(d);
|
|
||||||
} else {
|
|
||||||
pm_runtime_idle(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
phy_print_status(tp->phydev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int r8169_phy_connect(struct rtl8169_private *tp)
|
static int r8169_phy_connect(struct rtl8169_private *tp)
|
||||||
{
|
{
|
||||||
struct phy_device *phydev = tp->phydev;
|
|
||||||
phy_interface_t phy_mode;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
phy_mode = tp->supports_gmii ? PHY_INTERFACE_MODE_GMII :
|
ret = phylink_connect_phy(tp->phylink, tp->phydev);
|
||||||
PHY_INTERFACE_MODE_MII;
|
if (ret) {
|
||||||
|
netdev_err(tp->dev, "failed to connect phy\n");
|
||||||
ret = phy_connect_direct(tp->dev, phydev, r8169_phylink_handler,
|
|
||||||
phy_mode);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
if (!tp->supports_gmii)
|
|
||||||
phy_set_max_speed(phydev, SPEED_100);
|
|
||||||
|
|
||||||
phy_attached_info(phydev);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -5007,8 +5001,6 @@ static void rtl8169_down(struct rtl8169_private *tp)
|
||||||
/* Clear all task flags */
|
/* Clear all task flags */
|
||||||
bitmap_zero(tp->wk.flags, RTL_FLAG_MAX);
|
bitmap_zero(tp->wk.flags, RTL_FLAG_MAX);
|
||||||
|
|
||||||
phy_stop(tp->phydev);
|
|
||||||
|
|
||||||
/* Reset SerDes PHY to bring down fiber link */
|
/* Reset SerDes PHY to bring down fiber link */
|
||||||
if (tp->sfp_mode)
|
if (tp->sfp_mode)
|
||||||
rtl_sfp_reset(tp);
|
rtl_sfp_reset(tp);
|
||||||
|
|
@ -5038,8 +5030,6 @@ static void rtl8169_up(struct rtl8169_private *tp)
|
||||||
napi_enable(&tp->napi);
|
napi_enable(&tp->napi);
|
||||||
enable_work(&tp->wk.work);
|
enable_work(&tp->wk.work);
|
||||||
rtl_reset_work(tp);
|
rtl_reset_work(tp);
|
||||||
|
|
||||||
phy_start(tp->phydev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rtl8169_close(struct net_device *dev)
|
static int rtl8169_close(struct net_device *dev)
|
||||||
|
|
@ -5049,13 +5039,14 @@ static int rtl8169_close(struct net_device *dev)
|
||||||
|
|
||||||
pm_runtime_get_sync(&pdev->dev);
|
pm_runtime_get_sync(&pdev->dev);
|
||||||
|
|
||||||
|
phylink_stop(tp->phylink);
|
||||||
netif_stop_queue(dev);
|
netif_stop_queue(dev);
|
||||||
rtl8169_down(tp);
|
rtl8169_down(tp);
|
||||||
rtl8169_rx_clear(tp);
|
rtl8169_rx_clear(tp);
|
||||||
|
|
||||||
free_irq(tp->irq, tp);
|
free_irq(tp->irq, tp);
|
||||||
|
|
||||||
phy_disconnect(tp->phydev);
|
phylink_disconnect_phy(tp->phylink);
|
||||||
|
|
||||||
dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
|
dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
|
||||||
tp->RxPhyAddr);
|
tp->RxPhyAddr);
|
||||||
|
|
@ -5117,6 +5108,7 @@ static int rtl_open(struct net_device *dev)
|
||||||
goto err_free_irq;
|
goto err_free_irq;
|
||||||
|
|
||||||
rtl8169_up(tp);
|
rtl8169_up(tp);
|
||||||
|
phylink_start(tp->phylink);
|
||||||
rtl8169_init_counter_offsets(tp);
|
rtl8169_init_counter_offsets(tp);
|
||||||
netif_start_queue(dev);
|
netif_start_queue(dev);
|
||||||
out:
|
out:
|
||||||
|
|
@ -5288,6 +5280,7 @@ static void rtl_remove_one(struct pci_dev *pdev)
|
||||||
r8169_remove_leds(tp->leds);
|
r8169_remove_leds(tp->leds);
|
||||||
|
|
||||||
unregister_netdev(tp->dev);
|
unregister_netdev(tp->dev);
|
||||||
|
phylink_destroy(tp->phylink);
|
||||||
|
|
||||||
if (tp->dash_type != RTL_DASH_NONE)
|
if (tp->dash_type != RTL_DASH_NONE)
|
||||||
rtl8168_driver_stop(tp);
|
rtl8168_driver_stop(tp);
|
||||||
|
|
@ -5310,7 +5303,7 @@ static const struct net_device_ops rtl_netdev_ops = {
|
||||||
.ndo_fix_features = rtl8169_fix_features,
|
.ndo_fix_features = rtl8169_fix_features,
|
||||||
.ndo_set_features = rtl8169_set_features,
|
.ndo_set_features = rtl8169_set_features,
|
||||||
.ndo_set_mac_address = rtl_set_mac_address,
|
.ndo_set_mac_address = rtl_set_mac_address,
|
||||||
.ndo_eth_ioctl = phy_do_ioctl_running,
|
.ndo_eth_ioctl = rtl8169_ioctl,
|
||||||
.ndo_set_rx_mode = rtl_set_rx_mode,
|
.ndo_set_rx_mode = rtl_set_rx_mode,
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
.ndo_poll_controller = rtl8169_netpoll,
|
.ndo_poll_controller = rtl8169_netpoll,
|
||||||
|
|
@ -5474,16 +5467,6 @@ static int r8169_mdio_register(struct rtl8169_private *tp)
|
||||||
return -EUNATCH;
|
return -EUNATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
tp->phydev->mac_managed_pm = true;
|
|
||||||
if (rtl_supports_eee(tp))
|
|
||||||
phy_support_eee(tp->phydev);
|
|
||||||
phy_support_asym_pause(tp->phydev);
|
|
||||||
|
|
||||||
/* mimic behavior of r8125/r8126 vendor drivers */
|
|
||||||
if (tp->mac_version == RTL_GIGA_MAC_VER_61)
|
|
||||||
phy_disable_eee_mode(tp->phydev,
|
|
||||||
ETHTOOL_LINK_MODE_2500baseT_Full_BIT);
|
|
||||||
|
|
||||||
/* PHY will be woken up in rtl_open() */
|
/* PHY will be woken up in rtl_open() */
|
||||||
phy_suspend(tp->phydev);
|
phy_suspend(tp->phydev);
|
||||||
|
|
||||||
|
|
@ -5599,6 +5582,159 @@ static bool rtl_aspm_is_safe(struct rtl8169_private *tp)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rtl_mac_link_down(struct phylink_config *config, unsigned int mode,
|
||||||
|
phy_interface_t interface)
|
||||||
|
{
|
||||||
|
struct rtl8169_private *tp = container_of(config,
|
||||||
|
struct rtl8169_private,
|
||||||
|
phylink_config);
|
||||||
|
|
||||||
|
tp->speed = SPEED_UNKNOWN;
|
||||||
|
pm_runtime_idle(tp_to_dev(tp));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtl_mac_link_up(struct phylink_config *config,
|
||||||
|
struct phy_device *phydev,
|
||||||
|
unsigned int mode,
|
||||||
|
phy_interface_t interface,
|
||||||
|
int speed, int duplex,
|
||||||
|
bool tx_pause, bool rx_pause)
|
||||||
|
{
|
||||||
|
struct rtl8169_private *tp = container_of(config,
|
||||||
|
struct rtl8169_private,
|
||||||
|
phylink_config);
|
||||||
|
struct device *d = tp_to_dev(tp);
|
||||||
|
|
||||||
|
tp->speed = speed;
|
||||||
|
rtl_link_chg_patch(tp, speed);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: This hardware does not support forcing flow control.
|
||||||
|
* Tx/Rx pause is completely hardwired: if autoneg is ON, hardware
|
||||||
|
* handles it automatically based on PHY result; if autoneg is OFF,
|
||||||
|
* hardware forces pause to be disabled. No software override exists.
|
||||||
|
*/
|
||||||
|
pm_request_resume(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct phylink_pcs *rtl_mac_select_pcs(struct phylink_config *config,
|
||||||
|
phy_interface_t interface)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtl_mac_config(struct phylink_config *config, unsigned int mode,
|
||||||
|
const struct phylink_link_state *state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtl_mac_disable_tx_lpi(struct phylink_config *config)
|
||||||
|
{
|
||||||
|
struct rtl8169_private *tp = container_of(config,
|
||||||
|
struct rtl8169_private,
|
||||||
|
phylink_config);
|
||||||
|
|
||||||
|
rtl_enable_tx_lpi(tp, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rtl_mac_enable_tx_lpi(struct phylink_config *config,
|
||||||
|
u32 timer,
|
||||||
|
bool tx_clk_stop)
|
||||||
|
{
|
||||||
|
struct rtl8169_private *tp = container_of(config,
|
||||||
|
struct rtl8169_private,
|
||||||
|
phylink_config);
|
||||||
|
|
||||||
|
rtl_enable_tx_lpi(tp, true);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct phylink_mac_ops rtl_phylink_mac_ops = {
|
||||||
|
.mac_select_pcs = rtl_mac_select_pcs,
|
||||||
|
.mac_config = rtl_mac_config,
|
||||||
|
.mac_link_down = rtl_mac_link_down,
|
||||||
|
.mac_link_up = rtl_mac_link_up,
|
||||||
|
.mac_disable_tx_lpi = rtl_mac_disable_tx_lpi,
|
||||||
|
.mac_enable_tx_lpi = rtl_mac_enable_tx_lpi,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned long rtl8169_get_lpi_caps(struct rtl8169_private *tp)
|
||||||
|
{
|
||||||
|
unsigned long caps = 0;
|
||||||
|
|
||||||
|
if (!rtl_supports_eee(tp))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
caps |= MAC_100FD | MAC_1000FD;
|
||||||
|
|
||||||
|
/* mimic behavior of r8125/r8126 vendor drivers
|
||||||
|
* RTL_GIGA_MAC_VER_61 doesn't support 2.5G eee
|
||||||
|
*/
|
||||||
|
if (tp->mac_version >= RTL_GIGA_MAC_VER_63)
|
||||||
|
caps |= MAC_2500FD;
|
||||||
|
if (tp->mac_version >= RTL_GIGA_MAC_VER_70)
|
||||||
|
caps |= MAC_5000FD;
|
||||||
|
if (tp->mac_version == RTL_GIGA_MAC_VER_80)
|
||||||
|
caps |= MAC_10000FD;
|
||||||
|
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rtl_init_phylink(struct rtl8169_private *tp)
|
||||||
|
{
|
||||||
|
struct phylink *pl;
|
||||||
|
phy_interface_t phy_mode;
|
||||||
|
|
||||||
|
tp->phylink_config.dev = &tp->dev->dev;
|
||||||
|
tp->phylink_config.type = PHYLINK_NETDEV;
|
||||||
|
tp->phylink_config.mac_managed_pm = true;
|
||||||
|
tp->phylink_config.lpi_capabilities = rtl8169_get_lpi_caps(tp);
|
||||||
|
tp->phylink_config.mac_capabilities |= MAC_ASYM_PAUSE | MAC_SYM_PAUSE;
|
||||||
|
|
||||||
|
if (tp->sfp_mode) {
|
||||||
|
phy_mode = PHY_INTERFACE_MODE_INTERNAL;
|
||||||
|
tp->phylink_config.mac_capabilities |= MAC_10000FD;
|
||||||
|
} else {
|
||||||
|
tp->phylink_config.mac_capabilities |= MAC_10 | MAC_100;
|
||||||
|
|
||||||
|
if (tp->mac_version == RTL_GIGA_MAC_VER_80)
|
||||||
|
tp->phylink_config.mac_capabilities |= MAC_1000FD |
|
||||||
|
MAC_2500FD |
|
||||||
|
MAC_5000FD |
|
||||||
|
MAC_10000FD;
|
||||||
|
else if (tp->mac_version == RTL_GIGA_MAC_VER_70)
|
||||||
|
tp->phylink_config.mac_capabilities |= MAC_1000FD |
|
||||||
|
MAC_2500FD |
|
||||||
|
MAC_5000FD;
|
||||||
|
else if (tp->mac_version >= RTL_GIGA_MAC_VER_61)
|
||||||
|
tp->phylink_config.mac_capabilities |= MAC_1000FD |
|
||||||
|
MAC_2500FD;
|
||||||
|
else
|
||||||
|
if (tp->supports_gmii)
|
||||||
|
tp->phylink_config.mac_capabilities |= MAC_1000FD;
|
||||||
|
|
||||||
|
if (tp->mac_version < RTL_GIGA_MAC_VER_61)
|
||||||
|
phy_mode = tp->supports_gmii ? PHY_INTERFACE_MODE_GMII :
|
||||||
|
PHY_INTERFACE_MODE_MII;
|
||||||
|
else
|
||||||
|
phy_mode = PHY_INTERFACE_MODE_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
__set_bit(phy_mode, tp->phylink_config.supported_interfaces);
|
||||||
|
if (tp->phylink_config.lpi_capabilities)
|
||||||
|
__set_bit(phy_mode, tp->phylink_config.lpi_interfaces);
|
||||||
|
|
||||||
|
pl = phylink_create(&tp->phylink_config, tp_to_dev(tp)->fwnode,
|
||||||
|
phy_mode, &rtl_phylink_mac_ops);
|
||||||
|
if (IS_ERR(pl))
|
||||||
|
return PTR_ERR(pl);
|
||||||
|
|
||||||
|
tp->phylink = pl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||||
{
|
{
|
||||||
const struct rtl_chip_info *chip;
|
const struct rtl_chip_info *chip;
|
||||||
|
|
@ -5789,13 +5925,21 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||||
|
|
||||||
pci_set_drvdata(pdev, tp);
|
pci_set_drvdata(pdev, tp);
|
||||||
|
|
||||||
rc = r8169_mdio_register(tp);
|
rc = rtl_init_phylink(tp);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
rc = register_netdev(dev);
|
rc = r8169_mdio_register(tp);
|
||||||
if (rc)
|
if (rc) {
|
||||||
|
phylink_destroy(tp->phylink);
|
||||||
return rc;
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = register_netdev(dev);
|
||||||
|
if (rc) {
|
||||||
|
phylink_destroy(tp->phylink);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_R8169_LEDS)) {
|
if (IS_ENABLED(CONFIG_R8169_LEDS)) {
|
||||||
if (rtl_is_8125(tp))
|
if (rtl_is_8125(tp))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user