From 51c8f766124487f6e84076c272645e5f29d32f5e Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Mon, 17 Jan 2022 13:19:13 +0100 Subject: [PATCH] realtek: Improve MAC config handling for all SoCs Adds a rtl931x_phylink_mac_config for the RTL931X and improve the handling of the RTL930X phylink configuration. Add separate handling of the RTL839x since some configurations are different from the RTL838X. Signed-off-by: Birger Koblitz --- .../files-5.10/drivers/net/dsa/rtl83xx/dsa.c | 173 +++++++++++++++--- .../drivers/net/dsa/rtl83xx/rtl838x.h | 63 ++++++- .../drivers/net/dsa/rtl83xx/rtl83xx.h | 3 + 3 files changed, 205 insertions(+), 34 deletions(-) diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c index 12334dff9f..8afb503b23 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c @@ -38,7 +38,7 @@ static void rtl83xx_enable_phy_polling(struct rtl838x_switch_priv *priv) v |= BIT_ULL(i); } - pr_debug("%s: %16llx\n", __func__, v); + pr_info("%s: %16llx\n", __func__, v); priv->r->set_port_reg_le(v, priv->r->smi_poll_ctrl); /* PHY update complete, there is no global PHY polling enable bit on the 9300 */ @@ -131,6 +131,11 @@ static void rtl83xx_vlan_setup(struct rtl838x_switch_priv *priv) info.hash_mc_fid = false; // Do the same for Multicast packets info.profile_id = 0; // Use default Vlan Profile 0 info.tagged_ports = 0; // Initially no port members + if (priv->family_id == RTL9310_FAMILY_ID) { + info.if_id = 0; + info.multicast_grp_mask = 0; + info.l2_tunnel_list_id = -1; + } // Initialize all vlans 0-4095 for (i = 0; i < MAX_VLANS; i ++) @@ -195,7 +200,7 @@ static int rtl83xx_setup(struct dsa_switch *ds) return 0; } -static int rtl930x_setup(struct dsa_switch *ds) +static int rtl93xx_setup(struct dsa_switch *ds) { int i; struct rtl838x_switch_priv *priv = ds->priv; @@ -203,11 +208,14 @@ static int rtl930x_setup(struct dsa_switch *ds) pr_info("%s called\n", __func__); - // Enable CSTI STP mode -// sw_w32(1, RTL930X_ST_CTRL); - /* Disable MAC polling the PHY so that we can start configuration */ - sw_w32(0, RTL930X_SMI_POLL_CTRL); + if (priv->family_id == RTL9300_FAMILY_ID) + sw_w32(0, RTL930X_SMI_POLL_CTRL); + + if (priv->family_id == RTL9310_FAMILY_ID) { + sw_w32(0, RTL931X_SMI_PORT_POLLING_CTRL); + sw_w32(0, RTL931X_SMI_PORT_POLLING_CTRL + 4); + } // Disable all ports except CPU port for (i = 0; i < ds->num_ports; i++) @@ -322,6 +330,7 @@ static void rtl93xx_phylink_validate(struct dsa_switch *ds, int port, unsigned long *supported, struct phylink_link_state *state) { + struct rtl838x_switch_priv *priv = ds->priv; __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; pr_debug("In %s port %d, state is %d (%s)", __func__, port, state->interface, @@ -362,11 +371,24 @@ static void rtl93xx_phylink_validate(struct dsa_switch *ds, int port, phylink_set(mask, 1000baseT_Half); } - /* On the RTL9300 family of SoCs, ports 26 to 27 may be SFP ports TODO: take out of .dts */ - if (port >= 26 && port <= 27) + // Internal phys of the RTL93xx family provide 10G + if (priv->ports[port].phy_is_integrated + && state->interface == PHY_INTERFACE_MODE_1000BASEX) { + phylink_set(mask, 1000baseX_Full); + } else if (priv->ports[port].phy_is_integrated) { phylink_set(mask, 1000baseX_Full); - if (port >= 26 && port <= 27) phylink_set(mask, 10000baseKR_Full); + phylink_set(mask, 10000baseSR_Full); + phylink_set(mask, 10000baseCR_Full); + } + if (state->interface == PHY_INTERFACE_MODE_INTERNAL) { + phylink_set(mask, 1000baseX_Full); + phylink_set(mask, 1000baseT_Full); + phylink_set(mask, 10000baseKR_Full); + phylink_set(mask, 10000baseT_Full); + phylink_set(mask, 10000baseSR_Full); + phylink_set(mask, 10000baseCR_Full); + } phylink_set(mask, 10baseT_Half); phylink_set(mask, 10baseT_Full); @@ -377,6 +399,7 @@ static void rtl93xx_phylink_validate(struct dsa_switch *ds, int port, __ETHTOOL_LINK_MODE_MASK_NBITS); bitmap_and(state->advertising, state->advertising, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); + pr_debug("%s leaving supported: %*pb", __func__, __ETHTOOL_LINK_MODE_MASK_NBITS, supported); } static int rtl83xx_phylink_mac_link_state(struct dsa_switch *ds, int port, @@ -482,6 +505,13 @@ static int rtl93xx_phylink_mac_link_state(struct dsa_switch *ds, int port, pr_err("%s: unknown speed: %d\n", __func__, (u32)speed & 0xf); } + if (priv->family_id == RTL9310_FAMILY_ID + && (port >= 52 || port <= 55)) { /* Internal serdes */ + state->speed = SPEED_10000; + state->link = 1; + state->duplex = 1; + } + pr_debug("%s: speed is: %d %d\n", __func__, (u32)speed & 0xf, state->speed); state->pause &= (MLO_PAUSE_RX | MLO_PAUSE_TX); if (priv->r->get_port_reg_le(priv->r->mac_rx_pause_sts) & BIT_ULL(port)) @@ -559,7 +589,7 @@ static void rtl83xx_phylink_mac_config(struct dsa_switch *ds, int port, if (priv->family_id == RTL8380_FAMILY_ID) { if (mode == MLO_AN_PHY || phylink_autoneg_inband(mode)) { pr_debug("PHY autonegotiates\n"); - reg |= BIT(2); + reg |= RTL838X_NWAY_EN; sw_w32(reg, priv->r->mac_force_mode_ctrl(port)); rtl83xx_config_interface(port, state->interface); return; @@ -569,19 +599,25 @@ static void rtl83xx_phylink_mac_config(struct dsa_switch *ds, int port, if (mode != MLO_AN_FIXED) pr_debug("Fixed state.\n"); + /* Clear id_mode_dis bit, and the existing port mode, let + * RGMII_MODE_EN bet set by mac_link_{up,down} */ if (priv->family_id == RTL8380_FAMILY_ID) { - /* Clear id_mode_dis bit, and the existing port mode, let - * RGMII_MODE_EN bet set by mac_link_{up,down} - */ - reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN); - + reg &= ~(RTL838X_RX_PAUSE_EN | RTL838X_TX_PAUSE_EN); if (state->pause & MLO_PAUSE_TXRX_MASK) { if (state->pause & MLO_PAUSE_TX) - reg |= TX_PAUSE_EN; - reg |= RX_PAUSE_EN; + reg |= RTL838X_TX_PAUSE_EN; + reg |= RTL838X_RX_PAUSE_EN; + } + } else if (priv->family_id == RTL8390_FAMILY_ID) { + reg &= ~(RTL839X_RX_PAUSE_EN | RTL839X_TX_PAUSE_EN); + if (state->pause & MLO_PAUSE_TXRX_MASK) { + if (state->pause & MLO_PAUSE_TX) + reg |= RTL839X_TX_PAUSE_EN; + reg |= RTL839X_RX_PAUSE_EN; } } + reg &= ~(3 << speed_bit); switch (state->speed) { case SPEED_1000: @@ -590,22 +626,98 @@ static void rtl83xx_phylink_mac_config(struct dsa_switch *ds, int port, case SPEED_100: reg |= 1 << speed_bit; break; + default: + break; // Ignore, including 10MBit which has a speed value of 0 } if (priv->family_id == RTL8380_FAMILY_ID) { - reg &= ~(DUPLEX_FULL | FORCE_LINK_EN); + reg &= ~(RTL838X_DUPLEX_MODE | RTL838X_FORCE_LINK_EN); if (state->link) - reg |= FORCE_LINK_EN; - if (state->duplex == DUPLEX_FULL) - reg |= DUPLX_MODE; + reg |= RTL838X_FORCE_LINK_EN; + if (state->duplex == RTL838X_DUPLEX_MODE) + reg |= RTL838X_DUPLEX_MODE; + } else if (priv->family_id == RTL8390_FAMILY_ID) { + reg &= ~(RTL839X_DUPLEX_MODE | RTL839X_FORCE_LINK_EN); + if (state->link) + reg |= RTL839X_FORCE_LINK_EN; + if (state->duplex == RTL839X_DUPLEX_MODE) + reg |= RTL839X_DUPLEX_MODE; } - // Disable AN if (priv->family_id == RTL8380_FAMILY_ID) - reg &= ~BIT(2); + reg &= ~RTL838X_NWAY_EN; sw_w32(reg, priv->r->mac_force_mode_ctrl(port)); } +static void rtl931x_phylink_mac_config(struct dsa_switch *ds, int port, + unsigned int mode, + const struct phylink_link_state *state) +{ + struct rtl838x_switch_priv *priv = ds->priv; + int sds_num; + u32 reg, band; + + sds_num = priv->ports[port].sds_num; + pr_info("%s: speed %d sds_num %d\n", __func__, state->speed, sds_num); + + switch (state->interface) { + case PHY_INTERFACE_MODE_HSGMII: + pr_info("%s setting mode PHY_INTERFACE_MODE_HSGMII\n", __func__); + band = rtl931x_sds_cmu_band_get(sds_num, PHY_INTERFACE_MODE_HSGMII); + rtl931x_sds_init(sds_num, PHY_INTERFACE_MODE_HSGMII); + band = rtl931x_sds_cmu_band_set(sds_num, true, 62, PHY_INTERFACE_MODE_HSGMII); + break; + case PHY_INTERFACE_MODE_1000BASEX: + band = rtl931x_sds_cmu_band_get(sds_num, PHY_INTERFACE_MODE_1000BASEX); + rtl931x_sds_init(sds_num, PHY_INTERFACE_MODE_1000BASEX); + break; + case PHY_INTERFACE_MODE_XGMII: + band = rtl931x_sds_cmu_band_get(sds_num, PHY_INTERFACE_MODE_XGMII); + rtl931x_sds_init(sds_num, PHY_INTERFACE_MODE_XGMII); + break; + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_10GKR: + band = rtl931x_sds_cmu_band_get(sds_num, PHY_INTERFACE_MODE_10GBASER); + rtl931x_sds_init(sds_num, PHY_INTERFACE_MODE_10GBASER); + break; + case PHY_INTERFACE_MODE_USXGMII: + // Translates to MII_USXGMII_10GSXGMII + band = rtl931x_sds_cmu_band_get(sds_num, PHY_INTERFACE_MODE_USXGMII); + rtl931x_sds_init(sds_num, PHY_INTERFACE_MODE_USXGMII); + break; + case PHY_INTERFACE_MODE_SGMII: + pr_info("%s setting mode PHY_INTERFACE_MODE_SGMII\n", __func__); + band = rtl931x_sds_cmu_band_get(sds_num, PHY_INTERFACE_MODE_SGMII); + rtl931x_sds_init(sds_num, PHY_INTERFACE_MODE_SGMII); + band = rtl931x_sds_cmu_band_set(sds_num, true, 62, PHY_INTERFACE_MODE_SGMII); + break; + case PHY_INTERFACE_MODE_QSGMII: + band = rtl931x_sds_cmu_band_get(sds_num, PHY_INTERFACE_MODE_QSGMII); + rtl931x_sds_init(sds_num, PHY_INTERFACE_MODE_QSGMII); + break; + default: + pr_err("%s: unknown serdes mode: %s\n", + __func__, phy_modes(state->interface)); + return; + } + + reg = sw_r32(priv->r->mac_force_mode_ctrl(port)); + pr_info("%s reading FORCE_MODE_CTRL: %08x\n", __func__, reg); + + reg &= ~(RTL931X_DUPLEX_MODE | RTL931X_FORCE_EN | RTL931X_FORCE_LINK_EN); + + reg &= ~(0xf << 12); + reg |= 0x2 << 12; // Set SMI speed to 0x2 + + reg |= BIT(17) | BIT(16); // Enable RX pause and TX pause + + if (state->duplex == DUPLEX_FULL) + reg |= RTL931X_DUPLEX_MODE; + + sw_w32(reg, priv->r->mac_force_mode_ctrl(port)); + +} + static void rtl93xx_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, const struct phylink_link_state *state) @@ -621,6 +733,9 @@ static void rtl93xx_phylink_mac_config(struct dsa_switch *ds, int port, if (port == priv->cpu_port) return; + if (priv->family_id == RTL9310_FAMILY_ID) + return rtl931x_phylink_mac_config(ds, port, mode, state); + reg = sw_r32(priv->r->mac_force_mode_ctrl(port)); reg &= ~(0xf << 3); @@ -672,12 +787,16 @@ static void rtl93xx_phylink_mac_config(struct dsa_switch *ds, int port, } if (state->link) - reg |= FORCE_LINK_EN; + reg |= RTL930X_FORCE_LINK_EN; if (state->duplex == DUPLEX_FULL) - reg |= BIT(2); + reg |= RTL930X_DUPLEX_MODE; + + if (priv->ports[port].phy_is_integrated) + reg &= ~RTL930X_FORCE_EN; // Clear MAC_FORCE_EN to allow SDS-MAC link + else + reg |= RTL930X_FORCE_EN; - reg |= 1; // Force Link up sw_w32(reg, priv->r->mac_force_mode_ctrl(port)); } @@ -1799,7 +1918,7 @@ const struct dsa_switch_ops rtl83xx_switch_ops = { const struct dsa_switch_ops rtl930x_switch_ops = { .get_tag_protocol = rtl83xx_get_tag_protocol, - .setup = rtl930x_setup, + .setup = rtl93xx_setup, .phy_read = dsa_phy_read, .phy_write = dsa_phy_write, diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h index 1c55ff6fc9..a334a5ddbb 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h @@ -147,12 +147,34 @@ #define RTL930X_MAC_LINK_MEDIA_STS (0xCB14) /* MAC link state bits */ -#define FORCE_EN (1 << 0) -#define FORCE_LINK_EN (1 << 1) -#define NWAY_EN (1 << 2) -#define DUPLX_MODE (1 << 3) -#define TX_PAUSE_EN (1 << 6) -#define RX_PAUSE_EN (1 << 7) +#define RTL838X_FORCE_EN (1 << 0) +#define RTL838X_FORCE_LINK_EN (1 << 1) +#define RTL838X_NWAY_EN (1 << 2) +#define RTL838X_DUPLEX_MODE (1 << 3) +#define RTL838X_TX_PAUSE_EN (1 << 6) +#define RTL838X_RX_PAUSE_EN (1 << 7) +#define RTL838X_MAC_FORCE_FC_EN (1 << 8) + +#define RTL839X_FORCE_EN (1 << 0) +#define RTL839X_FORCE_LINK_EN (1 << 1) +#define RTL839X_DUPLEX_MODE (1 << 2) +#define RTL839X_TX_PAUSE_EN (1 << 5) +#define RTL839X_RX_PAUSE_EN (1 << 6) +#define RTL839X_MAC_FORCE_FC_EN (1 << 7) + +#define RTL930X_FORCE_EN (1 << 0) +#define RTL930X_FORCE_LINK_EN (1 << 1) +#define RTL930X_DUPLEX_MODE (1 << 2) +#define RTL930X_TX_PAUSE_EN (1 << 7) +#define RTL930X_RX_PAUSE_EN (1 << 8) +#define RTL930X_MAC_FORCE_FC_EN (1 << 9) + +#define RTL931X_FORCE_EN (1 << 9) +#define RTL931X_FORCE_LINK_EN (1 << 0) +#define RTL931X_DUPLEX_MODE (1 << 2) +#define RTL931X_MAC_FORCE_FC_EN (1 << 4) +#define RTL931X_TX_PAUSE_EN (1 << 16) +#define RTL931X_RX_PAUSE_EN (1 << 17) /* EEE */ #define RTL838X_MAC_EEE_ABLTY (0xa1a8) @@ -433,6 +455,7 @@ enum phy_type { PHY_RTL8218B_EXT = 3, PHY_RTL8214FC = 4, PHY_RTL839X_SDS = 5, + PHY_RTL930X_SDS = 6, }; struct rtl838x_port { @@ -441,6 +464,7 @@ struct rtl838x_port { u16 pvid; bool eee_enabled; enum phy_type phy; + bool phy_is_integrated; bool is10G; bool is2G5; int sds_num; @@ -453,7 +477,12 @@ struct rtl838x_vlan_info { u8 profile_id; bool hash_mc_fid; bool hash_uc_fid; - u8 fid; + u8 fid; // AKA MSTI + + // The following fields are used only by the RTL931X + int if_id; // Interface (index in L3_EGR_INTF_IDX) + u16 multicast_grp_mask; + int l2_tunnel_list_id; }; enum l2_entry_type { @@ -488,6 +517,15 @@ struct rtl838x_l2_entry { u16 mc_mac_index; u16 nh_route_id; bool nh_vlan_target; // Only RTL83xx: VLAN used for next hop + + // The following is only valid on RTL931x + bool is_open_flow; + bool is_pe_forward; + bool is_local_forward; + bool is_remote_forward; + bool is_l2_tunnel; + int l2_tunnel_id; + int l2_tunnel_list_id; }; enum fwd_rule_action { @@ -500,6 +538,17 @@ enum pie_phase { PHASE_IACL = 1, }; +enum igr_filter { + IGR_FORWARD = 0, + IGR_DROP = 1, + IGR_TRAP = 2, +}; + +enum egr_filter { + EGR_DISABLE = 0, + EGR_ENABLE = 1, +}; + /* Intermediate representation of a Packet Inspection Engine Rule * as suggested by the Kernel's tc flower offload subsystem * Field meaning is universal across SoC families, but data content is specific diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl83xx.h b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl83xx.h index ffd37aa5a8..70b1c4e09d 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl83xx.h +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl83xx.h @@ -125,6 +125,9 @@ void rtl930x_print_matrix(void); /* RTL931x-specific */ irqreturn_t rtl931x_switch_irq(int irq, void *dev_id); +int rtl931x_sds_cmu_band_get(int sds, phy_interface_t mode); +int rtl931x_sds_cmu_band_set(int sds, bool enable, u32 band, phy_interface_t mode); +void rtl931x_sds_init(u32 sds, phy_interface_t mode); #endif /* _NET_DSA_RTL83XX_H */