Skip to content

Commit 75df1a2

Browse files
committed
Merge branch 'phylink-pcs-validation'
Russell King says: ==================== net: phylink: add PCS validation This series allows phylink to include the PCS in its validation step. There are two reasons to make this change: 1. Some of the network drivers that are making use of the split PCS support are already manually calling into their PCS drivers to perform validation. E.g. stmmac with xpcs. 2. Logically, some network drivers such as mvneta and mvpp2, the restriction we impose in the validate() callback is a property of the "PCS" block that we provide rather than the MAC. This series: 1. Gives phylink a mechanism to query the MAC driver which PCS is wishes to use for the PHY interface mode. This is necessary to allow the PCS to be involved in the validation step without making changes to the configuration. 2. Provide a pcs_validate() method that PCS can implement. This follows a similar model to the MAC's validate() callback, but with some minor differences due to observations from the various implementations. E.g. returning an error code for not-supported and the way the advertising bitmap is masked. 3. Convert mvpp2 and mvneta to this as examples of its use. Further Conversions are in the pipeline, including for stmmac+xpcs, as well as some DSA drivers. Note that DSA conversion to this is conditional upon all DSA drivers populating their supported_interfaces bitmap, since this is required before mac_select_pcs() can be used. Existing drivers that set a PCS in mac_prepare() or mac_config(), or shortly after phylink_create() will continue to work. However, it should be noted that mac_select_pcs() will be called during phylink_create(), and thus any PCS returned by mac_select_pcs() must be available by this time - or we drop the check in phylink_create(). v2: fix kerneldoc typo in patch 1. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 4134c84 + d8c3669 commit 75df1a2

File tree

5 files changed

+337
-144
lines changed

5 files changed

+337
-144
lines changed

drivers/net/ethernet/marvell/mvneta.c

Lines changed: 150 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ struct mvneta_port {
526526
unsigned int tx_csum_limit;
527527
struct phylink *phylink;
528528
struct phylink_config phylink_config;
529+
struct phylink_pcs phylink_pcs;
529530
struct phy *comphy;
530531

531532
struct mvneta_bm *bm_priv;
@@ -3846,29 +3847,31 @@ static int mvneta_set_mac_addr(struct net_device *dev, void *addr)
38463847
return 0;
38473848
}
38483849

3849-
static void mvneta_validate(struct phylink_config *config,
3850-
unsigned long *supported,
3851-
struct phylink_link_state *state)
3850+
static struct mvneta_port *mvneta_pcs_to_port(struct phylink_pcs *pcs)
3851+
{
3852+
return container_of(pcs, struct mvneta_port, phylink_pcs);
3853+
}
3854+
3855+
static int mvneta_pcs_validate(struct phylink_pcs *pcs,
3856+
unsigned long *supported,
3857+
const struct phylink_link_state *state)
38523858
{
38533859
/* We only support QSGMII, SGMII, 802.3z and RGMII modes.
38543860
* When in 802.3z mode, we must have AN enabled:
38553861
* "Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ...
38563862
* When <PortType> = 1 (1000BASE-X) this field must be set to 1."
38573863
*/
38583864
if (phy_interface_mode_is_8023z(state->interface) &&
3859-
!phylink_test(state->advertising, Autoneg)) {
3860-
linkmode_zero(supported);
3861-
return;
3862-
}
3865+
!phylink_test(state->advertising, Autoneg))
3866+
return -EINVAL;
38633867

3864-
phylink_generic_validate(config, supported, state);
3868+
return 0;
38653869
}
38663870

3867-
static void mvneta_mac_pcs_get_state(struct phylink_config *config,
3868-
struct phylink_link_state *state)
3871+
static void mvneta_pcs_get_state(struct phylink_pcs *pcs,
3872+
struct phylink_link_state *state)
38693873
{
3870-
struct net_device *ndev = to_net_dev(config->dev);
3871-
struct mvneta_port *pp = netdev_priv(ndev);
3874+
struct mvneta_port *pp = mvneta_pcs_to_port(pcs);
38723875
u32 gmac_stat;
38733876

38743877
gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS);
@@ -3886,17 +3889,71 @@ static void mvneta_mac_pcs_get_state(struct phylink_config *config,
38863889
state->link = !!(gmac_stat & MVNETA_GMAC_LINK_UP);
38873890
state->duplex = !!(gmac_stat & MVNETA_GMAC_FULL_DUPLEX);
38883891

3889-
state->pause = 0;
38903892
if (gmac_stat & MVNETA_GMAC_RX_FLOW_CTRL_ENABLE)
38913893
state->pause |= MLO_PAUSE_RX;
38923894
if (gmac_stat & MVNETA_GMAC_TX_FLOW_CTRL_ENABLE)
38933895
state->pause |= MLO_PAUSE_TX;
38943896
}
38953897

3896-
static void mvneta_mac_an_restart(struct phylink_config *config)
3898+
static int mvneta_pcs_config(struct phylink_pcs *pcs,
3899+
unsigned int mode, phy_interface_t interface,
3900+
const unsigned long *advertising,
3901+
bool permit_pause_to_mac)
38973902
{
3898-
struct net_device *ndev = to_net_dev(config->dev);
3899-
struct mvneta_port *pp = netdev_priv(ndev);
3903+
struct mvneta_port *pp = mvneta_pcs_to_port(pcs);
3904+
u32 mask, val, an, old_an, changed;
3905+
3906+
mask = MVNETA_GMAC_INBAND_AN_ENABLE |
3907+
MVNETA_GMAC_INBAND_RESTART_AN |
3908+
MVNETA_GMAC_AN_SPEED_EN |
3909+
MVNETA_GMAC_AN_FLOW_CTRL_EN |
3910+
MVNETA_GMAC_AN_DUPLEX_EN;
3911+
3912+
if (phylink_autoneg_inband(mode)) {
3913+
mask |= MVNETA_GMAC_CONFIG_MII_SPEED |
3914+
MVNETA_GMAC_CONFIG_GMII_SPEED |
3915+
MVNETA_GMAC_CONFIG_FULL_DUPLEX;
3916+
val = MVNETA_GMAC_INBAND_AN_ENABLE;
3917+
3918+
if (interface == PHY_INTERFACE_MODE_SGMII) {
3919+
/* SGMII mode receives the speed and duplex from PHY */
3920+
val |= MVNETA_GMAC_AN_SPEED_EN |
3921+
MVNETA_GMAC_AN_DUPLEX_EN;
3922+
} else {
3923+
/* 802.3z mode has fixed speed and duplex */
3924+
val |= MVNETA_GMAC_CONFIG_GMII_SPEED |
3925+
MVNETA_GMAC_CONFIG_FULL_DUPLEX;
3926+
3927+
/* The FLOW_CTRL_EN bit selects either the hardware
3928+
* automatically or the CONFIG_FLOW_CTRL manually
3929+
* controls the GMAC pause mode.
3930+
*/
3931+
if (permit_pause_to_mac)
3932+
val |= MVNETA_GMAC_AN_FLOW_CTRL_EN;
3933+
3934+
/* Update the advertisement bits */
3935+
mask |= MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL;
3936+
if (phylink_test(advertising, Pause))
3937+
val |= MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL;
3938+
}
3939+
} else {
3940+
/* Phy or fixed speed - disable in-band AN modes */
3941+
val = 0;
3942+
}
3943+
3944+
old_an = an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
3945+
an = (an & ~mask) | val;
3946+
changed = old_an ^ an;
3947+
if (changed)
3948+
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, an);
3949+
3950+
/* We are only interested in the advertisement bits changing */
3951+
return !!(changed & MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL);
3952+
}
3953+
3954+
static void mvneta_pcs_an_restart(struct phylink_pcs *pcs)
3955+
{
3956+
struct mvneta_port *pp = mvneta_pcs_to_port(pcs);
39003957
u32 gmac_an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
39013958

39023959
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG,
@@ -3905,6 +3962,47 @@ static void mvneta_mac_an_restart(struct phylink_config *config)
39053962
gmac_an & ~MVNETA_GMAC_INBAND_RESTART_AN);
39063963
}
39073964

3965+
static const struct phylink_pcs_ops mvneta_phylink_pcs_ops = {
3966+
.pcs_validate = mvneta_pcs_validate,
3967+
.pcs_get_state = mvneta_pcs_get_state,
3968+
.pcs_config = mvneta_pcs_config,
3969+
.pcs_an_restart = mvneta_pcs_an_restart,
3970+
};
3971+
3972+
static int mvneta_mac_prepare(struct phylink_config *config, unsigned int mode,
3973+
phy_interface_t interface)
3974+
{
3975+
struct net_device *ndev = to_net_dev(config->dev);
3976+
struct mvneta_port *pp = netdev_priv(ndev);
3977+
u32 val;
3978+
3979+
if (pp->phy_interface != interface ||
3980+
phylink_autoneg_inband(mode)) {
3981+
/* Force the link down when changing the interface or if in
3982+
* in-band mode. According to Armada 370 documentation, we
3983+
* can only change the port mode and in-band enable when the
3984+
* link is down.
3985+
*/
3986+
val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
3987+
val &= ~MVNETA_GMAC_FORCE_LINK_PASS;
3988+
val |= MVNETA_GMAC_FORCE_LINK_DOWN;
3989+
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
3990+
}
3991+
3992+
if (pp->phy_interface != interface)
3993+
WARN_ON(phy_power_off(pp->comphy));
3994+
3995+
/* Enable the 1ms clock */
3996+
if (phylink_autoneg_inband(mode)) {
3997+
unsigned long rate = clk_get_rate(pp->clk);
3998+
3999+
mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER,
4000+
MVNETA_GMAC_1MS_CLOCK_ENABLE | (rate / 1000));
4001+
}
4002+
4003+
return 0;
4004+
}
4005+
39084006
static void mvneta_mac_config(struct phylink_config *config, unsigned int mode,
39094007
const struct phylink_link_state *state)
39104008
{
@@ -3913,20 +4011,11 @@ static void mvneta_mac_config(struct phylink_config *config, unsigned int mode,
39134011
u32 new_ctrl0, gmac_ctrl0 = mvreg_read(pp, MVNETA_GMAC_CTRL_0);
39144012
u32 new_ctrl2, gmac_ctrl2 = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
39154013
u32 new_ctrl4, gmac_ctrl4 = mvreg_read(pp, MVNETA_GMAC_CTRL_4);
3916-
u32 new_clk, gmac_clk = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
3917-
u32 new_an, gmac_an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
39184014

39194015
new_ctrl0 = gmac_ctrl0 & ~MVNETA_GMAC0_PORT_1000BASE_X;
39204016
new_ctrl2 = gmac_ctrl2 & ~(MVNETA_GMAC2_INBAND_AN_ENABLE |
39214017
MVNETA_GMAC2_PORT_RESET);
39224018
new_ctrl4 = gmac_ctrl4 & ~(MVNETA_GMAC4_SHORT_PREAMBLE_ENABLE);
3923-
new_clk = gmac_clk & ~MVNETA_GMAC_1MS_CLOCK_ENABLE;
3924-
new_an = gmac_an & ~(MVNETA_GMAC_INBAND_AN_ENABLE |
3925-
MVNETA_GMAC_INBAND_RESTART_AN |
3926-
MVNETA_GMAC_AN_SPEED_EN |
3927-
MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL |
3928-
MVNETA_GMAC_AN_FLOW_CTRL_EN |
3929-
MVNETA_GMAC_AN_DUPLEX_EN);
39304019

39314020
/* Even though it might look weird, when we're configured in
39324021
* SGMII or QSGMII mode, the RGMII bit needs to be set.
@@ -3938,80 +4027,30 @@ static void mvneta_mac_config(struct phylink_config *config, unsigned int mode,
39384027
phy_interface_mode_is_8023z(state->interface))
39394028
new_ctrl2 |= MVNETA_GMAC2_PCS_ENABLE;
39404029

3941-
if (phylink_test(state->advertising, Pause))
3942-
new_an |= MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL;
3943-
39444030
if (!phylink_autoneg_inband(mode)) {
39454031
/* Phy or fixed speed - nothing to do, leave the
39464032
* configured speed, duplex and flow control as-is.
39474033
*/
39484034
} else if (state->interface == PHY_INTERFACE_MODE_SGMII) {
39494035
/* SGMII mode receives the state from the PHY */
39504036
new_ctrl2 |= MVNETA_GMAC2_INBAND_AN_ENABLE;
3951-
new_clk = MVNETA_GMAC_1MS_CLOCK_ENABLE;
3952-
new_an = (new_an & ~(MVNETA_GMAC_FORCE_LINK_DOWN |
3953-
MVNETA_GMAC_FORCE_LINK_PASS |
3954-
MVNETA_GMAC_CONFIG_MII_SPEED |
3955-
MVNETA_GMAC_CONFIG_GMII_SPEED |
3956-
MVNETA_GMAC_CONFIG_FULL_DUPLEX)) |
3957-
MVNETA_GMAC_INBAND_AN_ENABLE |
3958-
MVNETA_GMAC_AN_SPEED_EN |
3959-
MVNETA_GMAC_AN_DUPLEX_EN;
39604037
} else {
39614038
/* 802.3z negotiation - only 1000base-X */
39624039
new_ctrl0 |= MVNETA_GMAC0_PORT_1000BASE_X;
3963-
new_clk = MVNETA_GMAC_1MS_CLOCK_ENABLE;
3964-
new_an = (new_an & ~(MVNETA_GMAC_FORCE_LINK_DOWN |
3965-
MVNETA_GMAC_FORCE_LINK_PASS |
3966-
MVNETA_GMAC_CONFIG_MII_SPEED)) |
3967-
MVNETA_GMAC_INBAND_AN_ENABLE |
3968-
MVNETA_GMAC_CONFIG_GMII_SPEED |
3969-
/* The MAC only supports FD mode */
3970-
MVNETA_GMAC_CONFIG_FULL_DUPLEX;
3971-
3972-
if (state->pause & MLO_PAUSE_AN && state->an_enabled)
3973-
new_an |= MVNETA_GMAC_AN_FLOW_CTRL_EN;
39744040
}
39754041

3976-
/* Set the 1ms clock divisor */
3977-
if (new_clk == MVNETA_GMAC_1MS_CLOCK_ENABLE)
3978-
new_clk |= clk_get_rate(pp->clk) / 1000;
3979-
3980-
/* Armada 370 documentation says we can only change the port mode
3981-
* and in-band enable when the link is down, so force it down
3982-
* while making these changes. We also do this for GMAC_CTRL2
3983-
*/
3984-
if ((new_ctrl0 ^ gmac_ctrl0) & MVNETA_GMAC0_PORT_1000BASE_X ||
3985-
(new_ctrl2 ^ gmac_ctrl2) & MVNETA_GMAC2_INBAND_AN_ENABLE ||
3986-
(new_an ^ gmac_an) & MVNETA_GMAC_INBAND_AN_ENABLE) {
3987-
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG,
3988-
(gmac_an & ~MVNETA_GMAC_FORCE_LINK_PASS) |
3989-
MVNETA_GMAC_FORCE_LINK_DOWN);
3990-
}
3991-
3992-
39934042
/* When at 2.5G, the link partner can send frames with shortened
39944043
* preambles.
39954044
*/
39964045
if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
39974046
new_ctrl4 |= MVNETA_GMAC4_SHORT_PREAMBLE_ENABLE;
39984047

3999-
if (pp->phy_interface != state->interface) {
4000-
if (pp->comphy)
4001-
WARN_ON(phy_power_off(pp->comphy));
4002-
WARN_ON(mvneta_config_interface(pp, state->interface));
4003-
}
4004-
40054048
if (new_ctrl0 != gmac_ctrl0)
40064049
mvreg_write(pp, MVNETA_GMAC_CTRL_0, new_ctrl0);
40074050
if (new_ctrl2 != gmac_ctrl2)
40084051
mvreg_write(pp, MVNETA_GMAC_CTRL_2, new_ctrl2);
40094052
if (new_ctrl4 != gmac_ctrl4)
40104053
mvreg_write(pp, MVNETA_GMAC_CTRL_4, new_ctrl4);
4011-
if (new_clk != gmac_clk)
4012-
mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, new_clk);
4013-
if (new_an != gmac_an)
4014-
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, new_an);
40154054

40164055
if (gmac_ctrl2 & MVNETA_GMAC2_PORT_RESET) {
40174056
while ((mvreg_read(pp, MVNETA_GMAC_CTRL_2) &
@@ -4020,6 +4059,36 @@ static void mvneta_mac_config(struct phylink_config *config, unsigned int mode,
40204059
}
40214060
}
40224061

4062+
static int mvneta_mac_finish(struct phylink_config *config, unsigned int mode,
4063+
phy_interface_t interface)
4064+
{
4065+
struct net_device *ndev = to_net_dev(config->dev);
4066+
struct mvneta_port *pp = netdev_priv(ndev);
4067+
u32 val, clk;
4068+
4069+
/* Disable 1ms clock if not in in-band mode */
4070+
if (!phylink_autoneg_inband(mode)) {
4071+
clk = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
4072+
clk &= ~MVNETA_GMAC_1MS_CLOCK_ENABLE;
4073+
mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, clk);
4074+
}
4075+
4076+
if (pp->phy_interface != interface)
4077+
/* Enable the Serdes PHY */
4078+
WARN_ON(mvneta_config_interface(pp, interface));
4079+
4080+
/* Allow the link to come up if in in-band mode, otherwise the
4081+
* link is forced via mac_link_down()/mac_link_up()
4082+
*/
4083+
if (phylink_autoneg_inband(mode)) {
4084+
val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
4085+
val &= ~MVNETA_GMAC_FORCE_LINK_DOWN;
4086+
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
4087+
}
4088+
4089+
return 0;
4090+
}
4091+
40234092
static void mvneta_set_eee(struct mvneta_port *pp, bool enable)
40244093
{
40254094
u32 lpi_ctl1;
@@ -4106,10 +4175,10 @@ static void mvneta_mac_link_up(struct phylink_config *config,
41064175
}
41074176

41084177
static const struct phylink_mac_ops mvneta_phylink_ops = {
4109-
.validate = mvneta_validate,
4110-
.mac_pcs_get_state = mvneta_mac_pcs_get_state,
4111-
.mac_an_restart = mvneta_mac_an_restart,
4178+
.validate = phylink_generic_validate,
4179+
.mac_prepare = mvneta_mac_prepare,
41124180
.mac_config = mvneta_mac_config,
4181+
.mac_finish = mvneta_mac_finish,
41134182
.mac_link_down = mvneta_mac_link_down,
41144183
.mac_link_up = mvneta_mac_link_up,
41154184
};
@@ -5275,7 +5344,6 @@ static int mvneta_probe(struct platform_device *pdev)
52755344

52765345
pp->phylink_config.dev = &dev->dev;
52775346
pp->phylink_config.type = PHYLINK_NETDEV;
5278-
pp->phylink_config.legacy_pre_march2020 = true;
52795347
pp->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_10 |
52805348
MAC_100 | MAC_1000FD | MAC_2500FD;
52815349

@@ -5350,6 +5418,9 @@ static int mvneta_probe(struct platform_device *pdev)
53505418
goto err_clk;
53515419
}
53525420

5421+
pp->phylink_pcs.ops = &mvneta_phylink_pcs_ops;
5422+
phylink_set_pcs(phylink, &pp->phylink_pcs);
5423+
53535424
/* Alloc per-cpu port structure */
53545425
pp->ports = alloc_percpu(struct mvneta_pcpu_port);
53555426
if (!pp->ports) {

drivers/net/ethernet/marvell/mvpp2/mvpp2.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1239,7 +1239,8 @@ struct mvpp2_port {
12391239
phy_interface_t phy_interface;
12401240
struct phylink *phylink;
12411241
struct phylink_config phylink_config;
1242-
struct phylink_pcs phylink_pcs;
1242+
struct phylink_pcs pcs_gmac;
1243+
struct phylink_pcs pcs_xlg;
12431244
struct phy *comphy;
12441245

12451246
struct mvpp2_bm_pool *pool_long;

0 commit comments

Comments
 (0)