net: dsa: mv88e6xxx: convert 88e6185 to phylink_pcs
authorRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Thu, 13 Jul 2023 08:42:43 +0000 (09:42 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 14 Jul 2023 07:51:48 +0000 (08:51 +0100)
Convert the 88E6185 SERDES code to use the phylink_pcs infrastructure.

Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/mv88e6xxx/Makefile
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/mv88e6xxx/pcs-6185.c [new file with mode: 0644]
drivers/net/dsa/mv88e6xxx/serdes.c
drivers/net/dsa/mv88e6xxx/serdes.h

index 1409e69..9becf56 100644 (file)
@@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o
 mv88e6xxx-objs += global2_avb.o
 mv88e6xxx-objs += global2_scratch.o
 mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
+mv88e6xxx-objs += pcs-6185.o
 mv88e6xxx-objs += phy.o
 mv88e6xxx-objs += port.o
 mv88e6xxx-objs += port_hidden.o
index acbe557..fd876cf 100644 (file)
@@ -4230,15 +4230,13 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
        .stats_get_strings = mv88e6095_stats_get_strings,
        .stats_get_stats = mv88e6095_stats_get_stats,
        .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
-       .serdes_power = mv88e6185_serdes_power,
-       .serdes_get_lane = mv88e6185_serdes_get_lane,
-       .serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
        .ppu_enable = mv88e6185_g1_ppu_enable,
        .ppu_disable = mv88e6185_g1_ppu_disable,
        .reset = mv88e6185_g1_reset,
        .vtu_getnext = mv88e6185_g1_vtu_getnext,
        .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
        .phylink_get_caps = mv88e6095_phylink_get_caps,
+       .pcs_ops = &mv88e6185_pcs_ops,
        .set_max_frame_size = mv88e6185_g1_set_max_frame_size,
 };
 
@@ -4276,18 +4274,14 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
        .set_egress_port = mv88e6095_g1_set_egress_port,
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
-       .serdes_power = mv88e6185_serdes_power,
-       .serdes_get_lane = mv88e6185_serdes_get_lane,
-       .serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
        .serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
-       .serdes_irq_enable = mv88e6097_serdes_irq_enable,
-       .serdes_irq_status = mv88e6097_serdes_irq_status,
        .pot_clear = mv88e6xxx_g2_pot_clear,
        .reset = mv88e6352_g1_reset,
        .rmu_disable = mv88e6085_g1_rmu_disable,
        .vtu_getnext = mv88e6352_g1_vtu_getnext,
        .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
        .phylink_get_caps = mv88e6095_phylink_get_caps,
+       .pcs_ops = &mv88e6185_pcs_ops,
        .stu_getnext = mv88e6352_g1_stu_getnext,
        .stu_loadpurge = mv88e6352_g1_stu_loadpurge,
        .set_max_frame_size = mv88e6185_g1_set_max_frame_size,
@@ -4768,9 +4762,6 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
        .set_egress_port = mv88e6095_g1_set_egress_port,
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
-       .serdes_power = mv88e6185_serdes_power,
-       .serdes_get_lane = mv88e6185_serdes_get_lane,
-       .serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
        .set_cascade_port = mv88e6185_g1_set_cascade_port,
        .ppu_enable = mv88e6185_g1_ppu_enable,
        .ppu_disable = mv88e6185_g1_ppu_disable,
@@ -4778,6 +4769,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
        .vtu_getnext = mv88e6185_g1_vtu_getnext,
        .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
        .phylink_get_caps = mv88e6185_phylink_get_caps,
+       .pcs_ops = &mv88e6185_pcs_ops,
        .set_max_frame_size = mv88e6185_g1_set_max_frame_size,
 };
 
diff --git a/drivers/net/dsa/mv88e6xxx/pcs-6185.c b/drivers/net/dsa/mv88e6xxx/pcs-6185.c
new file mode 100644 (file)
index 0000000..4d677f8
--- /dev/null
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Marvell 88E6185 family SERDES PCS support
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
+ */
+#include <linux/phylink.h>
+
+#include "global2.h"
+#include "port.h"
+#include "serdes.h"
+
+struct mv88e6185_pcs {
+       struct phylink_pcs phylink_pcs;
+       unsigned int irq;
+       char name[64];
+
+       struct mv88e6xxx_chip *chip;
+       int port;
+};
+
+static struct mv88e6185_pcs *pcs_to_mv88e6185_pcs(struct phylink_pcs *pcs)
+{
+       return container_of(pcs, struct mv88e6185_pcs, phylink_pcs);
+}
+
+static irqreturn_t mv88e6185_pcs_handle_irq(int irq, void *dev_id)
+{
+       struct mv88e6185_pcs *mpcs = dev_id;
+       struct mv88e6xxx_chip *chip;
+       irqreturn_t ret = IRQ_NONE;
+       bool link_up;
+       u16 status;
+       int port;
+       int err;
+
+       chip = mpcs->chip;
+       port = mpcs->port;
+
+       mv88e6xxx_reg_lock(chip);
+       err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status);
+       mv88e6xxx_reg_unlock(chip);
+
+       if (!err) {
+               link_up = !!(status & MV88E6XXX_PORT_STS_LINK);
+
+               phylink_pcs_change(&mpcs->phylink_pcs, link_up);
+
+               ret = IRQ_HANDLED;
+       }
+
+       return ret;
+}
+
+static void mv88e6185_pcs_get_state(struct phylink_pcs *pcs,
+                                   struct phylink_link_state *state)
+{
+       struct mv88e6185_pcs *mpcs = pcs_to_mv88e6185_pcs(pcs);
+       struct mv88e6xxx_chip *chip = mpcs->chip;
+       int port = mpcs->port;
+       u16 status;
+       int err;
+
+       mv88e6xxx_reg_lock(chip);
+       err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status);
+       mv88e6xxx_reg_unlock(chip);
+
+       if (err)
+               status = 0;
+
+       state->link = !!(status & MV88E6XXX_PORT_STS_LINK);
+       if (state->link) {
+               state->duplex = status & MV88E6XXX_PORT_STS_DUPLEX ?
+                       DUPLEX_FULL : DUPLEX_HALF;
+
+               switch (status & MV88E6XXX_PORT_STS_SPEED_MASK) {
+               case MV88E6XXX_PORT_STS_SPEED_1000:
+                       state->speed = SPEED_1000;
+                       break;
+
+               case MV88E6XXX_PORT_STS_SPEED_100:
+                       state->speed = SPEED_100;
+                       break;
+
+               case MV88E6XXX_PORT_STS_SPEED_10:
+                       state->speed = SPEED_10;
+                       break;
+
+               default:
+                       state->link = false;
+                       break;
+               }
+       }
+}
+
+static int mv88e6185_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
+                               phy_interface_t interface,
+                               const unsigned long *advertising,
+                               bool permit_pause_to_mac)
+{
+       return 0;
+}
+
+static void mv88e6185_pcs_an_restart(struct phylink_pcs *pcs)
+{
+}
+
+static const struct phylink_pcs_ops mv88e6185_phylink_pcs_ops = {
+       .pcs_get_state = mv88e6185_pcs_get_state,
+       .pcs_config = mv88e6185_pcs_config,
+       .pcs_an_restart = mv88e6185_pcs_an_restart,
+};
+
+static int mv88e6185_pcs_init(struct mv88e6xxx_chip *chip, int port)
+{
+       struct mv88e6185_pcs *mpcs;
+       struct device *dev;
+       unsigned int irq;
+       int err;
+
+       /* There are no configurable serdes lanes on this switch chip, so
+        * we use the static cmode configuration to determine whether we
+        * have a PCS or not.
+        */
+       if (chip->ports[port].cmode != MV88E6185_PORT_STS_CMODE_SERDES &&
+           chip->ports[port].cmode != MV88E6185_PORT_STS_CMODE_1000BASE_X)
+               return 0;
+
+       dev = chip->dev;
+
+       mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL);
+       if (!mpcs)
+               return -ENOMEM;
+
+       mpcs->chip = chip;
+       mpcs->port = port;
+       mpcs->phylink_pcs.ops = &mv88e6185_phylink_pcs_ops;
+
+       irq = mv88e6xxx_serdes_irq_mapping(chip, port);
+       if (irq) {
+               snprintf(mpcs->name, sizeof(mpcs->name),
+                        "mv88e6xxx-%s-serdes-%d", dev_name(dev), port);
+
+               err = request_threaded_irq(irq, NULL, mv88e6185_pcs_handle_irq,
+                                          IRQF_ONESHOT, mpcs->name, mpcs);
+               if (err) {
+                       kfree(mpcs);
+                       return err;
+               }
+
+               mpcs->irq = irq;
+       } else {
+               mpcs->phylink_pcs.poll = true;
+       }
+
+       chip->ports[port].pcs_private = &mpcs->phylink_pcs;
+
+       return 0;
+}
+
+static void mv88e6185_pcs_teardown(struct mv88e6xxx_chip *chip, int port)
+{
+       struct mv88e6185_pcs *mpcs;
+
+       mpcs = chip->ports[port].pcs_private;
+       if (!mpcs)
+               return;
+
+       if (mpcs->irq)
+               free_irq(mpcs->irq, mpcs);
+
+       kfree(mpcs);
+
+       chip->ports[port].pcs_private = NULL;
+}
+
+static struct phylink_pcs *mv88e6185_pcs_select(struct mv88e6xxx_chip *chip,
+                                               int port,
+                                               phy_interface_t interface)
+{
+       return chip->ports[port].pcs_private;
+}
+
+const struct mv88e6xxx_pcs_ops mv88e6185_pcs_ops = {
+       .pcs_init = mv88e6185_pcs_init,
+       .pcs_teardown = mv88e6185_pcs_teardown,
+       .pcs_select = mv88e6185_pcs_select,
+};
index 7ea36d0..5ac5687 100644 (file)
@@ -460,115 +460,6 @@ int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
        return lane;
 }
 
-int mv88e6185_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
-                          bool up)
-{
-       /* The serdes power can't be controlled on this switch chip but we need
-        * to supply this function to avoid returning -EOPNOTSUPP in
-        * mv88e6xxx_serdes_power_up/mv88e6xxx_serdes_power_down
-        */
-       return 0;
-}
-
-int mv88e6185_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
-{
-       /* There are no configurable serdes lanes on this switch chip but we
-        * need to return a non-negative lane number so that callers of
-        * mv88e6xxx_serdes_get_lane() know this is a serdes port.
-        */
-       switch (chip->ports[port].cmode) {
-       case MV88E6185_PORT_STS_CMODE_SERDES:
-       case MV88E6185_PORT_STS_CMODE_1000BASE_X:
-               return 0;
-       default:
-               return -ENODEV;
-       }
-}
-
-int mv88e6185_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
-                                  int lane, struct phylink_link_state *state)
-{
-       int err;
-       u16 status;
-
-       err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status);
-       if (err)
-               return err;
-
-       state->link = !!(status & MV88E6XXX_PORT_STS_LINK);
-
-       if (state->link) {
-               state->duplex = status & MV88E6XXX_PORT_STS_DUPLEX ? DUPLEX_FULL : DUPLEX_HALF;
-
-               switch (status &  MV88E6XXX_PORT_STS_SPEED_MASK) {
-               case MV88E6XXX_PORT_STS_SPEED_1000:
-                       state->speed = SPEED_1000;
-                       break;
-               case MV88E6XXX_PORT_STS_SPEED_100:
-                       state->speed = SPEED_100;
-                       break;
-               case MV88E6XXX_PORT_STS_SPEED_10:
-                       state->speed = SPEED_10;
-                       break;
-               default:
-                       dev_err(chip->dev, "invalid PHY speed\n");
-                       return -EINVAL;
-               }
-       } else {
-               state->duplex = DUPLEX_UNKNOWN;
-               state->speed = SPEED_UNKNOWN;
-       }
-
-       return 0;
-}
-
-int mv88e6097_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
-                               bool enable)
-{
-       u8 cmode = chip->ports[port].cmode;
-
-       /* The serdes interrupts are enabled in the G2_INT_MASK register. We
-        * need to return 0 to avoid returning -EOPNOTSUPP in
-        * mv88e6xxx_serdes_irq_enable/mv88e6xxx_serdes_irq_disable
-        */
-       switch (cmode) {
-       case MV88E6185_PORT_STS_CMODE_SERDES:
-       case MV88E6185_PORT_STS_CMODE_1000BASE_X:
-               return 0;
-       }
-
-       return -EOPNOTSUPP;
-}
-
-static void mv88e6097_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
-{
-       u16 status;
-       int err;
-
-       err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status);
-       if (err) {
-               dev_err(chip->dev, "can't read port status: %d\n", err);
-               return;
-       }
-
-       dsa_port_phylink_mac_change(chip->ds, port, !!(status & MV88E6XXX_PORT_STS_LINK));
-}
-
-irqreturn_t mv88e6097_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
-                                       int lane)
-{
-       u8 cmode = chip->ports[port].cmode;
-
-       switch (cmode) {
-       case MV88E6185_PORT_STS_CMODE_SERDES:
-       case MV88E6185_PORT_STS_CMODE_1000BASE_X:
-               mv88e6097_serdes_irq_link(chip, port);
-               return IRQ_HANDLED;
-       }
-
-       return IRQ_NONE;
-}
-
 int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
 {
        u8 cmode = chip->ports[port].cmode;
index 93d40d6..93d363e 100644 (file)
@@ -112,7 +112,6 @@ struct phylink_link_state;
 int mv88e6xxx_pcs_decode_state(struct device *dev, u16 bmsr, u16 lpa,
                               u16 status, struct phylink_link_state *state);
 
-int mv88e6185_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
 int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
 int mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
 int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
@@ -126,8 +125,6 @@ int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
                                int lane, unsigned int mode,
                                phy_interface_t interface,
                                const unsigned long *advertise);
-int mv88e6185_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
-                                  int lane, struct phylink_link_state *state);
 int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
                                   int lane, struct phylink_link_state *state);
 int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
@@ -146,8 +143,6 @@ unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
                                          int port);
 unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
                                          int port);
-int mv88e6185_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
-                          bool up);
 int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
                           bool on);
 int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
@@ -155,16 +150,12 @@ int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
 int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
                            bool on);
 int mv88e6393x_serdes_setup_errata(struct mv88e6xxx_chip *chip);
-int mv88e6097_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
-                               bool enable);
 int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
                                bool enable);
 int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
                                bool enable);
 int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
                                 int lane, bool enable);
-irqreturn_t mv88e6097_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
-                                       int lane);
 irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
                                        int lane);
 irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
@@ -254,4 +245,6 @@ mv88e6xxx_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, int lane)
        return chip->info->ops->serdes_irq_status(chip, port, lane);
 }
 
+extern const struct mv88e6xxx_pcs_ops mv88e6185_pcs_ops;
+
 #endif