diff options
| author | David S. Miller <davem@davemloft.net> | 2015-08-31 14:48:03 -0700 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-08-31 14:48:03 -0700 |
| commit | 684511ac2eeb015b7a9a46c575543566e1b1fb7c (patch) | |
| tree | e755ec8c049139469d67a5f239002ec68c743113 /drivers/net/dsa/mv88e6xxx.c | |
| parent | 6ea3c9d5b042edf14eac1e21af21c41f81f3491e (diff) | |
| parent | bc0f4a87fc7e45642455682f281de2131cde9695 (diff) | |
| download | talos-op-linux-684511ac2eeb015b7a9a46c575543566e1b1fb7c.tar.gz talos-op-linux-684511ac2eeb015b7a9a46c575543566e1b1fb7c.zip | |
Merge branch 'dsa-port-config'
Andrew Lunn says:
====================
DSA port configuration and status
This patchset allows various switch port settings to be configured and
port status to be sampled. Some of these patches have been posted
before.
The first three patches provide infrastructure for configuring a
switch ports link speed and duplex from a fixed_link phy.
Patch four then uses this infrastructure to allow the CPU and DSA
ports of a switch to be configured using a fixed-link property in the
device tree.
Patches five and six allow a phy-mode property to be specified in the
device tree, and allow this to be used for configuring RGMII delays.
Patches seven through nine allow link status, for example that of an
SFP module, to be read from a gpio.
Changes since v1:
Rewrite 9/9 so that it hopefully does not regression on
868a4215be9a6d80 ("net: phy: fixed_phy: handle link-down case")
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/dsa/mv88e6xxx.c')
| -rw-r--r-- | drivers/net/dsa/mv88e6xxx.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 3774f53d28d7..6f13f7206762 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -14,6 +14,7 @@ #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/etherdevice.h> +#include <linux/ethtool.h> #include <linux/if_bridge.h> #include <linux/jiffies.h> #include <linux/list.h> @@ -394,6 +395,7 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds) for (i = 0; i < DSA_MAX_PORTS; i++) { struct net_device *dev; int uninitialized_var(port_status); + int pcs_ctrl; int link; int speed; int duplex; @@ -403,6 +405,10 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds) if (dev == NULL) continue; + pcs_ctrl = mv88e6xxx_reg_read(ds, REG_PORT(i), PORT_PCS_CTRL); + if (pcs_ctrl < 0 || pcs_ctrl & PORT_PCS_CTRL_FORCE_LINK) + continue; + link = 0; if (dev->flags & IFF_UP) { port_status = mv88e6xxx_reg_read(ds, REG_PORT(i), @@ -560,6 +566,73 @@ static bool mv88e6xxx_6352_family(struct dsa_switch *ds) return false; } +/* We expect the switch to perform auto negotiation if there is a real + * phy. However, in the case of a fixed link phy, we force the port + * settings from the fixed link settings. + */ +void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, + struct phy_device *phydev) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + u32 ret, reg; + + if (!phy_is_pseudo_fixed_link(phydev)) + return; + + mutex_lock(&ps->smi_mutex); + + ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL); + if (ret < 0) + goto out; + + reg = ret & ~(PORT_PCS_CTRL_LINK_UP | + PORT_PCS_CTRL_FORCE_LINK | + PORT_PCS_CTRL_DUPLEX_FULL | + PORT_PCS_CTRL_FORCE_DUPLEX | + PORT_PCS_CTRL_UNFORCED); + + reg |= PORT_PCS_CTRL_FORCE_LINK; + if (phydev->link) + reg |= PORT_PCS_CTRL_LINK_UP; + + if (mv88e6xxx_6065_family(ds) && phydev->speed > SPEED_100) + goto out; + + switch (phydev->speed) { + case SPEED_1000: + reg |= PORT_PCS_CTRL_1000; + break; + case SPEED_100: + reg |= PORT_PCS_CTRL_100; + break; + case SPEED_10: + reg |= PORT_PCS_CTRL_10; + break; + default: + pr_info("Unknown speed"); + goto out; + } + + reg |= PORT_PCS_CTRL_FORCE_DUPLEX; + if (phydev->duplex == DUPLEX_FULL) + reg |= PORT_PCS_CTRL_DUPLEX_FULL; + + if ((mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds)) && + (port >= ps->num_ports - 2)) { + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) + reg |= PORT_PCS_CTRL_RGMII_DELAY_RXCLK; + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + reg |= PORT_PCS_CTRL_RGMII_DELAY_TXCLK; + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + reg |= (PORT_PCS_CTRL_RGMII_DELAY_RXCLK | + PORT_PCS_CTRL_RGMII_DELAY_TXCLK); + } + _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_PCS_CTRL, reg); + +out: + mutex_unlock(&ps->smi_mutex); +} + /* Must be called with SMI mutex held */ static int _mv88e6xxx_stats_wait(struct dsa_switch *ds) { |

