diff --git a/drivers/net/dsa/realtek/rtl8365mb_main.c b/drivers/net/dsa/realtek/rtl8365mb_main.c index ea03c42d0f1a..d1ba0cc9426f 100644 --- a/drivers/net/dsa/realtek/rtl8365mb_main.c +++ b/drivers/net/dsa/realtek/rtl8365mb_main.c @@ -40,8 +40,8 @@ * driver has only been tested with a fixed-link, but in principle it should not * matter. * - * NOTE: Currently, only the RGMII and SGMII interfaces are implemented in this - * driver. + * NOTE: Currently, only the RGMII, SGMII and HSGMII interfaces are implemented + * in this driver. * * The interrupt line is asserted on link UP/DOWN events. The driver creates a * custom irqchip to handle this interrupt and demultiplex the events by reading @@ -251,6 +251,18 @@ #define RTL8365MB_BYPASS_LINE_RATE_REG 0x03F7 #define RTL8365MB_BYPASS_LINE_RATE_MASK(_port) BIT((_port) - 5) +/* Port 6 ingress and egress rate limiter registers. Each limit is a 19-bit + * value in units of 8 Kbps, split across a 16-bit LSB register (CTRL0) and a + * 3-bit MSB field (CTRL1). The chip resets them to 0x1FFFF; see + * rtl8365mb_sds_raise_rate_limits(). + */ +#define RTL8365MB_INGRESSBW_PORT6_RATE_CTRL0_REG 0x00CF +#define RTL8365MB_INGRESSBW_PORT6_RATE_CTRL1_REG 0x00D0 +#define RTL8365MB_INGRESSBW_PORT6_RATE_CTRL1_MASK 0x0007 +#define RTL8365MB_PORT6_EGRESSBW_CTRL0_REG 0x0398 +#define RTL8365MB_PORT6_EGRESSBW_CTRL1_REG 0x0399 +#define RTL8365MB_PORT6_EGRESSBW_CTRL1_MASK 0x0007 + /* SerDes indirect access registers */ #define RTL8365MB_SDS_INDACS_CMD_REG 0x6600 #define RTL8365MB_SDS_INDACS_CMD_BUSY_MASK 0x0100 @@ -637,6 +649,18 @@ static const struct rtl8365mb_jam_tbl_entry rtl8365mb_sds_jam_sgmii[] = { { 0x0424, 0xD810 }, { 0x002E, 0x83F2 }, }; +/* HSGMII SerDes tuning parameters, lifted from the vendor driver sources. As + * with the SGMII table, the vendor driver keeps several variants and selects + * one based on the chip option register; these are the values for a non-zero + * option, which is what RTL8367S parts seen so far report. See + * rtl8365mb_sds_probe_option(). + */ +static const struct rtl8365mb_jam_tbl_entry rtl8365mb_sds_jam_hsgmii[] = { + { 0x0500, 0x82F0 }, { 0x0501, 0xF195 }, { 0x0502, 0x31A2 }, + { 0x0503, 0x7960 }, { 0x0504, 0x9728 }, { 0x0423, 0x9D85 }, + { 0x0424, 0xD810 }, { 0x0001, 0x0F80 }, { 0x002E, 0x83F2 }, +}; + enum rtl8365mb_phy_interface_mode { RTL8365MB_PHY_INTERFACE_MODE_INVAL = 0, RTL8365MB_PHY_INTERFACE_MODE_INTERNAL = BIT(0), @@ -1242,20 +1266,70 @@ static int rtl8365mb_sds_probe_option(struct realtek_priv *priv) return 0; } +/* The vendor driver raises the port 6 ingress and egress rate limiters to + * their maximum in its switch init, unconditionally for the whole chip + * family. The chip reset in rtl8365mb_setup() puts them back to their reset + * default of 0x1FFFF, a ~1.048 Gbps limit which caps the aggregate + * throughput of an HSGMII CPU port at roughly 1 Gbps. The vendor + * documentation describes the reset default as disabling the limiter, but + * the cap has been observed on hardware. Raise them likewise, to 0x7FFFF + * (~4.19 Gbps, above the HSGMII line rate). The related HSGMII scheduler + * line rate register (LINE_RATE_HSG_H, 0x03FA) is already set to its + * maximum by the common init jam table. + */ +static int rtl8365mb_sds_raise_rate_limits(struct realtek_priv *priv) +{ + int ret; + + ret = regmap_write(priv->map, RTL8365MB_INGRESSBW_PORT6_RATE_CTRL0_REG, + 0xFFFF); + if (ret) + return ret; + + ret = regmap_update_bits(priv->map, + RTL8365MB_INGRESSBW_PORT6_RATE_CTRL1_REG, + RTL8365MB_INGRESSBW_PORT6_RATE_CTRL1_MASK, + RTL8365MB_INGRESSBW_PORT6_RATE_CTRL1_MASK); + if (ret) + return ret; + + ret = regmap_write(priv->map, RTL8365MB_PORT6_EGRESSBW_CTRL0_REG, + 0xFFFF); + if (ret) + return ret; + + return regmap_update_bits(priv->map, RTL8365MB_PORT6_EGRESSBW_CTRL1_REG, + RTL8365MB_PORT6_EGRESSBW_CTRL1_MASK, + RTL8365MB_PORT6_EGRESSBW_CTRL1_MASK); +} + static int rtl8365mb_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) { + const struct rtl8365mb_jam_tbl_entry *sds_jam; const int id = RTL8365MB_SDS_EXT_INTERFACE_ID; struct rtl8365mb *mb = pcs_to_rtl8365mb(pcs); struct realtek_priv *priv; + size_t sds_jam_size; + u32 mode; u16 val; int ret; int i; priv = mb->priv; + if (interface == PHY_INTERFACE_MODE_2500BASEX) { + sds_jam = rtl8365mb_sds_jam_hsgmii; + sds_jam_size = ARRAY_SIZE(rtl8365mb_sds_jam_hsgmii); + mode = RTL8365MB_EXT_PORT_MODE_HSGMII; + } else { + sds_jam = rtl8365mb_sds_jam_sgmii; + sds_jam_size = ARRAY_SIZE(rtl8365mb_sds_jam_sgmii); + mode = RTL8365MB_EXT_PORT_MODE_SGMII; + } + /* Hold the embedded DW8051 microcontroller in reset and keep it * disabled. The vendor driver loads firmware into it to manage the * SerDes link, but the firmware only duplicates work that phylink @@ -1283,24 +1357,24 @@ static int rtl8365mb_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, return ret; /* Tune the SerDes with vendor-prescribed parameters */ - for (i = 0; i < ARRAY_SIZE(rtl8365mb_sds_jam_sgmii); i++) { - ret = rtl8365mb_sds_write(priv, - rtl8365mb_sds_jam_sgmii[i].reg, - rtl8365mb_sds_jam_sgmii[i].val); + for (i = 0; i < sds_jam_size; i++) { + ret = rtl8365mb_sds_write(priv, sds_jam[i].reg, + sds_jam[i].val); if (ret) return ret; } - /* Mux the SerDes to MAC8 in SGMII mode */ + /* Mux the SerDes to MAC8 in the requested mode */ ret = regmap_update_bits(priv->map, RTL8365MB_SDS_MISC_REG, RTL8365MB_SDS_MISC_MAC8_SEL_SGMII_MASK | RTL8365MB_SDS_MISC_MAC8_SEL_HSGMII_MASK, - RTL8365MB_SDS_MISC_MAC8_SEL_SGMII_MASK); + mode == RTL8365MB_EXT_PORT_MODE_SGMII ? + RTL8365MB_SDS_MISC_MAC8_SEL_SGMII_MASK : + RTL8365MB_SDS_MISC_MAC8_SEL_HSGMII_MASK); if (ret) return ret; - val = RTL8365MB_EXT_PORT_MODE_SGMII - << RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(id); + val = mode << RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(id); ret = regmap_update_bits(priv->map, RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(id), RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(id), @@ -1346,7 +1420,8 @@ static int rtl8365mb_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, static bool rtl8365mb_interface_is_serdes(phy_interface_t interface) { - return interface == PHY_INTERFACE_MODE_SGMII; + return interface == PHY_INTERFACE_MODE_SGMII || + interface == PHY_INTERFACE_MODE_2500BASEX; } static unsigned int rtl8365mb_pcs_inband_caps(struct phylink_pcs *pcs, @@ -1401,7 +1476,9 @@ static void rtl8365mb_pcs_get_state(struct phylink_pcs *pcs, switch (FIELD_GET(RTL8365MB_SDS_MISC_SGMII_SPD_MASK, val)) { case RTL8365MB_PORT_SPEED_1000M: - state->speed = SPEED_1000; + state->speed = + state->interface == PHY_INTERFACE_MODE_2500BASEX ? + SPEED_2500 : SPEED_1000; break; case RTL8365MB_PORT_SPEED_100M: state->speed = SPEED_100; @@ -1426,7 +1503,11 @@ static void rtl8365mb_pcs_link_up(struct phylink_pcs *pcs, u32 r_speed; int ret; - if (speed == SPEED_1000) { + /* The speed field has no value for 2.5 Gbps: the rate is determined by + * the HSGMII SerDes configuration, and the vendor driver programs the + * 1 Gbps value here. + */ + if (speed == SPEED_2500 || speed == SPEED_1000) { r_speed = RTL8365MB_PORT_SPEED_1000M; } else if (speed == SPEED_100) { r_speed = RTL8365MB_PORT_SPEED_100M; @@ -1486,7 +1567,11 @@ static int rtl8365mb_ext_config_forcemode(struct realtek_priv *priv, int port, r_rx_pause = rx_pause ? 1 : 0; r_tx_pause = tx_pause ? 1 : 0; - if (speed == SPEED_1000) { + /* The speed field has no value for 2.5 Gbps: the rate is + * determined by the HSGMII SerDes configuration, and the + * vendor driver programs the 1 Gbps value here. + */ + if (speed == SPEED_2500 || speed == SPEED_1000) { r_speed = RTL8365MB_PORT_SPEED_1000M; } else if (speed == SPEED_100) { r_speed = RTL8365MB_PORT_SPEED_100M; @@ -1569,6 +1654,13 @@ static void rtl8365mb_phylink_get_caps(struct dsa_switch *ds, int port, mb->sds_supported) __set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces); + + if (extint->supported_interfaces & RTL8365MB_PHY_INTERFACE_MODE_HSGMII && + mb->sds_supported) { + __set_bit(PHY_INTERFACE_MODE_2500BASEX, + config->supported_interfaces); + config->mac_capabilities |= MAC_2500FD; + } } static struct phylink_pcs * @@ -1610,8 +1702,8 @@ static void rtl8365mb_phylink_mac_config(struct phylink_config *config, return; } - /* SGMII is handled by the SerDes PCS, configured through the - * phylink_pcs ops, so there is nothing to do here for it. + /* SGMII and 2500base-x are handled by the SerDes PCS, configured + * through the phylink_pcs ops, so nothing to do here for them. */ if (rtl8365mb_interface_is_serdes(state->interface)) return; @@ -2940,6 +3032,16 @@ static int rtl8365mb_setup(struct dsa_switch *ds) goto out_error; } + if (mb->sds_supported) { + ret = rtl8365mb_sds_raise_rate_limits(priv); + if (ret) { + dev_err(priv->dev, + "failed to raise port rate limits: %pe\n", + ERR_PTR(ret)); + goto out_error; + } + } + /* Set up cascading IRQs */ ret = rtl8365mb_irq_setup(priv); if (ret == -EPROBE_DEFER)