Skip to content

Commit dea8702

Browse files
lunndavem330
authored andcommitted
dsa: mv88e6xxx: Allow speed/duplex of port to be configured
The current code sets user ports to perform auto negotiation using the phy. CPU and DSA ports are configured to full duplex and maximum speed the switch supports. There are however use cases where the CPU has a slower port, and when user ports have SFP modules with fixed speed. In these cases, port settings to be read from a fixed_phy devices. The switch driver then needs to implement the adjust_link op, so the port settings can be set. Signed-off-by: Andrew Lunn <[email protected]> Reviewed-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5a11dd7 commit dea8702

File tree

6 files changed

+64
-0
lines changed

6 files changed

+64
-0
lines changed

drivers/net/dsa/mv88e6123_61_65.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ struct dsa_switch_driver mv88e6123_61_65_switch_driver = {
129129
.get_strings = mv88e6xxx_get_strings,
130130
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
131131
.get_sset_count = mv88e6xxx_get_sset_count,
132+
.adjust_link = mv88e6xxx_adjust_link,
132133
#ifdef CONFIG_NET_DSA_HWMON
133134
.get_temp = mv88e6xxx_get_temp,
134135
#endif

drivers/net/dsa/mv88e6131.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ struct dsa_switch_driver mv88e6131_switch_driver = {
182182
.get_strings = mv88e6xxx_get_strings,
183183
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
184184
.get_sset_count = mv88e6xxx_get_sset_count,
185+
.adjust_link = mv88e6xxx_adjust_link,
185186
};
186187

187188
MODULE_ALIAS("platform:mv88e6085");

drivers/net/dsa/mv88e6171.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
108108
.get_strings = mv88e6xxx_get_strings,
109109
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
110110
.get_sset_count = mv88e6xxx_get_sset_count,
111+
.adjust_link = mv88e6xxx_adjust_link,
111112
#ifdef CONFIG_NET_DSA_HWMON
112113
.get_temp = mv88e6xxx_get_temp,
113114
#endif

drivers/net/dsa/mv88e6352.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
328328
.get_strings = mv88e6xxx_get_strings,
329329
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
330330
.get_sset_count = mv88e6xxx_get_sset_count,
331+
.adjust_link = mv88e6xxx_adjust_link,
331332
.set_eee = mv88e6xxx_set_eee,
332333
.get_eee = mv88e6xxx_get_eee,
333334
#ifdef CONFIG_NET_DSA_HWMON

drivers/net/dsa/mv88e6xxx.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/debugfs.h>
1515
#include <linux/delay.h>
1616
#include <linux/etherdevice.h>
17+
#include <linux/ethtool.h>
1718
#include <linux/if_bridge.h>
1819
#include <linux/jiffies.h>
1920
#include <linux/list.h>
@@ -560,6 +561,63 @@ static bool mv88e6xxx_6352_family(struct dsa_switch *ds)
560561
return false;
561562
}
562563

564+
/* We expect the switch to perform auto negotiation if there is a real
565+
* phy. However, in the case of a fixed link phy, we force the port
566+
* settings from the fixed link settings.
567+
*/
568+
void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
569+
struct phy_device *phydev)
570+
{
571+
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
572+
u32 ret, reg;
573+
574+
if (!phy_is_pseudo_fixed_link(phydev))
575+
return;
576+
577+
mutex_lock(&ps->smi_mutex);
578+
579+
ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL);
580+
if (ret < 0)
581+
goto out;
582+
583+
reg = ret & ~(PORT_PCS_CTRL_LINK_UP |
584+
PORT_PCS_CTRL_FORCE_LINK |
585+
PORT_PCS_CTRL_DUPLEX_FULL |
586+
PORT_PCS_CTRL_FORCE_DUPLEX |
587+
PORT_PCS_CTRL_UNFORCED);
588+
589+
reg |= PORT_PCS_CTRL_FORCE_LINK;
590+
if (phydev->link)
591+
reg |= PORT_PCS_CTRL_LINK_UP;
592+
593+
if (mv88e6xxx_6065_family(ds) && phydev->speed > SPEED_100)
594+
goto out;
595+
596+
switch (phydev->speed) {
597+
case SPEED_1000:
598+
reg |= PORT_PCS_CTRL_1000;
599+
break;
600+
case SPEED_100:
601+
reg |= PORT_PCS_CTRL_100;
602+
break;
603+
case SPEED_10:
604+
reg |= PORT_PCS_CTRL_10;
605+
break;
606+
default:
607+
pr_info("Unknown speed");
608+
goto out;
609+
}
610+
611+
reg |= PORT_PCS_CTRL_FORCE_DUPLEX;
612+
if (phydev->duplex == DUPLEX_FULL)
613+
reg |= PORT_PCS_CTRL_DUPLEX_FULL;
614+
615+
_mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_PCS_CTRL, reg);
616+
617+
out:
618+
mutex_unlock(&ps->smi_mutex);
619+
}
620+
563621
/* Must be called with SMI mutex held */
564622
static int _mv88e6xxx_stats_wait(struct dsa_switch *ds)
565623
{

drivers/net/dsa/mv88e6xxx.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,8 @@ void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
446446
uint64_t *data);
447447
int mv88e6xxx_get_sset_count(struct dsa_switch *ds);
448448
int mv88e6xxx_get_sset_count_basic(struct dsa_switch *ds);
449+
void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
450+
struct phy_device *phydev);
449451
int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port);
450452
void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
451453
struct ethtool_regs *regs, void *_p);

0 commit comments

Comments
 (0)