net: dsa: mv88e6xxx: add port link setter
authorVivien Didelot <vivien.didelot@savoirfairelinux.com>
Fri, 4 Nov 2016 02:23:32 +0000 (03:23 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 4 Nov 2016 18:40:00 +0000 (14:40 -0400)
Most of the chips will have a port register control bits to force the
port's link up, down, or let normal link detection occurs.

Implement such operation to use it later when setting duplex, etc.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
drivers/net/dsa/mv88e6xxx/port.c
drivers/net/dsa/mv88e6xxx/port.h

index 181d3b9aad066f2cea7513822e5ab7cdceb9aaaf..cc43e6f09c5dd0d3e80f26f4aaeff58ac637859f 100644 (file)
@@ -3160,42 +3160,49 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
        .set_switch_mac = mv88e6xxx_g1_set_switch_mac,
        .phy_read = mv88e6xxx_phy_ppu_read,
        .phy_write = mv88e6xxx_phy_ppu_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6095_ops = {
        .set_switch_mac = mv88e6xxx_g1_set_switch_mac,
        .phy_read = mv88e6xxx_phy_ppu_read,
        .phy_write = mv88e6xxx_phy_ppu_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6123_ops = {
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_read,
        .phy_write = mv88e6xxx_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6131_ops = {
        .set_switch_mac = mv88e6xxx_g1_set_switch_mac,
        .phy_read = mv88e6xxx_phy_ppu_read,
        .phy_write = mv88e6xxx_phy_ppu_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6161_ops = {
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_read,
        .phy_write = mv88e6xxx_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6165_ops = {
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_read,
        .phy_write = mv88e6xxx_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6171_ops = {
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6172_ops = {
@@ -3204,12 +3211,14 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6175_ops = {
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6176_ops = {
@@ -3218,12 +3227,14 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6185_ops = {
        .set_switch_mac = mv88e6xxx_g1_set_switch_mac,
        .phy_read = mv88e6xxx_phy_ppu_read,
        .phy_write = mv88e6xxx_phy_ppu_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6240_ops = {
@@ -3232,6 +3243,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -3240,6 +3252,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -3248,18 +3261,21 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6350_ops = {
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6351_ops = {
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -3268,6 +3284,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
+       .port_set_link = mv88e6xxx_port_set_link,
 };
 
 static const struct mv88e6xxx_info mv88e6xxx_table[] = {
index 6f48e5886b2adbbae021576cf2bf51c59f901059..474d16d64629d5b35a4513e9d2e235ab304b1ba0 100644 (file)
@@ -727,6 +727,16 @@ struct mv88e6xxx_ops {
                        u16 *val);
        int (*phy_write)(struct mv88e6xxx_chip *chip, int addr, int reg,
                         u16 val);
+
+#define LINK_FORCED_DOWN       0
+#define LINK_FORCED_UP         1
+#define LINK_UNFORCED          -2
+
+       /* Port's MAC link state
+        * Use LINK_FORCED_UP or LINK_FORCED_DOWN to force link up or down,
+        * or LINK_UNFORCED for normal link detection.
+        */
+       int (*port_set_link)(struct mv88e6xxx_chip *chip, int port, int link);
 };
 
 enum stat_type {
index 53d17e63b04aa26cdfd829ba751aa86a07a025eb..09e25f975b25c76c3cf5cd92bd4d38280476072e 100644 (file)
@@ -30,6 +30,47 @@ int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
        return mv88e6xxx_write(chip, addr, reg, val);
 }
 
+/* Offset 0x01: MAC (or PCS or Physical) Control Register
+ *
+ * Link, Duplex and Flow Control have one force bit, one value bit.
+ */
+
+int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link)
+{
+       u16 reg;
+       int err;
+
+       err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, &reg);
+       if (err)
+               return err;
+
+       reg &= ~(PORT_PCS_CTRL_FORCE_LINK | PORT_PCS_CTRL_LINK_UP);
+
+       switch (link) {
+       case LINK_FORCED_DOWN:
+               reg |= PORT_PCS_CTRL_FORCE_LINK;
+               break;
+       case LINK_FORCED_UP:
+               reg |= PORT_PCS_CTRL_FORCE_LINK | PORT_PCS_CTRL_LINK_UP;
+               break;
+       case LINK_UNFORCED:
+               /* normal link detection */
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg);
+       if (err)
+               return err;
+
+       netdev_dbg(chip->ds->ports[port].netdev, "%s link %s\n",
+                  reg & PORT_PCS_CTRL_FORCE_LINK ? "Force" : "Unforce",
+                  reg & PORT_PCS_CTRL_LINK_UP ? "up" : "down");
+
+       return 0;
+}
+
 /* Offset 0x04: Port Control Register */
 
 static const char * const mv88e6xxx_port_state_names[] = {
index 921eecf8acb8546bd8c229203c65bae382f0dd64..87e7249d516b19b1e8a221c2ad4f83738213d0be 100644 (file)
@@ -21,6 +21,8 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
 int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
                         u16 val);
 
+int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link);
+
 int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state);
 
 int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map);