It's quite common for switches to have PHY per port so we may use a
generic function for setting port link. We just need an API to access
PHYs which this patch also adds.

Signed-off-by: Rafał Miłecki <zaj...@gmail.com>
---
 .../linux/generic/files/drivers/net/phy/swconfig.c | 44 ++++++++++++++++++++--
 target/linux/generic/files/include/linux/switch.h  |  3 ++
 2 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/target/linux/generic/files/drivers/net/phy/swconfig.c 
b/target/linux/generic/files/drivers/net/phy/swconfig.c
index 9a5f1e9..8b9bb51 100644
--- a/target/linux/generic/files/drivers/net/phy/swconfig.c
+++ b/target/linux/generic/files/drivers/net/phy/swconfig.c
@@ -25,6 +25,7 @@
 #include <linux/switch.h>
 #include <linux/of.h>
 #include <linux/version.h>
+#include <uapi/linux/mii.h>
 
 #define SWCONFIG_DEVNAME       "switch%d"
 
@@ -131,10 +132,47 @@ static int
 swconfig_set_link(struct switch_dev *dev, const struct switch_attr *attr,
                        struct switch_val *val)
 {
-       if (!dev->ops->set_port_link)
-               return -EOPNOTSUPP;
+       struct switch_port_link *link = val->value.link;
+       int port = val->port_vlan;
+
+       if (port == dev->cpu_port)
+               return -EINVAL;
+
+       /* Custom implementation */
+       if (dev->ops->set_port_link)
+               return dev->ops->set_port_link(dev, port, link);
+
+       /* Chceck if we can use generic implementation */
+       if (!dev->ops->phy_write16)
+               return -ENOTSUPP;
+
+       /* Generic implementation */
+       if (link->aneg) {
+               dev->ops->phy_write16(dev, port, MII_BMCR, 0x0000);
+               dev->ops->phy_write16(dev, port, MII_BMCR, BMCR_ANENABLE | 
BMCR_ANRESTART);
+       } else {
+               u16 bmcr = 0;
 
-       return dev->ops->set_port_link(dev, val->port_vlan, val->value.link);
+               if (link->duplex)
+                       bmcr |= BMCR_FULLDPLX;
+
+               switch (link->speed) {
+               case SWITCH_PORT_SPEED_10:
+                       break;
+               case SWITCH_PORT_SPEED_100:
+                       bmcr |= BMCR_SPEED100;
+                       break;
+               case SWITCH_PORT_SPEED_1000:
+                       bmcr |= BMCR_SPEED1000;
+                       break;
+               default:
+                       return -ENOTSUPP;
+               }
+
+               dev->ops->phy_write16(dev, port, MII_BMCR, bmcr);
+       }
+
+       return 0;
 }
 
 static int
diff --git a/target/linux/generic/files/include/linux/switch.h 
b/target/linux/generic/files/include/linux/switch.h
index 4ada0e5..ab587ea 100644
--- a/target/linux/generic/files/include/linux/switch.h
+++ b/target/linux/generic/files/include/linux/switch.h
@@ -99,6 +99,9 @@ struct switch_dev_ops {
                             struct switch_port_link *link);
        int (*get_port_stats)(struct switch_dev *dev, int port,
                              struct switch_port_stats *stats);
+
+       int (*phy_read16)(struct switch_dev *dev, int addr, u8 reg, u16 *value);
+       int (*phy_write16)(struct switch_dev *dev, int addr, u8 reg, u16 value);
 };
 
 struct switch_dev {
-- 
1.8.4.5
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to