extern const struct dsa_switch_ops rtl83xx_switch_ops;
extern const struct dsa_switch_ops rtl930x_switch_ops;
-extern const struct phylink_pcs_ops rtl83xx_pcs_ops;
-extern const struct phylink_pcs_ops rtl93xx_pcs_ops;
+extern struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int port);
int rtl83xx_port_get_stp_state(struct rtl838x_switch_priv *priv, int port)
{
static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
{
- struct device_node *dn, *phy_node, *led_node, *np, *mii_np;
+ struct device_node *dn, *phy_node, *pcs_node, *led_node, *np, *mii_np;
struct device *dev = priv->dev;
struct mii_bus *bus;
int ret;
continue;
}
+ /*
+ * TODO: phylink_pcs was completely converted to the standalone PCS driver - see
+ * rtpcs_create() below. Nevertheless we still make use of the old SerDes <sds>
+ * attribute of the phy node for the scatterd SerDes configuration functions. As
+ * soon as the PCS driver can completely configure the SerDes this is no longer
+ * needed.
+ */
+
if (of_property_read_u32(phy_node, "sds", &priv->ports[pn].sds_num))
priv->ports[pn].sds_num = -1;
pr_debug("%s port %d has SDS %d\n", __func__, pn, priv->ports[pn].sds_num);
+ pcs_node = of_parse_phandle(dn, "pcs-handle", 0);
+ priv->pcs[pn] = rtpcs_create(priv->dev, pcs_node, pn);
+
if (of_get_phy_mode(dn, &interface))
interface = PHY_INTERFACE_MODE_NA;
if (interface == PHY_INTERFACE_MODE_USXGMII)
static int __init rtl83xx_sw_probe(struct platform_device *pdev)
{
- int i, err = 0;
struct rtl838x_switch_priv *priv;
struct device *dev = &pdev->dev;
u64 bpdu_mask;
+ int err = 0;
pr_debug("Probing RTL838X switch device\n");
if (!pdev->dev.of_node) {
}
pr_debug("Chip version %c\n", priv->version);
- for (i = 0; i <= priv->cpu_port; i++) {
- switch (soc_info.family) {
- case RTL8380_FAMILY_ID:
- case RTL8390_FAMILY_ID:
- priv->pcs[i].pcs.ops = &rtl83xx_pcs_ops;
- break;
- case RTL9300_FAMILY_ID:
- case RTL9310_FAMILY_ID:
- priv->pcs[i].pcs.ops = &rtl93xx_pcs_ops;
- break;
- }
- priv->pcs[i].pcs.neg_mode = true;
- priv->pcs[i].priv = priv;
- priv->pcs[i].port = i;
- }
-
err = rtl83xx_mdio_probe(priv);
if (err) {
/* Probing fails the 1st time because of missing ethernet driver
return sds_num;
}
-static void rtldsa_83xx_pcs_get_state(struct phylink_pcs *pcs, struct phylink_link_state *state)
-{
- struct rtl838x_pcs *rtpcs = container_of(pcs, struct rtl838x_pcs, pcs);
- struct rtl838x_switch_priv *priv = rtpcs->priv;
- int port = rtpcs->port;
- u64 speed;
-
- state->link = 0;
- state->speed = SPEED_UNKNOWN;
- state->duplex = DUPLEX_UNKNOWN;
- state->pause &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX);
-
- if (port < 0 || port > priv->cpu_port)
- return;
-
- if (!(priv->r->get_port_reg_le(priv->r->mac_link_sts) & BIT_ULL(port)))
- return;
-
- state->link = 1;
-
- if (priv->r->get_port_reg_le(priv->r->mac_link_dup_sts) & BIT_ULL(port))
- state->duplex = DUPLEX_FULL;
- else
- state->duplex = DUPLEX_HALF;
-
- speed = priv->r->get_port_reg_le(priv->r->mac_link_spd_sts(port));
- speed = (speed >> ((port % 16) << 1)) & 0x3;
-
- switch (speed) {
- case RTL_SPEED_10:
- state->speed = SPEED_10;
- break;
- case RTL_SPEED_100:
- state->speed = SPEED_100;
- break;
- case RTL_SPEED_1000:
- state->speed = SPEED_1000;
- break;
- case 3:
- /*
- * This is ok so far but with minor inconsistencies. On RTL838x this setting is
- * for either 500M or 2G. It might be that MAC_GLITE_STS register tells more. On
- * RTL839x these vendor specifics are derived from MAC_LINK_500M_STS and mode 3
- * is 10G. This is of interest so resolve to it. Sadly it is off by one for the
- * current RTL_SPEED_10000 (=4) definition for RTL93xx.
- */
- state->speed = SPEED_10000;
- break;
- }
-
- if (priv->r->get_port_reg_le(priv->r->mac_rx_pause_sts) & BIT_ULL(port))
- state->pause |= MLO_PAUSE_RX;
- if (priv->r->get_port_reg_le(priv->r->mac_tx_pause_sts) & BIT_ULL(port))
- state->pause |= MLO_PAUSE_TX;
-}
-
-static void rtldsa_93xx_pcs_get_state(struct phylink_pcs *pcs,
- struct phylink_link_state *state)
-{
- struct rtl838x_pcs *rtpcs = container_of(pcs, struct rtl838x_pcs, pcs);
- struct rtl838x_switch_priv *priv = rtpcs->priv;
- int port = rtpcs->port;
- u64 speed;
- u64 link;
- u64 media;
-
- state->link = 0;
- state->speed = SPEED_UNKNOWN;
- state->duplex = DUPLEX_UNKNOWN;
- state->pause &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX);
-
- if (port < 0 || port > priv->cpu_port)
- return;
-
- /* On the RTL9300 for at least the RTL8226B PHY, the MAC-side link
- * state needs to be read twice in order to read a correct result.
- * This would not be necessary for ports connected e.g. to RTL8218D
- * PHYs.
- */
- link = priv->r->get_port_reg_le(priv->r->mac_link_sts);
- link = priv->r->get_port_reg_le(priv->r->mac_link_sts);
- if (!(link & BIT_ULL(port)))
- return;
-
- state->link = 1;
-
- if (priv->family_id == RTL9310_FAMILY_ID)
- media = priv->r->get_port_reg_le(RTL931X_MAC_LINK_MEDIA_STS);
-
- if (priv->family_id == RTL9300_FAMILY_ID)
- media = sw_r32(RTL930X_MAC_LINK_MEDIA_STS);
-
- pr_debug("%s: link state port %d: %llx, media %llx\n", __func__, port,
- link & BIT_ULL(port), media);
-
- if (priv->r->get_port_reg_le(priv->r->mac_link_dup_sts) & BIT_ULL(port))
- state->duplex = DUPLEX_FULL;
- else
- state->duplex = DUPLEX_HALF;
-
- speed = priv->r->get_port_reg_le(priv->r->mac_link_spd_sts(port));
- speed = (speed >> ((port % 8) << 2)) & 0xf;
- switch (speed) {
- case RTL_SPEED_10:
- state->speed = SPEED_10;
- break;
- case RTL_SPEED_100:
- state->speed = SPEED_100;
- break;
- case RTL_SPEED_1000:
- state->speed = SPEED_1000;
- break;
- case RTL_SPEED_10000:
- state->speed = SPEED_10000;
- break;
- case RTL_SPEED_2500:
- state->speed = SPEED_2500;
- break;
- case RTL_SPEED_5000:
- state->speed = SPEED_5000;
- break;
- default:
- pr_err("%s: unknown speed: %d\n", __func__, (u32)speed & 0xf);
- }
-
- pr_debug("%s: speed is: %d %d\n", __func__, (u32)speed & 0xf, state->speed);
- if (priv->r->get_port_reg_le(priv->r->mac_rx_pause_sts) & BIT_ULL(port))
- state->pause |= MLO_PAUSE_RX;
- if (priv->r->get_port_reg_le(priv->r->mac_tx_pause_sts) & BIT_ULL(port))
- state->pause |= MLO_PAUSE_TX;
-}
-
-static int rtl83xx_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
- phy_interface_t interface,
- const unsigned long *advertising,
- bool permit_pause_to_mac)
-{
- return 0;
-}
-
-static void rtl83xx_pcs_an_restart(struct phylink_pcs *pcs)
-{
-/* No restart functionality existed before we migrated to pcs */
-}
-
-static struct phylink_pcs *rtl83xx_phylink_mac_select_pcs(struct dsa_switch *ds,
- int port,
- phy_interface_t interface)
+static struct phylink_pcs *rtldsa_phylink_mac_select_pcs(struct dsa_switch *ds,
+ int port,
+ phy_interface_t interface)
{
struct rtl838x_switch_priv *priv = ds->priv;
- return &priv->pcs[port].pcs;
+ return priv->pcs[port];
}
static void rtl83xx_config_interface(int port, phy_interface_t interface)
return mdiobus_write_nested(priv->parent_bus, addr, regnum, val);
}
-const struct phylink_pcs_ops rtl83xx_pcs_ops = {
- .pcs_an_restart = rtl83xx_pcs_an_restart,
- .pcs_get_state = rtldsa_83xx_pcs_get_state,
- .pcs_config = rtl83xx_pcs_config,
-};
-
const struct dsa_switch_ops rtl83xx_switch_ops = {
.get_tag_protocol = rtl83xx_get_tag_protocol,
.setup = rtl83xx_setup,
.phylink_mac_config = rtl83xx_phylink_mac_config,
.phylink_mac_link_down = rtl83xx_phylink_mac_link_down,
.phylink_mac_link_up = rtl83xx_phylink_mac_link_up,
- .phylink_mac_select_pcs = rtl83xx_phylink_mac_select_pcs,
+ .phylink_mac_select_pcs = rtldsa_phylink_mac_select_pcs,
.get_strings = rtldsa_get_strings,
.get_ethtool_stats = rtldsa_get_ethtool_stats,
.port_bridge_flags = rtl83xx_port_bridge_flags,
};
-const struct phylink_pcs_ops rtl93xx_pcs_ops = {
- .pcs_an_restart = rtl83xx_pcs_an_restart,
- .pcs_get_state = rtldsa_93xx_pcs_get_state,
- .pcs_config = rtl83xx_pcs_config,
-};
-
const struct dsa_switch_ops rtl930x_switch_ops = {
.get_tag_protocol = rtl83xx_get_tag_protocol,
.setup = rtl93xx_setup,
.phylink_mac_config = rtl93xx_phylink_mac_config,
.phylink_mac_link_down = rtl93xx_phylink_mac_link_down,
.phylink_mac_link_up = rtl93xx_phylink_mac_link_up,
- .phylink_mac_select_pcs = rtl83xx_phylink_mac_select_pcs,
+ .phylink_mac_select_pcs = rtldsa_phylink_mac_select_pcs,
.get_strings = rtldsa_get_strings,
.get_ethtool_stats = rtldsa_get_ethtool_stats,
return RTL838X_L2_PORT_NEW_SA_FWD(p);
}
-static inline int rtl838x_mac_link_spd_sts(int p)
-{
- return RTL838X_MAC_LINK_SPD_STS(p);
-}
-
inline static int rtl838x_trk_mbr_ctr(int group)
{
return RTL838X_TRK_MBR_CTR + (group << 2);
.mir_ctrl = RTL838X_MIR_CTRL,
.mir_dpm = RTL838X_MIR_DPM_CTRL,
.mir_spm = RTL838X_MIR_SPM_CTRL,
- .mac_link_sts = RTL838X_MAC_LINK_STS,
- .mac_link_dup_sts = RTL838X_MAC_LINK_DUP_STS,
- .mac_link_spd_sts = rtl838x_mac_link_spd_sts,
- .mac_rx_pause_sts = RTL838X_MAC_RX_PAUSE_STS,
- .mac_tx_pause_sts = RTL838X_MAC_TX_PAUSE_STS,
.read_l2_entry_using_hash = rtl838x_read_l2_entry_using_hash,
.write_l2_entry_using_hash = rtl838x_write_l2_entry_using_hash,
.read_cam = rtl838x_read_cam,
#define RTL839X_MAC_LINK_STS (0x0390)
#define RTL930X_MAC_LINK_STS (0xCB10)
#define RTL931X_MAC_LINK_STS (0x0EC0)
-#define RTL838X_MAC_LINK_SPD_STS(p) (0xa190 + (((p >> 4) << 2)))
-#define RTL839X_MAC_LINK_SPD_STS(p) (0x03a0 + (((p >> 4) << 2)))
-#define RTL930X_MAC_LINK_SPD_STS(p) (0xCB18 + (((p >> 3) << 2)))
-#define RTL931X_MAC_LINK_SPD_STS (0x0ED0)
-#define RTL838X_MAC_LINK_DUP_STS (0xa19c)
-#define RTL839X_MAC_LINK_DUP_STS (0x03b0)
-#define RTL930X_MAC_LINK_DUP_STS (0xCB28)
-#define RTL931X_MAC_LINK_DUP_STS (0x0EF0)
-#define RTL838X_MAC_TX_PAUSE_STS (0xa1a0)
-#define RTL839X_MAC_TX_PAUSE_STS (0x03b8)
-#define RTL930X_MAC_TX_PAUSE_STS (0xCB2C)
-#define RTL931X_MAC_TX_PAUSE_STS (0x0EF8)
-#define RTL838X_MAC_RX_PAUSE_STS (0xa1a4)
-#define RTL839X_MAC_RX_PAUSE_STS (0x03c0)
-#define RTL930X_MAC_RX_PAUSE_STS (0xCB30)
-#define RTL931X_MAC_RX_PAUSE_STS (0x0F00)
-#define RTL930X_MAC_LINK_MEDIA_STS (0xCB14)
-#define RTL931X_MAC_LINK_MEDIA_STS (0x0EC8)
/* MAC link state bits */
#define RTL_SPEED_10 0
const struct dsa_port *dp;
};
-struct rtl838x_pcs {
- struct phylink_pcs pcs;
- struct rtl838x_switch_priv *priv;
- int port;
-};
-
struct rtl838x_vlan_info {
u64 untagged_ports;
u64 member_ports;
int mir_ctrl;
int mir_dpm;
int mir_spm;
- int mac_link_sts;
- int mac_link_dup_sts;
- int (*mac_link_spd_sts)(int port);
- int mac_rx_pause_sts;
- int mac_tx_pause_sts;
u64 (*read_l2_entry_using_hash)(u32 hash, u32 position, struct rtl838x_l2_entry *e);
void (*write_l2_entry_using_hash)(u32 hash, u32 pos, struct rtl838x_l2_entry *e);
u64 (*read_cam)(int idx, struct rtl838x_l2_entry *e);
u16 family_id;
char version;
struct rtl838x_port ports[57];
- struct rtl838x_pcs pcs[57];
+ struct phylink_pcs *pcs[57];
struct mutex reg_mutex; /* Mutex for individual register manipulations */
struct mutex pie_mutex; /* Mutex for Packet Inspection Engine */
int link_state_irq;
return RTL839X_L2_PORT_NEW_SA_FWD(p);
}
-static inline int rtl839x_mac_link_spd_sts(int p)
-{
- return RTL839X_MAC_LINK_SPD_STS(p);
-}
-
static inline int rtl839x_trk_mbr_ctr(int group)
{
return RTL839X_TRK_MBR_CTR + (group << 3);
.mir_ctrl = RTL839X_MIR_CTRL,
.mir_dpm = RTL839X_MIR_DPM_CTRL,
.mir_spm = RTL839X_MIR_SPM_CTRL,
- .mac_link_sts = RTL839X_MAC_LINK_STS,
- .mac_link_dup_sts = RTL839X_MAC_LINK_DUP_STS,
- .mac_link_spd_sts = rtl839x_mac_link_spd_sts,
- .mac_rx_pause_sts = RTL839X_MAC_RX_PAUSE_STS,
- .mac_tx_pause_sts = RTL839X_MAC_TX_PAUSE_STS,
.read_l2_entry_using_hash = rtl839x_read_l2_entry_using_hash,
.write_l2_entry_using_hash = rtl839x_write_l2_entry_using_hash,
.read_cam = rtl839x_read_cam,
return RTL930X_MAC_L2_PORT_CTRL(p);
}
-static inline int rtl930x_mac_link_spd_sts(int p)
-{
- return RTL930X_MAC_LINK_SPD_STS(p);
-}
-
static u64 rtl930x_l2_hash_seed(u64 mac, u32 vid)
{
u64 v = vid;
.mir_ctrl = RTL930X_MIR_CTRL,
.mir_dpm = RTL930X_MIR_DPM_CTRL,
.mir_spm = RTL930X_MIR_SPM_CTRL,
- .mac_link_sts = RTL930X_MAC_LINK_STS,
- .mac_link_dup_sts = RTL930X_MAC_LINK_DUP_STS,
- .mac_link_spd_sts = rtl930x_mac_link_spd_sts,
- .mac_rx_pause_sts = RTL930X_MAC_RX_PAUSE_STS,
- .mac_tx_pause_sts = RTL930X_MAC_TX_PAUSE_STS,
.read_l2_entry_using_hash = rtl930x_read_l2_entry_using_hash,
.write_l2_entry_using_hash = rtl930x_write_l2_entry_using_hash,
.read_cam = rtl930x_read_cam,
return RTL931X_MAC_FORCE_MODE_CTRL + (p << 2);
}
-static inline int rtl931x_mac_link_spd_sts(int p)
-{
- return RTL931X_MAC_LINK_SPD_STS + (((p >> 3) << 2));
-}
-
static inline int rtl931x_mac_port_ctrl(int p)
{
return RTL931X_MAC_L2_PORT_CTRL + (p << 7);
.mir_ctrl = RTL931X_MIR_CTRL,
.mir_dpm = RTL931X_MIR_DPM_CTRL,
.mir_spm = RTL931X_MIR_SPM_CTRL,
- .mac_link_sts = RTL931X_MAC_LINK_STS,
- .mac_link_dup_sts = RTL931X_MAC_LINK_DUP_STS,
- .mac_link_spd_sts = rtl931x_mac_link_spd_sts,
- .mac_rx_pause_sts = RTL931X_MAC_RX_PAUSE_STS,
- .mac_tx_pause_sts = RTL931X_MAC_TX_PAUSE_STS,
.read_l2_entry_using_hash = rtl931x_read_l2_entry_using_hash,
.write_l2_entry_using_hash = rtl931x_write_l2_entry_using_hash,
.read_cam = rtl931x_read_cam,
link->port = port;
link->sds = sds;
link->pcs.ops = ctrl->cfg->pcs_ops;
+ link->pcs.neg_mode = true;
ctrl->link[port] = link;