Merge tag 'hwlock-v4.18' of git://github.com/andersson/remoteproc
[linux-2.6-microblaze.git] / net / dsa / port.c
index 7acc116..ed05954 100644 (file)
@@ -252,6 +252,9 @@ int dsa_port_vlan_add(struct dsa_port *dp,
                .vlan = vlan,
        };
 
+       if (netif_is_bridge_master(vlan->obj.orig_dev))
+               return -EOPNOTSUPP;
+
        if (br_vlan_enabled(dp->bridge_dev))
                return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info);
 
@@ -267,31 +270,47 @@ int dsa_port_vlan_del(struct dsa_port *dp,
                .vlan = vlan,
        };
 
+       if (netif_is_bridge_master(vlan->obj.orig_dev))
+               return -EOPNOTSUPP;
+
        if (br_vlan_enabled(dp->bridge_dev))
                return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info);
 
        return 0;
 }
 
-static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
+static struct phy_device *dsa_port_get_phy_device(struct dsa_port *dp)
 {
-       struct device_node *port_dn = dp->dn;
        struct device_node *phy_dn;
-       struct dsa_switch *ds = dp->ds;
        struct phy_device *phydev;
-       int port = dp->index;
-       int err = 0;
 
-       phy_dn = of_parse_phandle(port_dn, "phy-handle", 0);
+       phy_dn = of_parse_phandle(dp->dn, "phy-handle", 0);
        if (!phy_dn)
-               return 0;
+               return NULL;
 
        phydev = of_phy_find_device(phy_dn);
        if (!phydev) {
-               err = -EPROBE_DEFER;
-               goto err_put_of;
+               of_node_put(phy_dn);
+               return ERR_PTR(-EPROBE_DEFER);
        }
 
+       return phydev;
+}
+
+static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
+{
+       struct dsa_switch *ds = dp->ds;
+       struct phy_device *phydev;
+       int port = dp->index;
+       int err = 0;
+
+       phydev = dsa_port_get_phy_device(dp);
+       if (!phydev)
+               return 0;
+
+       if (IS_ERR(phydev))
+               return PTR_ERR(phydev);
+
        if (enable) {
                err = genphy_config_init(phydev);
                if (err < 0)
@@ -317,8 +336,6 @@ static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
 
 err_put_dev:
        put_device(&phydev->mdio.dev);
-err_put_of:
-       of_node_put(phy_dn);
        return err;
 }
 
@@ -372,3 +389,60 @@ void dsa_port_link_unregister_of(struct dsa_port *dp)
        else
                dsa_port_setup_phy_of(dp, false);
 }
+
+int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data)
+{
+       struct phy_device *phydev;
+       int ret = -EOPNOTSUPP;
+
+       if (of_phy_is_fixed_link(dp->dn))
+               return ret;
+
+       phydev = dsa_port_get_phy_device(dp);
+       if (IS_ERR_OR_NULL(phydev))
+               return ret;
+
+       ret = phy_ethtool_get_strings(phydev, data);
+       put_device(&phydev->mdio.dev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dsa_port_get_phy_strings);
+
+int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data)
+{
+       struct phy_device *phydev;
+       int ret = -EOPNOTSUPP;
+
+       if (of_phy_is_fixed_link(dp->dn))
+               return ret;
+
+       phydev = dsa_port_get_phy_device(dp);
+       if (IS_ERR_OR_NULL(phydev))
+               return ret;
+
+       ret = phy_ethtool_get_stats(phydev, NULL, data);
+       put_device(&phydev->mdio.dev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dsa_port_get_ethtool_phy_stats);
+
+int dsa_port_get_phy_sset_count(struct dsa_port *dp)
+{
+       struct phy_device *phydev;
+       int ret = -EOPNOTSUPP;
+
+       if (of_phy_is_fixed_link(dp->dn))
+               return ret;
+
+       phydev = dsa_port_get_phy_device(dp);
+       if (IS_ERR_OR_NULL(phydev))
+               return ret;
+
+       ret = phy_ethtool_get_sset_count(phydev);
+       put_device(&phydev->mdio.dev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dsa_port_get_phy_sset_count);