mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 22:52:19 +02:00
net: dsa: vsc73xx: convert to PHYLINK
This patch replaces the adjust_link api with the phylink apis that provide equivalent functionality. The remaining functionality from the adjust_link is now covered in the mac_link_* and mac_config from phylink_mac_ops structure. Removes: .adjust_link Adds phylink_mac_ops structure: .mac_config .mac_link_up .mac_link_down Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com> Link: https://lore.kernel.org/r/20240417205048.3542839-3-paweldembicki@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
eb7e33d01d
commit
21fc3416ea
|
|
@ -717,16 +717,111 @@ static void vsc73xx_init_port(struct vsc73xx *vsc, int port)
|
|||
port, VSC73XX_C_RX0, 0);
|
||||
}
|
||||
|
||||
static void vsc73xx_adjust_enable_port(struct vsc73xx *vsc,
|
||||
int port, struct phy_device *phydev,
|
||||
u32 initval)
|
||||
static void vsc73xx_reset_port(struct vsc73xx *vsc, int port, u32 initval)
|
||||
{
|
||||
u32 val = initval;
|
||||
int ret, err;
|
||||
u32 val;
|
||||
|
||||
/* Disable RX on this port */
|
||||
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
|
||||
VSC73XX_MAC_CFG,
|
||||
VSC73XX_MAC_CFG_RX_EN, 0);
|
||||
|
||||
/* Discard packets */
|
||||
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
|
||||
VSC73XX_ARBDISC, BIT(port), BIT(port));
|
||||
|
||||
/* Wait until queue is empty */
|
||||
ret = read_poll_timeout(vsc73xx_read, err,
|
||||
err < 0 || (val & BIT(port)),
|
||||
VSC73XX_POLL_SLEEP_US,
|
||||
VSC73XX_POLL_TIMEOUT_US, false,
|
||||
vsc, VSC73XX_BLOCK_ARBITER, 0,
|
||||
VSC73XX_ARBEMPTY, &val);
|
||||
if (ret)
|
||||
dev_err(vsc->dev,
|
||||
"timeout waiting for block arbiter\n");
|
||||
else if (err < 0)
|
||||
dev_err(vsc->dev, "error reading arbiter\n");
|
||||
|
||||
/* Put this port into reset */
|
||||
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG,
|
||||
VSC73XX_MAC_CFG_RESET | initval);
|
||||
}
|
||||
|
||||
static void vsc73xx_mac_config(struct phylink_config *config, unsigned int mode,
|
||||
const struct phylink_link_state *state)
|
||||
{
|
||||
struct dsa_port *dp = dsa_phylink_to_port(config);
|
||||
struct vsc73xx *vsc = dp->ds->priv;
|
||||
int port = dp->index;
|
||||
|
||||
/* Special handling of the CPU-facing port */
|
||||
if (port == CPU_PORT) {
|
||||
/* Other ports are already initialized but not this one */
|
||||
vsc73xx_init_port(vsc, CPU_PORT);
|
||||
/* Select the external port for this interface (EXT_PORT)
|
||||
* Enable the GMII GTX external clock
|
||||
* Use double data rate (DDR mode)
|
||||
*/
|
||||
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
|
||||
CPU_PORT,
|
||||
VSC73XX_ADVPORTM,
|
||||
VSC73XX_ADVPORTM_EXT_PORT |
|
||||
VSC73XX_ADVPORTM_ENA_GTX |
|
||||
VSC73XX_ADVPORTM_DDR_MODE);
|
||||
}
|
||||
}
|
||||
|
||||
static void vsc73xx_mac_link_down(struct phylink_config *config,
|
||||
unsigned int mode, phy_interface_t interface)
|
||||
{
|
||||
struct dsa_port *dp = dsa_phylink_to_port(config);
|
||||
struct vsc73xx *vsc = dp->ds->priv;
|
||||
int port = dp->index;
|
||||
|
||||
/* This routine is described in the datasheet (below ARBDISC register
|
||||
* description)
|
||||
*/
|
||||
vsc73xx_reset_port(vsc, port, 0);
|
||||
|
||||
/* Allow backward dropping of frames from this port */
|
||||
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
|
||||
VSC73XX_SBACKWDROP, BIT(port), BIT(port));
|
||||
|
||||
/* Receive mask (disable forwarding) */
|
||||
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
|
||||
VSC73XX_RECVMASK, BIT(port), 0);
|
||||
}
|
||||
|
||||
static void vsc73xx_mac_link_up(struct phylink_config *config,
|
||||
struct phy_device *phy, unsigned int mode,
|
||||
phy_interface_t interface, int speed,
|
||||
int duplex, bool tx_pause, bool rx_pause)
|
||||
{
|
||||
struct dsa_port *dp = dsa_phylink_to_port(config);
|
||||
struct vsc73xx *vsc = dp->ds->priv;
|
||||
int port = dp->index;
|
||||
u32 val;
|
||||
u8 seed;
|
||||
|
||||
/* Reset this port FIXME: break out subroutine */
|
||||
val |= VSC73XX_MAC_CFG_RESET;
|
||||
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG, val);
|
||||
if (speed == SPEED_1000)
|
||||
val = VSC73XX_MAC_CFG_GIGA_MODE | VSC73XX_MAC_CFG_TX_IPG_1000M;
|
||||
else
|
||||
val = VSC73XX_MAC_CFG_TX_IPG_100_10M;
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_RGMII)
|
||||
val |= VSC73XX_MAC_CFG_CLK_SEL_1000M;
|
||||
else
|
||||
val |= VSC73XX_MAC_CFG_CLK_SEL_EXT;
|
||||
|
||||
if (duplex == DUPLEX_FULL)
|
||||
val |= VSC73XX_MAC_CFG_FDX;
|
||||
|
||||
/* This routine is described in the datasheet (below ARBDISC register
|
||||
* description)
|
||||
*/
|
||||
vsc73xx_reset_port(vsc, port, val);
|
||||
|
||||
/* Seed the port randomness with randomness */
|
||||
get_random_bytes(&seed, 1);
|
||||
|
|
@ -745,6 +840,14 @@ static void vsc73xx_adjust_enable_port(struct vsc73xx *vsc,
|
|||
VSC73XX_FCCONF_FLOW_CTRL_OBEY |
|
||||
0xff);
|
||||
|
||||
/* Accept packets again */
|
||||
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
|
||||
VSC73XX_ARBDISC, BIT(port), 0);
|
||||
|
||||
/* Enable port (forwarding) in the receive mask */
|
||||
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
|
||||
VSC73XX_RECVMASK, BIT(port), BIT(port));
|
||||
|
||||
/* Disallow backward dropping of frames from this port */
|
||||
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
|
||||
VSC73XX_SBACKWDROP, BIT(port), 0);
|
||||
|
|
@ -757,125 +860,6 @@ static void vsc73xx_adjust_enable_port(struct vsc73xx *vsc,
|
|||
VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN);
|
||||
}
|
||||
|
||||
static void vsc73xx_adjust_link(struct dsa_switch *ds, int port,
|
||||
struct phy_device *phydev)
|
||||
{
|
||||
struct vsc73xx *vsc = ds->priv;
|
||||
u32 val;
|
||||
|
||||
/* Special handling of the CPU-facing port */
|
||||
if (port == CPU_PORT) {
|
||||
/* Other ports are already initialized but not this one */
|
||||
vsc73xx_init_port(vsc, CPU_PORT);
|
||||
/* Select the external port for this interface (EXT_PORT)
|
||||
* Enable the GMII GTX external clock
|
||||
* Use double data rate (DDR mode)
|
||||
*/
|
||||
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
|
||||
CPU_PORT,
|
||||
VSC73XX_ADVPORTM,
|
||||
VSC73XX_ADVPORTM_EXT_PORT |
|
||||
VSC73XX_ADVPORTM_ENA_GTX |
|
||||
VSC73XX_ADVPORTM_DDR_MODE);
|
||||
}
|
||||
|
||||
/* This is the MAC confiuration that always need to happen
|
||||
* after a PHY or the CPU port comes up or down.
|
||||
*/
|
||||
if (!phydev->link) {
|
||||
int ret, err;
|
||||
|
||||
dev_dbg(vsc->dev, "port %d: went down\n",
|
||||
port);
|
||||
|
||||
/* Disable RX on this port */
|
||||
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
|
||||
VSC73XX_MAC_CFG,
|
||||
VSC73XX_MAC_CFG_RX_EN, 0);
|
||||
|
||||
/* Discard packets */
|
||||
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
|
||||
VSC73XX_ARBDISC, BIT(port), BIT(port));
|
||||
|
||||
/* Wait until queue is empty */
|
||||
ret = read_poll_timeout(vsc73xx_read, err,
|
||||
err < 0 || (val & BIT(port)),
|
||||
VSC73XX_POLL_SLEEP_US,
|
||||
VSC73XX_POLL_TIMEOUT_US, false,
|
||||
vsc, VSC73XX_BLOCK_ARBITER, 0,
|
||||
VSC73XX_ARBEMPTY, &val);
|
||||
if (ret)
|
||||
dev_err(vsc->dev,
|
||||
"timeout waiting for block arbiter\n");
|
||||
else if (err < 0)
|
||||
dev_err(vsc->dev, "error reading arbiter\n");
|
||||
|
||||
/* Put this port into reset */
|
||||
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG,
|
||||
VSC73XX_MAC_CFG_RESET);
|
||||
|
||||
/* Accept packets again */
|
||||
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
|
||||
VSC73XX_ARBDISC, BIT(port), 0);
|
||||
|
||||
/* Allow backward dropping of frames from this port */
|
||||
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
|
||||
VSC73XX_SBACKWDROP, BIT(port), BIT(port));
|
||||
|
||||
/* Receive mask (disable forwarding) */
|
||||
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
|
||||
VSC73XX_RECVMASK, BIT(port), 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Figure out what speed was negotiated */
|
||||
if (phydev->speed == SPEED_1000) {
|
||||
dev_dbg(vsc->dev, "port %d: 1000 Mbit mode full duplex\n",
|
||||
port);
|
||||
|
||||
/* Set up default for internal port or external RGMII */
|
||||
if (phydev->interface == PHY_INTERFACE_MODE_RGMII)
|
||||
val = VSC73XX_MAC_CFG_1000M_F_RGMII;
|
||||
else
|
||||
val = VSC73XX_MAC_CFG_1000M_F_PHY;
|
||||
vsc73xx_adjust_enable_port(vsc, port, phydev, val);
|
||||
} else if (phydev->speed == SPEED_100) {
|
||||
if (phydev->duplex == DUPLEX_FULL) {
|
||||
val = VSC73XX_MAC_CFG_100_10M_F_PHY;
|
||||
dev_dbg(vsc->dev,
|
||||
"port %d: 100 Mbit full duplex mode\n",
|
||||
port);
|
||||
} else {
|
||||
val = VSC73XX_MAC_CFG_100_10M_H_PHY;
|
||||
dev_dbg(vsc->dev,
|
||||
"port %d: 100 Mbit half duplex mode\n",
|
||||
port);
|
||||
}
|
||||
vsc73xx_adjust_enable_port(vsc, port, phydev, val);
|
||||
} else if (phydev->speed == SPEED_10) {
|
||||
if (phydev->duplex == DUPLEX_FULL) {
|
||||
val = VSC73XX_MAC_CFG_100_10M_F_PHY;
|
||||
dev_dbg(vsc->dev,
|
||||
"port %d: 10 Mbit full duplex mode\n",
|
||||
port);
|
||||
} else {
|
||||
val = VSC73XX_MAC_CFG_100_10M_H_PHY;
|
||||
dev_dbg(vsc->dev,
|
||||
"port %d: 10 Mbit half duplex mode\n",
|
||||
port);
|
||||
}
|
||||
vsc73xx_adjust_enable_port(vsc, port, phydev, val);
|
||||
} else {
|
||||
dev_err(vsc->dev,
|
||||
"could not adjust link: unknown speed\n");
|
||||
}
|
||||
|
||||
/* Enable port (forwarding) in the receieve mask */
|
||||
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
|
||||
VSC73XX_RECVMASK, BIT(port), BIT(port));
|
||||
}
|
||||
|
||||
static int vsc73xx_port_enable(struct dsa_switch *ds, int port,
|
||||
struct phy_device *phy)
|
||||
{
|
||||
|
|
@ -1055,12 +1039,17 @@ static void vsc73xx_phylink_get_caps(struct dsa_switch *dsa, int port,
|
|||
config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000;
|
||||
}
|
||||
|
||||
static const struct phylink_mac_ops vsc73xx_phylink_mac_ops = {
|
||||
.mac_config = vsc73xx_mac_config,
|
||||
.mac_link_down = vsc73xx_mac_link_down,
|
||||
.mac_link_up = vsc73xx_mac_link_up,
|
||||
};
|
||||
|
||||
static const struct dsa_switch_ops vsc73xx_ds_ops = {
|
||||
.get_tag_protocol = vsc73xx_get_tag_protocol,
|
||||
.setup = vsc73xx_setup,
|
||||
.phy_read = vsc73xx_phy_read,
|
||||
.phy_write = vsc73xx_phy_write,
|
||||
.adjust_link = vsc73xx_adjust_link,
|
||||
.get_strings = vsc73xx_get_strings,
|
||||
.get_ethtool_stats = vsc73xx_get_ethtool_stats,
|
||||
.get_sset_count = vsc73xx_get_sset_count,
|
||||
|
|
@ -1217,6 +1206,7 @@ int vsc73xx_probe(struct vsc73xx *vsc)
|
|||
vsc->ds->priv = vsc;
|
||||
|
||||
vsc->ds->ops = &vsc73xx_ds_ops;
|
||||
vsc->ds->phylink_mac_ops = &vsc73xx_phylink_mac_ops;
|
||||
ret = dsa_register_switch(vsc->ds);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to register switch (%d)\n", ret);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user