From 02074acc74781a32a6105c49d463cc77f759ea8b Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 22 Jun 2020 17:21:43 +0100 Subject: net: mvneta: convert to phylink pcs operations An initial stab at converting mvneta to PCS operations. There's a few FIXMEs to be solved. Signed-off-by: Russell King --- drivers/net/ethernet/marvell/mvneta.c | 135 +++++++++++++++++++++------------- 1 file changed, 84 insertions(+), 51 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 2648033e61db..5bc195d80f56 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -490,6 +490,7 @@ struct mvneta_port { unsigned int tx_csum_limit; struct phylink *phylink; struct phylink_config phylink_config; + struct phylink_pcs phylink_pcs; struct phy *comphy; struct mvneta_bm *bm_priv; @@ -3762,6 +3763,86 @@ static int mvneta_set_mac_addr(struct net_device *dev, void *addr) return 0; } +static struct mvneta_port *mvneta_pcs_to_port(struct phylink_pcs *pcs) +{ + return container_of(pcs, struct mvneta_port, phylink_pcs); +} + +static void mvneta_pcs_get_state(struct phylink_pcs *pcs, + struct phylink_link_state *state) +{ + struct mvneta_port *pp = mvneta_pcs_to_port(pcs); + u32 gmac_stat; + + gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS); + + if (gmac_stat & MVNETA_GMAC_SPEED_1000) + state->speed = + state->interface == PHY_INTERFACE_MODE_2500BASEX ? + SPEED_2500 : SPEED_1000; + else if (gmac_stat & MVNETA_GMAC_SPEED_100) + state->speed = SPEED_100; + else + state->speed = SPEED_10; + + state->an_complete = !!(gmac_stat & MVNETA_GMAC_AN_COMPLETE); + state->link = !!(gmac_stat & MVNETA_GMAC_LINK_UP); + state->duplex = !!(gmac_stat & MVNETA_GMAC_FULL_DUPLEX); + + if (gmac_stat & MVNETA_GMAC_RX_FLOW_CTRL_ENABLE) + state->pause |= MLO_PAUSE_RX; + if (gmac_stat & MVNETA_GMAC_TX_FLOW_CTRL_ENABLE) + state->pause |= MLO_PAUSE_TX; +} + +static int mvneta_pcs_config(struct phylink_pcs *pcs, + unsigned int mode, phy_interface_t interface, + const unsigned long *advertising, + bool permit_pause_to_mac) +{ + struct mvneta_port *pp = mvneta_pcs_to_port(pcs); + u32 mask, val, an, old_an, changed; + + mask = MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL | MVNETA_GMAC_AN_FLOW_CTRL_EN; + val = 0; + if (phylink_test(advertising, Pause)) + val |= MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL; + + /* The FLOW_CTRL_EN bit selects either the hardware automatically + * or the CONFIG_FLOW_CTRL manually controls the GMAC pause mode. + */ + if (phylink_autoneg_inband(mode) && + phy_interface_mode_is_8023z(interface) && + permit_pause_to_mac) + val |= MVNETA_GMAC_AN_FLOW_CTRL_EN; + + old_an = an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); + an = (an & ~mask) | val; + changed = old_an ^ an; + if (changed) + mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, an); + + /* We are only interested in the advertisement bits changing */ + return !!(changed & MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL); +} + +static void mvneta_pcs_an_restart(struct phylink_pcs *pcs) +{ + struct mvneta_port *pp = mvneta_pcs_to_port(pcs); + u32 gmac_an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); + + mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, + gmac_an | MVNETA_GMAC_INBAND_RESTART_AN); + mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, + gmac_an & ~MVNETA_GMAC_INBAND_RESTART_AN); +} + +static const struct phylink_pcs_ops mvneta_phylink_pcs_ops = { + .pcs_get_state = mvneta_pcs_get_state, + .pcs_config = mvneta_pcs_config, + .pcs_an_restart = mvneta_pcs_an_restart, +}; + static void mvneta_validate(struct phylink_config *config, unsigned long *supported, struct phylink_link_state *state) @@ -3816,47 +3897,6 @@ static void mvneta_validate(struct phylink_config *config, phylink_helper_basex_speed(state); } -static void mvneta_mac_pcs_get_state(struct phylink_config *config, - struct phylink_link_state *state) -{ - struct net_device *ndev = to_net_dev(config->dev); - struct mvneta_port *pp = netdev_priv(ndev); - u32 gmac_stat; - - gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS); - - if (gmac_stat & MVNETA_GMAC_SPEED_1000) - state->speed = - state->interface == PHY_INTERFACE_MODE_2500BASEX ? - SPEED_2500 : SPEED_1000; - else if (gmac_stat & MVNETA_GMAC_SPEED_100) - state->speed = SPEED_100; - else - state->speed = SPEED_10; - - state->an_complete = !!(gmac_stat & MVNETA_GMAC_AN_COMPLETE); - state->link = !!(gmac_stat & MVNETA_GMAC_LINK_UP); - state->duplex = !!(gmac_stat & MVNETA_GMAC_FULL_DUPLEX); - - state->pause = 0; - if (gmac_stat & MVNETA_GMAC_RX_FLOW_CTRL_ENABLE) - state->pause |= MLO_PAUSE_RX; - if (gmac_stat & MVNETA_GMAC_TX_FLOW_CTRL_ENABLE) - state->pause |= MLO_PAUSE_TX; -} - -static void mvneta_mac_an_restart(struct phylink_config *config) -{ - struct net_device *ndev = to_net_dev(config->dev); - struct mvneta_port *pp = netdev_priv(ndev); - u32 gmac_an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); - - mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, - gmac_an | MVNETA_GMAC_INBAND_RESTART_AN); - mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, - gmac_an & ~MVNETA_GMAC_INBAND_RESTART_AN); -} - static int mvneta_mac_prepare(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { @@ -3902,8 +3942,6 @@ static void mvneta_mac_config(struct phylink_config *config, unsigned int mode, new_an = gmac_an & ~(MVNETA_GMAC_INBAND_AN_ENABLE | MVNETA_GMAC_INBAND_RESTART_AN | MVNETA_GMAC_AN_SPEED_EN | - MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL | - MVNETA_GMAC_AN_FLOW_CTRL_EN | MVNETA_GMAC_AN_DUPLEX_EN); /* Even though it might look weird, when we're configured in @@ -3916,9 +3954,6 @@ static void mvneta_mac_config(struct phylink_config *config, unsigned int mode, phy_interface_mode_is_8023z(state->interface)) new_ctrl2 |= MVNETA_GMAC2_PCS_ENABLE; - if (phylink_test(state->advertising, Pause)) - new_an |= MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL; - if (!phylink_autoneg_inband(mode)) { /* Phy or fixed speed - nothing to do, leave the * configured speed, duplex and flow control as-is. @@ -3942,9 +3977,6 @@ static void mvneta_mac_config(struct phylink_config *config, unsigned int mode, MVNETA_GMAC_CONFIG_GMII_SPEED | /* The MAC only supports FD mode */ MVNETA_GMAC_CONFIG_FULL_DUPLEX; - - if (state->pause & MLO_PAUSE_AN && state->an_enabled) - new_an |= MVNETA_GMAC_AN_FLOW_CTRL_EN; } /* When at 2.5G, the link partner can send frames with shortened @@ -4081,8 +4113,6 @@ static void mvneta_mac_link_up(struct phylink_config *config, static const struct phylink_mac_ops mvneta_phylink_ops = { .validate = mvneta_validate, - .mac_pcs_get_state = mvneta_mac_pcs_get_state, - .mac_an_restart = mvneta_mac_an_restart, .mac_prepare = mvneta_mac_prepare, .mac_config = mvneta_mac_config, .mac_finish = mvneta_mac_finish, @@ -5102,6 +5132,9 @@ static int mvneta_probe(struct platform_device *pdev) goto err_free_irq; } + pp->phylink_pcs.ops = &mvneta_phylink_pcs_ops; + phylink_set_pcs(phylink, &pp->phylink_pcs); + dev->tx_queue_len = MVNETA_MAX_TXD; dev->watchdog_timeo = 5 * HZ; dev->netdev_ops = &mvneta_netdev_ops; -- cgit