Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[cascardo/linux.git] / drivers / net / phy / micrel.c
index e13ad6c..03833db 100644 (file)
 
 #define PS_TO_REG                              200
 
+struct kszphy_hw_stat {
+       const char *string;
+       u8 reg;
+       u8 bits;
+};
+
+static struct kszphy_hw_stat kszphy_hw_stats[] = {
+       { "phy_receive_errors", 21, 16},
+       { "phy_idle_errors", 10, 8 },
+};
+
 struct kszphy_type {
        u32 led_mode_reg;
        u16 interrupt_level_mask;
@@ -86,6 +97,7 @@ struct kszphy_priv {
        int led_mode;
        bool rmii_ref_clk_sel;
        bool rmii_ref_clk_sel_val;
+       u64 stats[ARRAY_SIZE(kszphy_hw_stats)];
 };
 
 static const struct kszphy_type ksz8021_type = {
@@ -212,7 +224,7 @@ static int kszphy_setup_led(struct phy_device *phydev, u32 reg, int val)
        rc = phy_write(phydev, reg, temp);
 out:
        if (rc < 0)
-               dev_err(&phydev->dev, "failed to set led mode\n");
+               phydev_err(phydev, "failed to set led mode\n");
 
        return rc;
 }
@@ -231,7 +243,7 @@ static int kszphy_broadcast_disable(struct phy_device *phydev)
        ret = phy_write(phydev, MII_KSZPHY_OMSO, ret | KSZPHY_OMSO_B_CAST_OFF);
 out:
        if (ret)
-               dev_err(&phydev->dev, "failed to disable broadcast address\n");
+               phydev_err(phydev, "failed to disable broadcast address\n");
 
        return ret;
 }
@@ -251,7 +263,7 @@ static int kszphy_nand_tree_disable(struct phy_device *phydev)
                        ret & ~KSZPHY_OMSO_NAND_TREE_ON);
 out:
        if (ret)
-               dev_err(&phydev->dev, "failed to disable NAND tree mode\n");
+               phydev_err(phydev, "failed to disable NAND tree mode\n");
 
        return ret;
 }
@@ -276,7 +288,8 @@ static int kszphy_config_init(struct phy_device *phydev)
        if (priv->rmii_ref_clk_sel) {
                ret = kszphy_rmii_clk_sel(phydev, priv->rmii_ref_clk_sel_val);
                if (ret) {
-                       dev_err(&phydev->dev, "failed to set rmii reference clock\n");
+                       phydev_err(phydev,
+                                  "failed to set rmii reference clock\n");
                        return ret;
                }
        }
@@ -337,7 +350,7 @@ static int ksz9021_load_values_from_of(struct phy_device *phydev,
 
 static int ksz9021_config_init(struct phy_device *phydev)
 {
-       const struct device *dev = &phydev->dev;
+       const struct device *dev = &phydev->mdio.dev;
        const struct device_node *of_node = dev->of_node;
        const struct device *dev_walker;
 
@@ -345,7 +358,7 @@ static int ksz9021_config_init(struct phy_device *phydev)
         * properties in the MAC node. Walk up the tree of devices to
         * find a device with an OF node.
         */
-       dev_walker = &phydev->dev;
+       dev_walker = &phydev->mdio.dev;
        do {
                of_node = dev_walker->of_node;
                dev_walker = dev_walker->parent;
@@ -458,7 +471,7 @@ static int ksz9031_center_flp_timing(struct phy_device *phydev)
 
 static int ksz9031_config_init(struct phy_device *phydev)
 {
-       const struct device *dev = &phydev->dev;
+       const struct device *dev = &phydev->mdio.dev;
        const struct device_node *of_node = dev->of_node;
        static const char *clk_skews[2] = {"rxc-skew-ps", "txc-skew-ps"};
        static const char *rx_data_skews[4] = {
@@ -470,9 +483,17 @@ static int ksz9031_config_init(struct phy_device *phydev)
                "txd2-skew-ps", "txd3-skew-ps"
        };
        static const char *control_skews[2] = {"txen-skew-ps", "rxdv-skew-ps"};
+       const struct device *dev_walker;
 
-       if (!of_node && dev->parent->of_node)
-               of_node = dev->parent->of_node;
+       /* The Micrel driver has a deprecated option to place phy OF
+        * properties in the MAC node. Walk up the tree of devices to
+        * find a device with an OF node.
+        */
+       dev_walker = &phydev->mdio.dev;
+       do {
+               of_node = dev_walker->of_node;
+               dev_walker = dev_walker->parent;
+       } while (!of_node && dev_walker);
 
        if (of_node) {
                ksz9031_of_load_skew_values(phydev, of_node,
@@ -569,15 +590,60 @@ ksz9021_wr_mmd_phyreg(struct phy_device *phydev, int ptrad, int devnum,
 {
 }
 
+static int kszphy_get_sset_count(struct phy_device *phydev)
+{
+       return ARRAY_SIZE(kszphy_hw_stats);
+}
+
+static void kszphy_get_strings(struct phy_device *phydev, u8 *data)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++) {
+               memcpy(data + i * ETH_GSTRING_LEN,
+                      kszphy_hw_stats[i].string, ETH_GSTRING_LEN);
+       }
+}
+
+#ifndef UINT64_MAX
+#define UINT64_MAX              (u64)(~((u64)0))
+#endif
+static u64 kszphy_get_stat(struct phy_device *phydev, int i)
+{
+       struct kszphy_hw_stat stat = kszphy_hw_stats[i];
+       struct kszphy_priv *priv = phydev->priv;
+       u64 val;
+
+       val = phy_read(phydev, stat.reg);
+       if (val < 0) {
+               val = UINT64_MAX;
+       } else {
+               val = val & ((1 << stat.bits) - 1);
+               priv->stats[i] += val;
+               val = priv->stats[i];
+       }
+
+       return val;
+}
+
+static void kszphy_get_stats(struct phy_device *phydev,
+                            struct ethtool_stats *stats, u64 *data)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++)
+               data[i] = kszphy_get_stat(phydev, i);
+}
+
 static int kszphy_probe(struct phy_device *phydev)
 {
        const struct kszphy_type *type = phydev->drv->driver_data;
-       const struct device_node *np = phydev->dev.of_node;
+       const struct device_node *np = phydev->mdio.dev.of_node;
        struct kszphy_priv *priv;
        struct clk *clk;
        int ret;
 
-       priv = devm_kzalloc(&phydev->dev, sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
@@ -592,15 +658,15 @@ static int kszphy_probe(struct phy_device *phydev)
                        priv->led_mode = -1;
 
                if (priv->led_mode > 3) {
-                       dev_err(&phydev->dev, "invalid led mode: 0x%02x\n",
-                                       priv->led_mode);
+                       phydev_err(phydev, "invalid led mode: 0x%02x\n",
+                                  priv->led_mode);
                        priv->led_mode = -1;
                }
        } else {
                priv->led_mode = -1;
        }
 
-       clk = devm_clk_get(&phydev->dev, "rmii-ref");
+       clk = devm_clk_get(&phydev->mdio.dev, "rmii-ref");
        /* NOTE: clk may be NULL if building without CONFIG_HAVE_CLK */
        if (!IS_ERR_OR_NULL(clk)) {
                unsigned long rate = clk_get_rate(clk);
@@ -615,7 +681,8 @@ static int kszphy_probe(struct phy_device *phydev)
                } else if (rate > 49500000 && rate < 50500000) {
                        priv->rmii_ref_clk_sel_val = !rmii_ref_clk_sel_25_mhz;
                } else {
-                       dev_err(&phydev->dev, "Clock rate out of range: %ld\n", rate);
+                       phydev_err(phydev, "Clock rate out of range: %ld\n",
+                                  rate);
                        return -EINVAL;
                }
        }
@@ -642,9 +709,11 @@ static struct phy_driver ksphy_driver[] = {
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
        .config_intr    = kszphy_config_intr,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
-       .driver         = { .owner = THIS_MODULE,},
 }, {
        .phy_id         = PHY_ID_KSZ8021,
        .phy_id_mask    = 0x00ffffff,
@@ -659,9 +728,11 @@ static struct phy_driver ksphy_driver[] = {
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
        .config_intr    = kszphy_config_intr,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
-       .driver         = { .owner = THIS_MODULE,},
 }, {
        .phy_id         = PHY_ID_KSZ8031,
        .phy_id_mask    = 0x00ffffff,
@@ -676,9 +747,11 @@ static struct phy_driver ksphy_driver[] = {
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
        .config_intr    = kszphy_config_intr,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
-       .driver         = { .owner = THIS_MODULE,},
 }, {
        .phy_id         = PHY_ID_KSZ8041,
        .phy_id_mask    = 0x00fffff0,
@@ -693,9 +766,11 @@ static struct phy_driver ksphy_driver[] = {
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
        .config_intr    = kszphy_config_intr,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
-       .driver         = { .owner = THIS_MODULE,},
 }, {
        .phy_id         = PHY_ID_KSZ8041RNLI,
        .phy_id_mask    = 0x00fffff0,
@@ -710,9 +785,11 @@ static struct phy_driver ksphy_driver[] = {
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
        .config_intr    = kszphy_config_intr,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
-       .driver         = { .owner = THIS_MODULE,},
 }, {
        .phy_id         = PHY_ID_KSZ8051,
        .phy_id_mask    = 0x00fffff0,
@@ -727,9 +804,11 @@ static struct phy_driver ksphy_driver[] = {
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
        .config_intr    = kszphy_config_intr,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
-       .driver         = { .owner = THIS_MODULE,},
 }, {
        .phy_id         = PHY_ID_KSZ8001,
        .name           = "Micrel KSZ8001 or KS8721",
@@ -743,9 +822,11 @@ static struct phy_driver ksphy_driver[] = {
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
        .config_intr    = kszphy_config_intr,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
-       .driver         = { .owner = THIS_MODULE,},
 }, {
        .phy_id         = PHY_ID_KSZ8081,
        .name           = "Micrel KSZ8081 or KSZ8091",
@@ -759,9 +840,11 @@ static struct phy_driver ksphy_driver[] = {
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
        .config_intr    = kszphy_config_intr,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
-       .driver         = { .owner = THIS_MODULE,},
 }, {
        .phy_id         = PHY_ID_KSZ8061,
        .name           = "Micrel KSZ8061",
@@ -773,9 +856,11 @@ static struct phy_driver ksphy_driver[] = {
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
        .config_intr    = kszphy_config_intr,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
-       .driver         = { .owner = THIS_MODULE,},
 }, {
        .phy_id         = PHY_ID_KSZ9021,
        .phy_id_mask    = 0x000ffffe,
@@ -788,11 +873,13 @@ static struct phy_driver ksphy_driver[] = {
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
        .config_intr    = kszphy_config_intr,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
        .read_mmd_indirect = ksz9021_rd_mmd_phyreg,
        .write_mmd_indirect = ksz9021_wr_mmd_phyreg,
-       .driver         = { .owner = THIS_MODULE, },
 }, {
        .phy_id         = PHY_ID_KSZ9031,
        .phy_id_mask    = 0x00fffff0,
@@ -805,9 +892,11 @@ static struct phy_driver ksphy_driver[] = {
        .read_status    = ksz9031_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
        .config_intr    = kszphy_config_intr,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
-       .driver         = { .owner = THIS_MODULE, },
 }, {
        .phy_id         = PHY_ID_KSZ8873MLL,
        .phy_id_mask    = 0x00fffff0,
@@ -817,9 +906,11 @@ static struct phy_driver ksphy_driver[] = {
        .config_init    = kszphy_config_init,
        .config_aneg    = ksz8873mll_config_aneg,
        .read_status    = ksz8873mll_read_status,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
-       .driver         = { .owner = THIS_MODULE, },
 }, {
        .phy_id         = PHY_ID_KSZ886X,
        .phy_id_mask    = 0x00fffff0,
@@ -829,9 +920,11 @@ static struct phy_driver ksphy_driver[] = {
        .config_init    = kszphy_config_init,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
-       .driver         = { .owner = THIS_MODULE, },
 } };
 
 module_phy_driver(ksphy_driver);