Skip to content

Commit a5a6858

Browse files
Russell Kingdavem330
authored andcommitted
net: dsa: mv88e6xxx: extend phylink to Serdes PHYs
Extend the mv88e6xxx phylink implementation down to Serdes PHYs, which handle the PCS layer of such links. - Implement phylink PCS link state reading, so that we can provide ethtool with the linkmodes and link speed in the expected manner. Note: this will only be called for in-band negotiation, which is only supported by the serdes interfaces. - Implement phylink PCS configuration, so that the in-band AN and advertisement can be configured. - Implement phylink PCS negotiation restart, so that the in-band AN can be restarted. - Implement phylink PCS link up, so that when operating out-of-band, the Serdes can be configured for the appropriate fixed speed mode. Signed-off-by: Russell King <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 64d47d5 commit a5a6858

File tree

4 files changed

+480
-74
lines changed

4 files changed

+480
-74
lines changed

drivers/net/dsa/mv88e6xxx/chip.c

Lines changed: 153 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -419,9 +419,9 @@ static int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip,
419419
return 0;
420420
}
421421

422-
int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
423-
int speed, int duplex, int pause,
424-
phy_interface_t mode)
422+
static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
423+
int link, int speed, int duplex, int pause,
424+
phy_interface_t mode)
425425
{
426426
struct phylink_link_state state;
427427
int err;
@@ -488,6 +488,81 @@ static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
488488
return port < chip->info->num_internal_phys;
489489
}
490490

491+
static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port,
492+
struct phylink_link_state *state)
493+
{
494+
struct mv88e6xxx_chip *chip = ds->priv;
495+
u8 lane;
496+
int err;
497+
498+
mv88e6xxx_reg_lock(chip);
499+
lane = mv88e6xxx_serdes_get_lane(chip, port);
500+
if (lane && chip->info->ops->serdes_pcs_get_state)
501+
err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
502+
state);
503+
else
504+
err = -EOPNOTSUPP;
505+
mv88e6xxx_reg_unlock(chip);
506+
507+
return err;
508+
}
509+
510+
static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
511+
unsigned int mode,
512+
phy_interface_t interface,
513+
const unsigned long *advertise)
514+
{
515+
const struct mv88e6xxx_ops *ops = chip->info->ops;
516+
u8 lane;
517+
518+
if (ops->serdes_pcs_config) {
519+
lane = mv88e6xxx_serdes_get_lane(chip, port);
520+
if (lane)
521+
return ops->serdes_pcs_config(chip, port, lane, mode,
522+
interface, advertise);
523+
}
524+
525+
return 0;
526+
}
527+
528+
static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port)
529+
{
530+
struct mv88e6xxx_chip *chip = ds->priv;
531+
const struct mv88e6xxx_ops *ops;
532+
int err = 0;
533+
u8 lane;
534+
535+
ops = chip->info->ops;
536+
537+
if (ops->serdes_pcs_an_restart) {
538+
mv88e6xxx_reg_lock(chip);
539+
lane = mv88e6xxx_serdes_get_lane(chip, port);
540+
if (lane)
541+
err = ops->serdes_pcs_an_restart(chip, port, lane);
542+
mv88e6xxx_reg_unlock(chip);
543+
544+
if (err)
545+
dev_err(ds->dev, "p%d: failed to restart AN\n", port);
546+
}
547+
}
548+
549+
static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
550+
unsigned int mode,
551+
int speed, int duplex)
552+
{
553+
const struct mv88e6xxx_ops *ops = chip->info->ops;
554+
u8 lane;
555+
556+
if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) {
557+
lane = mv88e6xxx_serdes_get_lane(chip, port);
558+
if (lane)
559+
return ops->serdes_pcs_link_up(chip, port, lane,
560+
speed, duplex);
561+
}
562+
563+
return 0;
564+
}
565+
491566
static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port,
492567
unsigned long *mask,
493568
struct phylink_link_state *state)
@@ -592,22 +667,6 @@ static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
592667
phylink_helper_basex_speed(state);
593668
}
594669

595-
static int mv88e6xxx_link_state(struct dsa_switch *ds, int port,
596-
struct phylink_link_state *state)
597-
{
598-
struct mv88e6xxx_chip *chip = ds->priv;
599-
int err;
600-
601-
mv88e6xxx_reg_lock(chip);
602-
if (chip->info->ops->port_link_state)
603-
err = chip->info->ops->port_link_state(chip, port, state);
604-
else
605-
err = -EOPNOTSUPP;
606-
mv88e6xxx_reg_unlock(chip);
607-
608-
return err;
609-
}
610-
611670
static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
612671
unsigned int mode,
613672
const struct phylink_link_state *state)
@@ -629,6 +688,18 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
629688
* gets in the way.
630689
*/
631690
err = mv88e6xxx_port_config_interface(chip, port, state->interface);
691+
if (err && err != -EOPNOTSUPP)
692+
goto err_unlock;
693+
694+
err = mv88e6xxx_serdes_pcs_config(chip, port, mode, state->interface,
695+
state->advertising);
696+
/* FIXME: we should restart negotiation if something changed - which
697+
* is something we get if we convert to using phylinks PCS operations.
698+
*/
699+
if (err > 0)
700+
err = 0;
701+
702+
err_unlock:
632703
mv88e6xxx_reg_unlock(chip);
633704

634705
if (err && err != -EOPNOTSUPP)
@@ -683,9 +754,14 @@ static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
683754
/* FIXME: for an automedia port, should we force the link
684755
* down here - what if the link comes up due to "other" media
685756
* while we're bringing the port up, how is the exclusivity
686-
* handled in the Marvell hardware? E.g. port 4 on 88E6532
757+
* handled in the Marvell hardware? E.g. port 2 on 88E6390
687758
* shared between internal PHY and Serdes.
688759
*/
760+
err = mv88e6xxx_serdes_pcs_link_up(chip, port, mode, speed,
761+
duplex);
762+
if (err)
763+
goto error;
764+
689765
if (ops->port_set_speed) {
690766
err = ops->port_set_speed(chip, port, speed);
691767
if (err && err != -EOPNOTSUPP)
@@ -3557,6 +3633,11 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
35573633
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
35583634
.serdes_power = mv88e6390_serdes_power,
35593635
.serdes_get_lane = mv88e6341_serdes_get_lane,
3636+
/* Check status register pause & lpa register */
3637+
.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
3638+
.serdes_pcs_config = mv88e6390_serdes_pcs_config,
3639+
.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
3640+
.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
35603641
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
35613642
.serdes_irq_enable = mv88e6390_serdes_irq_enable,
35623643
.serdes_irq_status = mv88e6390_serdes_irq_status,
@@ -3729,6 +3810,10 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
37293810
.vtu_getnext = mv88e6352_g1_vtu_getnext,
37303811
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37313812
.serdes_get_lane = mv88e6352_serdes_get_lane,
3813+
.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
3814+
.serdes_pcs_config = mv88e6352_serdes_pcs_config,
3815+
.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
3816+
.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
37323817
.serdes_power = mv88e6352_serdes_power,
37333818
.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
37343819
.serdes_get_regs = mv88e6352_serdes_get_regs,
@@ -3822,6 +3907,10 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
38223907
.vtu_getnext = mv88e6352_g1_vtu_getnext,
38233908
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
38243909
.serdes_get_lane = mv88e6352_serdes_get_lane,
3910+
.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
3911+
.serdes_pcs_config = mv88e6352_serdes_pcs_config,
3912+
.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
3913+
.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
38253914
.serdes_power = mv88e6352_serdes_power,
38263915
.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
38273916
.serdes_irq_enable = mv88e6352_serdes_irq_enable,
@@ -3912,6 +4001,11 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
39124001
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
39134002
.serdes_power = mv88e6390_serdes_power,
39144003
.serdes_get_lane = mv88e6390_serdes_get_lane,
4004+
/* Check status register pause & lpa register */
4005+
.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4006+
.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4007+
.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4008+
.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
39154009
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
39164010
.serdes_irq_enable = mv88e6390_serdes_irq_enable,
39174011
.serdes_irq_status = mv88e6390_serdes_irq_status,
@@ -3968,6 +4062,11 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
39684062
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
39694063
.serdes_power = mv88e6390_serdes_power,
39704064
.serdes_get_lane = mv88e6390x_serdes_get_lane,
4065+
/* Check status register pause & lpa register */
4066+
.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4067+
.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4068+
.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4069+
.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
39714070
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
39724071
.serdes_irq_enable = mv88e6390_serdes_irq_enable,
39734072
.serdes_irq_status = mv88e6390_serdes_irq_status,
@@ -4023,6 +4122,11 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
40234122
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
40244123
.serdes_power = mv88e6390_serdes_power,
40254124
.serdes_get_lane = mv88e6390_serdes_get_lane,
4125+
/* Check status register pause & lpa register */
4126+
.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4127+
.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4128+
.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4129+
.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
40264130
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
40274131
.serdes_irq_enable = mv88e6390_serdes_irq_enable,
40284132
.serdes_irq_status = mv88e6390_serdes_irq_status,
@@ -4080,6 +4184,10 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
40804184
.vtu_getnext = mv88e6352_g1_vtu_getnext,
40814185
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
40824186
.serdes_get_lane = mv88e6352_serdes_get_lane,
4187+
.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
4188+
.serdes_pcs_config = mv88e6352_serdes_pcs_config,
4189+
.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
4190+
.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
40834191
.serdes_power = mv88e6352_serdes_power,
40844192
.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
40854193
.serdes_irq_enable = mv88e6352_serdes_irq_enable,
@@ -4176,6 +4284,11 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
41764284
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
41774285
.serdes_power = mv88e6390_serdes_power,
41784286
.serdes_get_lane = mv88e6390_serdes_get_lane,
4287+
/* Check status register pause & lpa register */
4288+
.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4289+
.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4290+
.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4291+
.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
41794292
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
41804293
.serdes_irq_enable = mv88e6390_serdes_irq_enable,
41814294
.serdes_irq_status = mv88e6390_serdes_irq_status,
@@ -4319,6 +4432,11 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
43194432
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
43204433
.serdes_power = mv88e6390_serdes_power,
43214434
.serdes_get_lane = mv88e6341_serdes_get_lane,
4435+
/* Check status register pause & lpa register */
4436+
.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4437+
.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4438+
.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4439+
.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
43224440
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
43234441
.serdes_irq_enable = mv88e6390_serdes_irq_enable,
43244442
.serdes_irq_status = mv88e6390_serdes_irq_status,
@@ -4458,6 +4576,10 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
44584576
.vtu_getnext = mv88e6352_g1_vtu_getnext,
44594577
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
44604578
.serdes_get_lane = mv88e6352_serdes_get_lane,
4579+
.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
4580+
.serdes_pcs_config = mv88e6352_serdes_pcs_config,
4581+
.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
4582+
.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
44614583
.serdes_power = mv88e6352_serdes_power,
44624584
.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
44634585
.serdes_irq_enable = mv88e6352_serdes_irq_enable,
@@ -4519,6 +4641,11 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
45194641
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
45204642
.serdes_power = mv88e6390_serdes_power,
45214643
.serdes_get_lane = mv88e6390_serdes_get_lane,
4644+
/* Check status register pause & lpa register */
4645+
.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4646+
.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4647+
.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4648+
.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
45224649
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
45234650
.serdes_irq_enable = mv88e6390_serdes_irq_enable,
45244651
.serdes_irq_status = mv88e6390_serdes_irq_status,
@@ -4579,6 +4706,10 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
45794706
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
45804707
.serdes_power = mv88e6390_serdes_power,
45814708
.serdes_get_lane = mv88e6390x_serdes_get_lane,
4709+
.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4710+
.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4711+
.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4712+
.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
45824713
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
45834714
.serdes_irq_enable = mv88e6390_serdes_irq_enable,
45844715
.serdes_irq_status = mv88e6390_serdes_irq_status,
@@ -5457,8 +5588,9 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
54575588
.setup = mv88e6xxx_setup,
54585589
.teardown = mv88e6xxx_teardown,
54595590
.phylink_validate = mv88e6xxx_validate,
5460-
.phylink_mac_link_state = mv88e6xxx_link_state,
5591+
.phylink_mac_link_state = mv88e6xxx_serdes_pcs_get_state,
54615592
.phylink_mac_config = mv88e6xxx_mac_config,
5593+
.phylink_mac_an_restart = mv88e6xxx_serdes_pcs_an_restart,
54625594
.phylink_mac_link_down = mv88e6xxx_mac_link_down,
54635595
.phylink_mac_link_up = mv88e6xxx_mac_link_up,
54645596
.get_strings = mv88e6xxx_get_strings,

drivers/net/dsa/mv88e6xxx/chip.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,17 @@ struct mv88e6xxx_ops {
502502
/* SERDES lane mapping */
503503
u8 (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port);
504504

505+
int (*serdes_pcs_get_state)(struct mv88e6xxx_chip *chip, int port,
506+
u8 lane, struct phylink_link_state *state);
507+
int (*serdes_pcs_config)(struct mv88e6xxx_chip *chip, int port,
508+
u8 lane, unsigned int mode,
509+
phy_interface_t interface,
510+
const unsigned long *advertise);
511+
int (*serdes_pcs_an_restart)(struct mv88e6xxx_chip *chip, int port,
512+
u8 lane);
513+
int (*serdes_pcs_link_up)(struct mv88e6xxx_chip *chip, int port,
514+
u8 lane, int speed, int duplex);
515+
505516
/* SERDES interrupt handling */
506517
unsigned int (*serdes_irq_mapping)(struct mv88e6xxx_chip *chip,
507518
int port);
@@ -669,9 +680,6 @@ int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg,
669680
u16 mask, u16 val);
670681
int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg,
671682
int bit, int val);
672-
int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
673-
int speed, int duplex, int pause,
674-
phy_interface_t mode);
675683
struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip);
676684

677685
static inline void mv88e6xxx_reg_lock(struct mv88e6xxx_chip *chip)

0 commit comments

Comments
 (0)