diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig index 9b0f4f9631db..5818a9a500a8 100644 --- a/drivers/net/ethernet/realtek/Kconfig +++ b/drivers/net/ethernet/realtek/Kconfig @@ -86,8 +86,8 @@ config R8169 depends on PCI select FW_LOADER select CRC32 - select PHYLIB select REALTEK_PHY + select PHYLINK help Say Y here if you have a Realtek Ethernet adapter belonging to the following families: diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index ec4fc21fa21f..5415ff62a286 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -26,12 +26,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include "r8169.h" #include "r8169_firmware.h" @@ -96,6 +96,26 @@ #define JUMBO_9K (9 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN) #define JUMBO_16K (SZ_16K - VLAN_ETH_HLEN - ETH_FCS_LEN) +#define R8127_SDS_CMD 0x2348 +#define R8127_SDS_ADDR 0x234a +#define R8127_SDS_DATA_IN 0x234c +#define R8127_SDS_DATA_OUT 0x234e +#define R8127_SDS_CMD_EXEC BIT(0) +#define R8127_SDS_CMD_WE BIT(1) +#define OCP_SDS_ADDR_REG 0xeb10 +#define OCP_SDS_CMD_REG 0xeb0e +#define OCP_SDS_DATA_REG 0xeb14 +#define SDS_CMD_READ 0x0001 +#define RTL_SDS_C22_BASE 0x40 +#define RTL_SDS_C45_BASE 0x0080 +#define RTL_PKG_DETECT 0xdc00 +#define RTL_PKG_DETECT_MASK 0x0078 +#define RTL_PKG_DETECT_8116AF 0x0030 +#define RTL_INT_HW_ID 0xd006 +#define RTL_INT_HW_ID_MASK 0x00ff +#define RTL_INT_HW_ID_8116AF 0x0000 +#define RTL_PM_CTRL_D3HOT 0x03 + static const struct rtl_chip_info { u32 mask; u32 val; @@ -334,11 +354,13 @@ enum rtl_registers { ALDPS_LTR = 0xe0a2, LTR_OBFF_LOCK = 0xe032, LTR_SNOOP = 0xe034, + SEND_LTR_MSG = 0xe038, #define ALDPS_LTR_EN BIT(0) #define LTR_OBFF_LOCK_EN BIT(0) #define LINK_SPEED_CHANGE_EN BIT(14) #define LTR_SNOOP_EN GENMASK(15, 14) +#define LTR_MSG_EN BIT(0) }; enum rtl8168_8101_registers { @@ -728,6 +750,12 @@ enum rtl_dash_type { RTL_DASH_25_BP, }; +enum rtl_sfp_mode { + RTL_SFP_NONE, + RTL_SFP_8168_AF, + RTL_SFP_8127_ATF, +}; + struct rtl8169_private { void __iomem *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; @@ -736,6 +764,7 @@ struct rtl8169_private { struct napi_struct napi; enum mac_version mac_version; enum rtl_dash_type dash_type; + enum rtl_sfp_mode sfp_mode; u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ u32 dirty_tx; @@ -750,6 +779,7 @@ struct rtl8169_private { u32 irq_mask; int irq; struct clk *clk; + int speed; struct { DECLARE_BITMAP(flags, RTL_FLAG_MAX); @@ -762,7 +792,6 @@ struct rtl8169_private { unsigned supports_gmii:1; unsigned aspm_manageable:1; unsigned dash_enabled:1; - bool sfp_mode:1; dma_addr_t counters_phys_addr; struct rtl8169_counters *counters; struct rtl8169_tc_offsets tc_offset; @@ -774,6 +803,9 @@ struct rtl8169_private { struct r8169_led_classdev *leds; u32 ocp_base; + struct phylink *phylink; + struct phylink_config phylink_config; + struct phylink_pcs pcs; }; typedef void (*rtl_generic_fct)(struct rtl8169_private *tp); @@ -1128,10 +1160,6 @@ static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg) if (rtl_ocp_reg_failure(reg)) return 0; - /* Return dummy MII_PHYSID2 in SFP mode to match SFP PHY driver */ - if (tp->sfp_mode && reg == (OCP_STD_PHY_BASE + 2 * MII_PHYSID2)) - return PHY_ID_RTL_DUMMY_SFP & 0xffff; - RTL_W32(tp, GPHY_OCP, reg << 15); return rtl_loop_wait_high(tp, &rtl_ocp_gphy_cond, 25, 10) ? @@ -1199,6 +1227,75 @@ static void r8127_sfp_sds_phy_reset(struct rtl8169_private *tp) usleep_range(10, 20); } +DECLARE_RTL_COND(r8127_sds_cmd_cond) +{ + return RTL_R16(tp, R8127_SDS_CMD) & R8127_SDS_CMD_EXEC; +} + +static int r8127_sds_read(struct rtl8169_private *tp, u16 index, + u16 page, u16 reg) +{ + u16 addr = (index << 11) | (page << 5) | reg; + + RTL_W16(tp, R8127_SDS_ADDR, addr); + RTL_W16(tp, R8127_SDS_CMD, R8127_SDS_CMD_EXEC); + + if (rtl_loop_wait_low(tp, &r8127_sds_cmd_cond, 10, 100)) + return RTL_R16(tp, R8127_SDS_DATA_OUT); + + return -ETIMEDOUT; +} + +static int r8127_sds_write(struct rtl8169_private *tp, u16 index, u16 page, + u16 reg, u16 val) +{ + u16 addr = (index << 11) | (page << 5) | reg; + + RTL_W16(tp, R8127_SDS_DATA_IN, val); + RTL_W16(tp, R8127_SDS_ADDR, addr); + RTL_W16(tp, R8127_SDS_CMD, R8127_SDS_CMD_EXEC | R8127_SDS_CMD_WE); + + if (rtl_loop_wait_low(tp, &r8127_sds_cmd_cond, 10, 100)) + return 0; + + return -ETIMEDOUT; +} + +static void r8127_sds_modify(struct rtl8169_private *tp, u16 index, u16 page, + u16 reg, u16 clearmask, u16 setmask) +{ + int val = r8127_sds_read(tp, index, page, reg); + + if (val < 0) + return; + + val = (val & ~clearmask) | setmask; + r8127_sds_write(tp, index, page, reg, val); +} + +static void r8127_sfp_init_1g(struct rtl8169_private *tp) +{ + int val; + + r8127_sfp_sds_phy_reset(tp); + + r8127_sds_modify(tp, 0, 1, 31, 0, BIT(3)); + r8127_sds_modify(tp, 0, 2, 0, BIT(13) | BIT(12) | BIT(6), + BIT(12) | BIT(6)); + r8127_sds_modify(tp, 0, 0, 4, 0, BIT(2)); + + RTL_W16(tp, 0x233a, 0x8004); + RTL_W16(tp, 0x233e, (RTL_R16(tp, 0x233e) & ~0x3003) | 0x0002); + + r8168_phy_ocp_write(tp, 0xc40a, 0x0000); + r8168_phy_ocp_write(tp, 0xc466, 0x0000); + r8168_phy_ocp_write(tp, 0xc808, 0x0000); + r8168_phy_ocp_write(tp, 0xc80a, 0x0000); + + val = r8168_phy_ocp_read(tp, 0xc804); + r8168_phy_ocp_write(tp, 0xc804, (val & ~0x000f) | 0x000c); +} + static void r8127_sfp_init_10g(struct rtl8169_private *tp) { int val; @@ -1217,12 +1314,6 @@ static void r8127_sfp_init_10g(struct rtl8169_private *tp) r8168_phy_ocp_write(tp, 0xc804, (val & ~0x000f) | 0x000c); } -static void rtl_sfp_init(struct rtl8169_private *tp) -{ - if (tp->mac_version == RTL_GIGA_MAC_VER_80) - r8127_sfp_init_10g(tp); -} - static void rtl_sfp_reset(struct rtl8169_private *tp) { if (tp->mac_version == RTL_GIGA_MAC_VER_80) @@ -1283,6 +1374,15 @@ static void mac_mcu_write(struct rtl8169_private *tp, int reg, int value) r8168_mac_ocp_write(tp, tp->ocp_base + reg, value); } +static bool rtl_is_8116af(struct rtl8169_private *tp) +{ + return tp->mac_version == RTL_GIGA_MAC_VER_52 && + (r8168_mac_ocp_read(tp, RTL_PKG_DETECT) & RTL_PKG_DETECT_MASK) == + RTL_PKG_DETECT_8116AF && + (r8168_mac_ocp_read(tp, RTL_INT_HW_ID) & RTL_INT_HW_ID_MASK) == + RTL_INT_HW_ID_8116AF; +} + static int mac_mcu_read(struct rtl8169_private *tp, int reg) { return r8168_mac_ocp_read(tp, tp->ocp_base + reg); @@ -1578,6 +1678,20 @@ static bool rtl_dash_is_enabled(struct rtl8169_private *tp) } } +static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private *tp) +{ + if (rtl_is_8125(tp)) { + u16 data = r8168_mac_ocp_read(tp, RTL_INT_HW_ID); + + if ((data & 0xff) == 0x07) + return RTL_SFP_8127_ATF; + } else if (rtl_is_8116af(tp)) { + return RTL_SFP_8168_AF; + } + + return RTL_SFP_NONE; +} + static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp) { switch (tp->mac_version) { @@ -1673,16 +1787,14 @@ static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp) rtl_pci_commit(tp); } -static void rtl_link_chg_patch(struct rtl8169_private *tp) +static void rtl_link_chg_patch(struct rtl8169_private *tp, int speed) { - struct phy_device *phydev = tp->phydev; - if (tp->mac_version == RTL_GIGA_MAC_VER_34 || tp->mac_version == RTL_GIGA_MAC_VER_38) { - if (phydev->speed == SPEED_1000) { + if (speed == SPEED_1000) { rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011); rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005); - } else if (phydev->speed == SPEED_100) { + } else if (speed == SPEED_100) { rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f); rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005); } else { @@ -1692,7 +1804,7 @@ static void rtl_link_chg_patch(struct rtl8169_private *tp) rtl_reset_packet_filter(tp); } else if (tp->mac_version == RTL_GIGA_MAC_VER_35 || tp->mac_version == RTL_GIGA_MAC_VER_36) { - if (phydev->speed == SPEED_1000) { + if (speed == SPEED_1000) { rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011); rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005); } else { @@ -1700,7 +1812,7 @@ static void rtl_link_chg_patch(struct rtl8169_private *tp) rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f); } } else if (tp->mac_version == RTL_GIGA_MAC_VER_37) { - if (phydev->speed == SPEED_10) { + if (speed == SPEED_10) { rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x4d02); rtl_eri_write(tp, 0x1dc, ERIAR_MASK_0011, 0x0060a); } else { @@ -2074,11 +2186,11 @@ rtl_coalesce_info(struct rtl8169_private *tp) ci = rtl_coalesce_info_8168_8136; /* if speed is unknown assume highest one */ - if (tp->phydev->speed == SPEED_UNKNOWN) + if (tp->speed == SPEED_UNKNOWN) return ci; for (; ci->speed; ci++) { - if (tp->phydev->speed == ci->speed) + if (tp->speed == ci->speed) return ci; } @@ -2236,7 +2348,7 @@ static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp) static unsigned int r8169_get_tx_lpi_timer_us(struct rtl8169_private *tp) { - unsigned int speed = tp->phydev->speed; + unsigned int speed = tp->speed; unsigned int timer = tp->tx_lpi_timer; if (!timer || speed == SPEED_UNKNOWN) @@ -2254,7 +2366,7 @@ static int rtl8169_get_eee(struct net_device *dev, struct ethtool_keee *data) if (!rtl_supports_eee(tp)) return -EOPNOTSUPP; - ret = phy_ethtool_get_eee(tp->phydev, data); + ret = phylink_ethtool_get_eee(tp->phylink, data); if (ret) return ret; @@ -2270,7 +2382,7 @@ static int rtl8169_set_eee(struct net_device *dev, struct ethtool_keee *data) if (!rtl_supports_eee(tp)) 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, @@ -2301,13 +2413,8 @@ static void rtl8169_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *data) { struct rtl8169_private *tp = netdev_priv(dev); - bool tx_pause, rx_pause; - phy_get_pause(tp->phydev, &tx_pause, &rx_pause); - - data->autoneg = tp->phydev->autoneg; - data->tx_pause = tx_pause ? 1 : 0; - data->rx_pause = rx_pause ? 1 : 0; + phylink_ethtool_get_pauseparam(tp->phylink, data); } static int rtl8169_set_pauseparam(struct net_device *dev, @@ -2315,12 +2422,10 @@ static int rtl8169_set_pauseparam(struct net_device *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; - phy_set_asym_pause(tp->phydev, data->rx_pause, data->tx_pause); - - return 0; + return phylink_ethtool_set_pauseparam(tp->phylink, data); } static void rtl8169_get_eth_mac_stats(struct net_device *dev, @@ -2386,34 +2491,27 @@ static void rtl8169_get_eth_ctrl_stats(struct net_device *dev, 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, const struct ethtool_link_ksettings *cmd) { struct rtl8169_private *tp = netdev_priv(ndev); - struct phy_device *phydev = tp->phydev; - int duplex = cmd->base.duplex; - int speed = cmd->base.speed; - 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) - return -EINVAL; +static int rtl8169_nway_reset(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); - if (!phy_check_valid(speed, duplex, phydev->supported)) - return -EINVAL; - - mutex_lock(&phydev->lock); - - phydev->autoneg = AUTONEG_DISABLE; - phydev->speed = speed; - phydev->duplex = duplex; - - rtl_sfp_init(tp); - - mutex_unlock(&phydev->lock); - - return 0; + return phylink_ethtool_nway_reset(tp->phylink); } static const struct ethtool_ops rtl8169_ethtool_ops = { @@ -2431,10 +2529,10 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .get_sset_count = rtl8169_get_sset_count, .get_ethtool_stats = rtl8169_get_ethtool_stats, .get_ts_info = ethtool_op_get_ts_info, - .nway_reset = phy_ethtool_nway_reset, + .nway_reset = rtl8169_nway_reset, .get_eee = rtl8169_get_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, .get_ringparam = rtl8169_get_ringparam, .get_pause_stats = rtl8169_get_pause_stats, @@ -2499,9 +2597,10 @@ void r8169_apply_firmware(struct rtl8169_private *tp) tp->ocp_base = OCP_STD_PHY_BASE; /* PHY soft reset may still be in progress */ - phy_read_poll_timeout(tp->phydev, MII_BMCR, val, - !(val & BMCR_RESET), - 50000, 600000, true); + if (tp->phydev) + phy_read_poll_timeout(tp->phydev, MII_BMCR, val, + !(val & BMCR_RESET), + 50000, 600000, true); } } @@ -2538,6 +2637,8 @@ static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag) static void rtl8169_init_phy(struct rtl8169_private *tp) { + phy_init_hw(tp->phydev); + phy_resume(tp->phydev); r8169_hw_phy_config(tp, tp->phydev, tp->mac_version); if (tp->mac_version <= RTL_GIGA_MAC_VER_06) { @@ -2552,9 +2653,6 @@ static void rtl8169_init_phy(struct rtl8169_private *tp) tp->pci_dev->subsystem_device == 0xe000) phy_write_paged(tp->phydev, 0x0001, 0x10, 0xf01b); - if (tp->sfp_mode) - rtl_sfp_init(tp); - /* We may have called phy_speed_down before */ phy_speed_up(tp->phydev); @@ -2657,15 +2755,6 @@ static void rtl_jumbo_config(struct rtl8169_private *tp) if (pci_is_pcie(tp->pci_dev) && tp->supports_gmii) 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) @@ -2780,7 +2869,7 @@ static void rtl_prepare_power_down(struct rtl8169_private *tp) rtl_ephy_write(tp, 0x19, 0xff64); 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); } } @@ -2832,6 +2921,16 @@ static void rtl8169_set_magic_reg(struct rtl8169_private *tp) 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) { u32 rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast; @@ -3098,8 +3197,23 @@ static void rtl_enable_ltr(struct rtl8169_private *tp) r8168_mac_ocp_write(tp, 0xcdf2, 0x9003); r8168_mac_ocp_modify(tp, LTR_OBFF_LOCK, 0x0000, LINK_SPEED_CHANGE_EN); break; - case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: case RTL_GIGA_MAC_VER_52: + r8168_mac_ocp_write(tp, 0xcdd0, 0x9003); + r8168_mac_ocp_modify(tp, LTR_SNOOP, 0x0000, LTR_SNOOP_EN); + r8168_mac_ocp_write(tp, 0xe02c, 0x1880); + r8168_mac_ocp_write(tp, 0xe02e, 0x4880); + r8168_mac_ocp_modify(tp, ALDPS_LTR, 0x0000, ALDPS_LTR_EN); + r8168_mac_ocp_write(tp, 0xcdd8, 0x9003); + r8168_mac_ocp_write(tp, 0xcdda, 0x9003); + r8168_mac_ocp_write(tp, 0xcddc, 0x9003); + r8168_mac_ocp_write(tp, 0xcdd2, 0x883c); + r8168_mac_ocp_write(tp, 0xcdd4, 0x8c12); + r8168_mac_ocp_write(tp, 0xcdd6, 0x9003); + r8168_mac_ocp_write(tp, 0xe0a6, 0x9003); + r8168_mac_ocp_write(tp, 0xe0a8, 0x9003); + r8168_mac_ocp_modify(tp, LTR_OBFF_LOCK, 0x0000, LINK_SPEED_CHANGE_EN); + break; + case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: r8168_mac_ocp_modify(tp, ALDPS_LTR, 0x0000, ALDPS_LTR_EN); RTL_W8(tp, COMBO_LTR_EXTEND, RTL_R8(tp, COMBO_LTR_EXTEND) | COMBO_LTR_EXTEND_EN); fallthrough; @@ -3119,6 +3233,7 @@ static void rtl_enable_ltr(struct rtl8169_private *tp) } /* chip can trigger LTR */ r8168_mac_ocp_modify(tp, LTR_OBFF_LOCK, 0x0003, LTR_OBFF_LOCK_EN); + r8168_mac_ocp_modify(tp, SEND_LTR_MSG, 0x0000, LTR_MSG_EN); } static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) @@ -3152,6 +3267,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) rtl_enable_ltr(tp); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: + case RTL_GIGA_MAC_VER_52: case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: /* reset ephy tx/rx disable timer */ r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0); @@ -3164,6 +3280,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) } else { switch (tp->mac_version) { case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: + case RTL_GIGA_MAC_VER_52: case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0); break; @@ -3657,6 +3774,41 @@ static void rtl_hw_start_8168ep_3(struct rtl8169_private *tp) r8168_mac_ocp_modify(tp, 0xe860, 0x0000, 0x0080); } +static void rtl_lowpower_hidden_functions(struct pci_dev *pdev) +{ + unsigned int slot = PCI_SLOT(pdev->devfn); + struct pci_bus *bus = pdev->bus; + int func, pos; + u16 val; + + for (func = 2; func < 8; func++) { + unsigned int devfn = PCI_DEVFN(slot, func); + + pos = pci_bus_find_capability(bus, devfn, PCI_CAP_ID_EXP); + if (pos) { + pci_bus_read_config_word(bus, devfn, pos + PCI_EXP_LNKCTL, &val); + + if (PCI_POSSIBLE_ERROR(val)) + continue; + + val |= (PCI_EXP_LNKCTL_ASPMC | PCI_EXP_LNKCTL_CLKREQ_EN); + pci_bus_write_config_word(bus, devfn, pos + PCI_EXP_LNKCTL, val); + } + + pos = pci_bus_find_capability(bus, devfn, PCI_CAP_ID_PM); + if (pos) { + pci_bus_read_config_word(bus, devfn, pos + PCI_PM_CTRL, &val); + + if (PCI_POSSIBLE_ERROR(val)) + continue; + + val &= ~PCI_PM_CTRL_STATE_MASK; + val |= (RTL_PM_CTRL_D3HOT | PCI_PM_CTRL_PME_STATUS); + pci_bus_write_config_word(bus, devfn, pos + PCI_PM_CTRL, val); + } + } +} + static void rtl_hw_start_8117(struct rtl8169_private *tp) { static const struct ephy_info e_info_8117[] = { @@ -3693,12 +3845,14 @@ static void rtl_hw_start_8117(struct rtl8169_private *tp) rtl_pcie_state_l2l3_disable(tp); - rg_saw_cnt = phy_read_paged(tp->phydev, 0x0c42, 0x13) & 0x3fff; - if (rg_saw_cnt > 0) { - u16 sw_cnt_1ms_ini; + if (tp->phydev) { + rg_saw_cnt = phy_read_paged(tp->phydev, 0x0c42, 0x13) & 0x3fff; + if (rg_saw_cnt > 0) { + u16 sw_cnt_1ms_ini; - sw_cnt_1ms_ini = (16000000 / rg_saw_cnt) & 0x0fff; - r8168_mac_ocp_modify(tp, 0xd412, 0x0fff, sw_cnt_1ms_ini); + sw_cnt_1ms_ini = (16000000 / rg_saw_cnt) & 0x0fff; + r8168_mac_ocp_modify(tp, 0xd412, 0x0fff, sw_cnt_1ms_ini); + } } r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0000); @@ -4139,12 +4293,23 @@ static void rtl_hw_start(struct rtl8169_private *tp) static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) { 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); netdev_update_features(dev); rtl_jumbo_config(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; } @@ -4869,8 +5034,13 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) goto out; } - if (status & LinkChg) - phy_mac_interrupt(tp->phydev); + if (status & LinkChg) { + if (tp->phydev) + phy_mac_interrupt(tp->phydev); + else if (tp->sfp_mode) + phylink_mac_change(tp->phylink, + !!(RTL_R8(tp, PHYstatus) & LinkStatus)); + } rtl_irq_disable(tp); napi_schedule(&tp->napi); @@ -4930,9 +5100,6 @@ static int rtl8169_poll(struct napi_struct *napi, int budget) static void rtl_enable_tx_lpi(struct rtl8169_private *tp, bool enable) { - if (!rtl_supports_eee(tp)) - return; - switch (tp->mac_version) { case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_52: /* Adjust EEE LED frequency */ @@ -4963,40 +5130,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); - - if (netif_carrier_ok(ndev)) { - rtl_link_chg_patch(tp); - 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) { - struct phy_device *phydev = tp->phydev; - phy_interface_t phy_mode; int ret; - phy_mode = tp->supports_gmii ? PHY_INTERFACE_MODE_GMII : - PHY_INTERFACE_MODE_MII; - - ret = phy_connect_direct(tp->dev, phydev, r8169_phylink_handler, - phy_mode); - if (ret) + ret = phylink_connect_phy(tp->phylink, tp->phydev); + if (ret) { + netdev_err(tp->dev, "failed to connect phy\n"); return ret; - - if (!tp->supports_gmii) - phy_set_max_speed(phydev, SPEED_100); - - phy_attached_info(phydev); + } return 0; } @@ -5007,10 +5149,8 @@ static void rtl8169_down(struct rtl8169_private *tp) /* Clear all task flags */ bitmap_zero(tp->wk.flags, RTL_FLAG_MAX); - phy_stop(tp->phydev); - /* Reset SerDes PHY to bring down fiber link */ - if (tp->sfp_mode) + if (tp->sfp_mode == RTL_SFP_8127_ATF) rtl_sfp_reset(tp); rtl8169_update_counters(tp); @@ -5032,14 +5172,12 @@ static void rtl8169_up(struct rtl8169_private *tp) rtl8168_driver_start(tp); pci_set_master(tp->pci_dev); - phy_init_hw(tp->phydev); - phy_resume(tp->phydev); - rtl8169_init_phy(tp); + if (tp->phydev) + rtl8169_init_phy(tp); + napi_enable(&tp->napi); enable_work(&tp->wk.work); rtl_reset_work(tp); - - phy_start(tp->phydev); } static int rtl8169_close(struct net_device *dev) @@ -5049,13 +5187,14 @@ static int rtl8169_close(struct net_device *dev) pm_runtime_get_sync(&pdev->dev); + phylink_stop(tp->phylink); netif_stop_queue(dev); rtl8169_down(tp); rtl8169_rx_clear(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, tp->RxPhyAddr); @@ -5112,11 +5251,13 @@ static int rtl_open(struct net_device *dev) if (retval < 0) goto err_release_fw_2; - retval = r8169_phy_connect(tp); - if (retval) - goto err_free_irq; - + if (tp->phydev) { + retval = r8169_phy_connect(tp); + if (retval) + goto err_free_irq; + } rtl8169_up(tp); + phylink_start(tp->phylink); rtl8169_init_counter_offsets(tp); netif_start_queue(dev); out: @@ -5221,6 +5362,9 @@ static int rtl8169_resume(struct device *device) /* Some chip versions may truncate packets without this initialization */ rtl_init_rxcfg(tp); + if (rtl_is_8116af(tp)) + rtl_lowpower_hidden_functions(tp->pci_dev); + return rtl8169_runtime_resume(device); } @@ -5288,6 +5432,7 @@ static void rtl_remove_one(struct pci_dev *pdev) r8169_remove_leds(tp->leds); unregister_netdev(tp->dev); + phylink_destroy(tp->phylink); if (tp->dash_type != RTL_DASH_NONE) rtl8168_driver_stop(tp); @@ -5310,7 +5455,7 @@ static const struct net_device_ops rtl_netdev_ops = { .ndo_fix_features = rtl8169_fix_features, .ndo_set_features = rtl8169_set_features, .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, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = rtl8169_netpoll, @@ -5474,16 +5619,6 @@ static int r8169_mdio_register(struct rtl8169_private *tp) 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_suspend(tp->phydev); @@ -5599,6 +5734,277 @@ static bool rtl_aspm_is_safe(struct rtl8169_private *tp) 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) +{ + struct rtl8169_private *tp = container_of(config, + struct rtl8169_private, + phylink_config); + + if (!tp->pcs.ops) + return NULL; + + if (interface == PHY_INTERFACE_MODE_1000BASEX || + interface == PHY_INTERFACE_MODE_10GBASER) + return &tp->pcs; + + return NULL; +} + +static void rtl_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ +} + +static u16 rtl8169_sds_read(struct rtl8169_private *tp, u16 sds_reg) +{ + unsigned long flags; + u16 val = 0; + + raw_spin_lock_irqsave(&tp->mac_ocp_lock, flags); + __r8168_mac_ocp_write(tp, OCP_SDS_ADDR_REG, sds_reg); + __r8168_mac_ocp_write(tp, OCP_SDS_CMD_REG, SDS_CMD_READ); + val = __r8168_mac_ocp_read(tp, OCP_SDS_DATA_REG); + raw_spin_unlock_irqrestore(&tp->mac_ocp_lock, flags); + + return val; +} + +static void rtl8169_pcs_get_state(struct phylink_pcs *pcs, + unsigned int neg_mode, + struct phylink_link_state *state) +{ + struct rtl8169_private *tp = container_of(pcs, struct rtl8169_private, + pcs); + + if (tp->sfp_mode == RTL_SFP_8127_ATF) { + u16 stat1; + + stat1 = rtl8169_sds_read(tp, RTL_SDS_C45_BASE + MDIO_STAT1); + + if (!(stat1 & MDIO_STAT1_LSTATUS)) + stat1 = rtl8169_sds_read(tp, RTL_SDS_C45_BASE + MDIO_STAT1); + + state->link = !!(stat1 & MDIO_STAT1_LSTATUS); + if (!state->link) + return; + + if (state->interface == PHY_INTERFACE_MODE_1000BASEX) + state->speed = SPEED_1000; + else + state->speed = SPEED_10000; + + state->duplex = DUPLEX_FULL; + } else { + u16 bmsr, lpa; + + bmsr = rtl8169_sds_read(tp, RTL_SDS_C22_BASE + MII_BMSR); + lpa = rtl8169_sds_read(tp, RTL_SDS_C22_BASE + MII_LPA); + phylink_mii_c22_pcs_decode_state(state, neg_mode, bmsr, lpa); + } +} + +static int rtl8169_pcs_config(struct phylink_pcs *pcs, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising, + bool permit_pause_to_mac) +{ + struct rtl8169_private *tp = container_of(pcs, struct rtl8169_private, + pcs); + + if (tp->sfp_mode == RTL_SFP_8127_ATF) { + switch (interface) { + case PHY_INTERFACE_MODE_10GBASER: + r8127_sfp_init_10g(tp); + break; + case PHY_INTERFACE_MODE_1000BASEX: + r8127_sfp_init_1g(tp); + break; + default: + netdev_err(tp->dev, "Unsupported SFP interface mode: %s\n", + phy_modes(interface)); + return -EOPNOTSUPP; + } + } + + return 0; +} + +static int rtl8169_pcs_validate(struct phylink_pcs *pcs, + unsigned long *supported, + const struct phylink_link_state *state) +{ + return 0; +} + +static void rtl8169_pcs_an_restart(struct phylink_pcs *pcs) +{ +} + +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) || tp->sfp_mode == RTL_SFP_8127_ATF) + 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 const struct phylink_pcs_ops r8169_pcs_ops = { + .pcs_validate = rtl8169_pcs_validate, + .pcs_get_state = rtl8169_pcs_get_state, + .pcs_config = rtl8169_pcs_config, + .pcs_an_restart = rtl8169_pcs_an_restart, +}; + +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; + + switch (tp->sfp_mode) { + case RTL_SFP_8168_AF: + tp->pcs.ops = &r8169_pcs_ops; + tp->phylink_config.default_an_inband = true; + phy_mode = PHY_INTERFACE_MODE_1000BASEX; + tp->phylink_config.mac_capabilities |= MAC_1000FD; + break; + case RTL_SFP_8127_ATF: + tp->pcs.ops = &r8169_pcs_ops; + phy_mode = PHY_INTERFACE_MODE_10GBASER; + tp->phylink_config.default_an_inband = true; + tp->phylink_config.mac_capabilities |= MAC_1000FD | MAC_10000FD; + __set_bit(PHY_INTERFACE_MODE_10GBASER, + tp->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, + tp->phylink_config.supported_interfaces); + break; + default: + 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; + break; + } + + __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) { const struct rtl_chip_info *chip; @@ -5667,6 +6073,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ext_xid_str, xid); tp->mac_version = chip->mac_version; tp->fw_name = chip->fw_name; + tp->speed = SPEED_UNKNOWN; /* Disable ASPM L1 as that cause random device stop working * problems as well as full system hangs for some PCIe devices users. @@ -5679,12 +6086,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } tp->aspm_manageable = !rc; - if (rtl_is_8125(tp)) { - u16 data = r8168_mac_ocp_read(tp, 0xd006); - - if ((data & 0xff) == 0x07) - tp->sfp_mode = true; - } + tp->sfp_mode = rtl_get_sfp_mode(tp); tp->dash_type = rtl_get_dash_type(tp); tp->dash_enabled = rtl_dash_is_enabled(tp); @@ -5788,13 +6190,23 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, tp); - rc = r8169_mdio_register(tp); + rc = rtl_init_phylink(tp); if (rc) return rc; + if (tp->sfp_mode == RTL_SFP_NONE) { + rc = r8169_mdio_register(tp); + if (rc) { + phylink_destroy(tp->phylink); + return rc; + } + } + rc = register_netdev(dev); - if (rc) + if (rc) { + phylink_destroy(tp->phylink); return rc; + } if (IS_ENABLED(CONFIG_R8169_LEDS)) { if (rtl_is_8125(tp)) @@ -5817,6 +6229,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rtl8168_driver_start(tp); } + if (rtl_is_8116af(tp)) + rtl_lowpower_hidden_functions(tp->pci_dev); + if (pci_dev_run_wake(pdev)) pm_runtime_put_sync(&pdev->dev); diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index ff4375f1e910..b9fc8599df74 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1829,6 +1829,126 @@ int phylink_set_fixed_link(struct phylink *pl, } EXPORT_SYMBOL_GPL(phylink_set_fixed_link); +/** + * phylink_update_pause_state() - Update the phylink pause frame configuration + * @pl: a pointer to a &struct phylink instance + * @pause_state: bitmask indicating the new pause state + * + * Update the MAC pause frame (flow control) state for the phylink instance. + */ +static void phylink_update_pause_state(struct phylink *pl, int pause_state) +{ + struct phylink_link_state *config = &pl->link_config; + bool tx_pause = !!(pause_state & MLO_PAUSE_TX); + bool rx_pause = !!(pause_state & MLO_PAUSE_RX); + bool manual_changed; + + mutex_lock(&pl->state_mutex); + + /* + * See the comments for linkmode_set_pause(), wrt the deficiencies + * with the current implementation. A solution to this issue would + * be: + * ethtool Local device + * rx tx Pause AsymDir + * 0 0 0 0 + * 1 0 1 1 + * 0 1 0 1 + * 1 1 1 1 + * and then use the ethtool rx/tx enablement status to mask the + * rx/tx pause resolution. + */ + linkmode_set_pause(config->advertising, tx_pause, + rx_pause); + + manual_changed = (config->pause ^ pause_state) & MLO_PAUSE_AN || + (!(pause_state & MLO_PAUSE_AN) && + (config->pause ^ pause_state) & MLO_PAUSE_TXRX_MASK); + + config->pause = pause_state; + + /* Update our in-band advertisement, triggering a renegotiation if + * the advertisement changed. + */ + if (!pl->phydev) + phylink_change_inband_advert(pl); + + mutex_unlock(&pl->state_mutex); + + /* If we have a PHY, a change of the pause frame advertisement will + * cause phylib to renegotiate (if AN is enabled) which will in turn + * call our phylink_phy_change() and trigger a resolve. Note that + * we can't hold our state mutex while calling phy_set_asym_pause(). + */ + if (pl->phydev) + phy_set_asym_pause(pl->phydev, rx_pause, tx_pause); + + /* If the manual pause settings changed, make sure we trigger a + * resolve to update their state; we can not guarantee that the + * link will cycle. + */ + if (manual_changed) { + pl->link_failed = true; + phylink_run_resolve(pl); + } +} + +/** + * phylink_update_mac_pause_capabilities() - Dynamically update MAC pause + * @pl: a pointer to a &struct phylink returned from phylink_create() + * @mac_pause: the new MAC pause capabilities mask + * + * This function allows a MAC driver to dynamically change its pause state, + * such as losing/gaining Pause frame support based on MTU size. + * It recalculates supported link modes and triggers renegotiation if needed. + */ +void phylink_update_mac_pause_capabilities(struct phylink *pl, unsigned long mac_pause) +{ + struct phylink_link_state *config = &pl->link_config; + unsigned long old_pause; + int pause_state; + + ASSERT_RTNL(); + + if (mac_pause & ~(MAC_SYM_PAUSE | MAC_ASYM_PAUSE)) { + phylink_err(pl, "Attempted to dynamically change non-pause MAC capabilities\n"); + return; + } + + old_pause = pl->config->mac_capabilities & (MAC_SYM_PAUSE | MAC_ASYM_PAUSE); + if (old_pause == mac_pause) + return; + + mutex_lock(&pl->state_mutex); + + pl->config->mac_capabilities &= ~(MAC_SYM_PAUSE | MAC_ASYM_PAUSE); + pl->config->mac_capabilities |= mac_pause; + + phylink_set(pl->supported, Pause); + phylink_set(pl->supported, Asym_Pause); + + if (pl->phydev) + linkmode_and(pl->supported, pl->supported, pl->phydev->supported); + else if (pl->sfp_bus) + linkmode_and(pl->supported, pl->supported, pl->sfp_support); + + phylink_validate(pl, pl->supported, config); + + pause_state = config->pause; + + if (!phylink_test(pl->supported, Pause)) { + pause_state &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX); + } else if (!phylink_test(pl->supported, Asym_Pause)) { + if ((pause_state & MLO_PAUSE_RX) ^ (pause_state & MLO_PAUSE_TX)) + pause_state &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX); + } + + mutex_unlock(&pl->state_mutex); + + phylink_update_pause_state(pl, pause_state); +} +EXPORT_SYMBOL_GPL(phylink_update_mac_pause_capabilities); + /** * phylink_create() - create a phylink instance * @config: a pointer to the target &struct phylink_config @@ -3188,8 +3308,6 @@ EXPORT_SYMBOL_GPL(phylink_ethtool_get_pauseparam); int phylink_ethtool_set_pauseparam(struct phylink *pl, struct ethtool_pauseparam *pause) { - struct phylink_link_state *config = &pl->link_config; - bool manual_changed; int pause_state; ASSERT_RTNL(); @@ -3213,54 +3331,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl, if (pause->tx_pause) pause_state |= MLO_PAUSE_TX; - mutex_lock(&pl->state_mutex); - /* - * See the comments for linkmode_set_pause(), wrt the deficiencies - * with the current implementation. A solution to this issue would - * be: - * ethtool Local device - * rx tx Pause AsymDir - * 0 0 0 0 - * 1 0 1 1 - * 0 1 0 1 - * 1 1 1 1 - * and then use the ethtool rx/tx enablement status to mask the - * rx/tx pause resolution. - */ - linkmode_set_pause(config->advertising, pause->tx_pause, - pause->rx_pause); - - manual_changed = (config->pause ^ pause_state) & MLO_PAUSE_AN || - (!(pause_state & MLO_PAUSE_AN) && - (config->pause ^ pause_state) & MLO_PAUSE_TXRX_MASK); - - config->pause = pause_state; - - /* Update our in-band advertisement, triggering a renegotiation if - * the advertisement changed. - */ - if (!pl->phydev) - phylink_change_inband_advert(pl); - - mutex_unlock(&pl->state_mutex); - - /* If we have a PHY, a change of the pause frame advertisement will - * cause phylib to renegotiate (if AN is enabled) which will in turn - * call our phylink_phy_change() and trigger a resolve. Note that - * we can't hold our state mutex while calling phy_set_asym_pause(). - */ - if (pl->phydev) - phy_set_asym_pause(pl->phydev, pause->rx_pause, - pause->tx_pause); - - /* If the manual pause settings changed, make sure we trigger a - * resolve to update their state; we can not guarantee that the - * link will cycle. - */ - if (manual_changed) { - pl->link_failed = true; - phylink_run_resolve(pl); - } + phylink_update_pause_state(pl, pause_state); return 0; } diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 177b62a7b2d1..27e31a799e2c 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "../phylib.h" #include "realtek.h" @@ -3044,45 +3043,6 @@ static irqreturn_t rtl8221b_handle_interrupt(struct phy_device *phydev) return IRQ_HANDLED; } -static int rtlgen_sfp_get_features(struct phy_device *phydev) -{ - linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, - phydev->supported); - - /* set default mode */ - phydev->speed = SPEED_10000; - phydev->duplex = DUPLEX_FULL; - - phydev->port = PORT_FIBRE; - - return 0; -} - -static int rtlgen_sfp_read_status(struct phy_device *phydev) -{ - int val, err; - - err = genphy_update_link(phydev); - if (err) - return err; - - if (!phydev->link) - return 0; - - val = phy_read(phydev, RTL_PHYSR); - if (val < 0) - return val; - - rtlgen_decode_physr(phydev, val); - - return 0; -} - -static int rtlgen_sfp_config_aneg(struct phy_device *phydev) -{ - return 0; -} - static struct phy_driver realtek_drvs[] = { { PHY_ID_MATCH_EXACT(0x00008201), @@ -3332,20 +3292,6 @@ static struct phy_driver realtek_drvs[] = { .write_page = rtl821x_write_page, .read_mmd = rtl822x_read_mmd, .write_mmd = rtl822x_write_mmd, - }, { - PHY_ID_MATCH_EXACT(PHY_ID_RTL_DUMMY_SFP), - .name = "Realtek SFP PHY Mode", - .flags = PHY_IS_INTERNAL, - .probe = rtl822x_probe, - .get_features = rtlgen_sfp_get_features, - .config_aneg = rtlgen_sfp_config_aneg, - .read_status = rtlgen_sfp_read_status, - .suspend = genphy_suspend, - .resume = rtlgen_resume, - .read_page = rtl821x_read_page, - .write_page = rtl821x_write_page, - .read_mmd = rtl822x_read_mmd, - .write_mmd = rtl822x_write_mmd, }, { PHY_ID_MATCH_EXACT(0x001ccad0), .name = "RTL8224 2.5Gbps PHY", diff --git a/include/linux/phylink.h b/include/linux/phylink.h index 1dda5c7ed5f1..3a88a69882a6 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -843,4 +843,6 @@ void phylink_replay_link_begin(struct phylink *pl); void phylink_replay_link_end(struct phylink *pl); +void phylink_update_mac_pause_capabilities(struct phylink *pl, unsigned long mac_pause); + #endif diff --git a/include/net/phy/realtek_phy.h b/include/net/phy/realtek_phy.h deleted file mode 100644 index d683bc1b0659..000000000000 --- a/include/net/phy/realtek_phy.h +++ /dev/null @@ -1,7 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _REALTEK_PHY_H -#define _REALTEK_PHY_H - -#define PHY_ID_RTL_DUMMY_SFP 0x001ccbff - -#endif /* _REALTEK_PHY_H */