generic: provide get_port_stats() on ar8xxx switches
[openwrt/openwrt.git] / target / linux / generic / files / drivers / net / phy / ar8216.c
index 746d8e6c3dcc312b03f851901b0c4d9ec8edfa96..7f3d5115ab0979081731ee1a2369250c12a90e36 100644 (file)
@@ -49,6 +49,12 @@ extern const struct ar8xxx_chip ar8337_chip;
                .name = (_n),   \
        }
 
+#define AR8216_MIB_RXB_ID      14      /* RxGoodByte */
+#define AR8216_MIB_TXB_ID      29      /* TxByte */
+
+#define AR8236_MIB_RXB_ID      15      /* RxGoodByte */
+#define AR8236_MIB_TXB_ID      31      /* TxByte */
+
 static const struct ar8xxx_mib_desc ar8216_mibs[] = {
        MIB_DESC(1, AR8216_STATS_RXBROAD, "RxBroad"),
        MIB_DESC(1, AR8216_STATS_RXPAUSE, "RxPause"),
@@ -177,7 +183,7 @@ ar8xxx_phy_check_aneg(struct phy_device *phydev)
        if (ret & BMCR_ANENABLE)
                return 0;
 
-       dev_info(&phydev->dev, "ANEG disabled, re-enabling ...\n");
+       dev_info(&phydev->mdio.dev, "ANEG disabled, re-enabling ...\n");
        ret |= BMCR_ANENABLE | BMCR_ANRESTART;
        return phy_write(phydev, MII_BMCR, ret);
 }
@@ -975,7 +981,7 @@ ar8xxx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
 {
        struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
 
-       if (val->port_vlan >= AR8X16_MAX_PORTS)
+       if (val->port_vlan >= AR8X16_MAX_VLANS)
                return -EINVAL;
 
        priv->vlan_id[val->port_vlan] = val->value.i;
@@ -1194,6 +1200,7 @@ ar8xxx_sw_reset_switch(struct switch_dev *dev)
        priv->arl_age_time = AR8XXX_DEFAULT_ARL_AGE_TIME;
 
        chip->init_globals(priv);
+       chip->atu_flush(priv);
 
        mutex_unlock(&priv->reg_mutex);
 
@@ -1580,6 +1587,56 @@ ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev,
        return ret;
 }
 
+int
+ar8xxx_sw_get_port_stats(struct switch_dev *dev, int port,
+                       struct switch_port_stats *stats)
+{
+       struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+       u64 *mib_stats;
+       int ret;
+       int mib_txb_id, mib_rxb_id;
+
+       if (!ar8xxx_has_mib_counters(priv))
+               return -EOPNOTSUPP;
+
+       if (port >= dev->ports)
+               return -EINVAL;
+
+       switch (priv->chip_ver) {
+               case AR8XXX_VER_AR8216:
+                       mib_txb_id = AR8216_MIB_TXB_ID;
+                       mib_rxb_id = AR8216_MIB_RXB_ID;
+                       break;
+               case AR8XXX_VER_AR8236:
+               case AR8XXX_VER_AR8316:
+               case AR8XXX_VER_AR8327:
+               case AR8XXX_VER_AR8337:
+                       mib_txb_id = AR8236_MIB_TXB_ID;
+                       mib_rxb_id = AR8236_MIB_RXB_ID;
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+       }
+
+       mutex_lock(&priv->mib_lock);
+       ret = ar8xxx_mib_capture(priv);
+       if (ret)
+               goto unlock;
+
+       ar8xxx_mib_fetch_port_stat(priv, port, false);
+
+       mib_stats = &priv->mib_stats[port * priv->chip->num_mibs];
+
+       stats->tx_bytes = mib_stats[mib_txb_id];
+       stats->rx_bytes = mib_stats[mib_rxb_id];
+
+       ret = 0;
+
+unlock:
+       mutex_unlock(&priv->mib_lock);
+       return ret;
+}
+
 static const struct switch_attr ar8xxx_sw_attr_globals[] = {
        {
                .type = SWITCH_TYPE_INT,
@@ -1695,6 +1752,7 @@ static const struct switch_dev_ops ar8xxx_sw_ops = {
        .apply_config = ar8xxx_sw_hw_apply,
        .reset_switch = ar8xxx_sw_reset_switch,
        .get_port_link = ar8xxx_sw_get_port_link,
+       .get_port_stats = ar8xxx_sw_get_port_stats,
 };
 
 static const struct ar8xxx_chip ar8216_chip = {
@@ -1996,7 +2054,7 @@ ar8xxx_phy_config_init(struct phy_device *phydev)
 
        priv->phy = phydev;
 
-       if (phydev->addr != 0) {
+       if (phydev->mdio.addr != 0) {
                if (chip_is_ar8316(priv)) {
                        /* switch device has been initialized, reinit */
                        priv->dev.ports = (AR8216_NUM_PORTS - 1);
@@ -2044,7 +2102,7 @@ ar8xxx_check_link_states(struct ar8xxx_priv *priv)
                /* flush ARL entries for this port if it went down*/
                if (!link_new)
                        priv->chip->atu_flush_port(priv, i);
-               dev_info(&priv->phy->dev, "Port %d is %s\n",
+               dev_info(&priv->phy->mdio.dev, "Port %d is %s\n",
                         i, link_new ? "up" : "down");
        }
 
@@ -2063,10 +2121,10 @@ ar8xxx_phy_read_status(struct phy_device *phydev)
        if (phydev->state == PHY_CHANGELINK)
                ar8xxx_check_link_states(priv);
 
-       if (phydev->addr != 0)
+       if (phydev->mdio.addr != 0)
                return genphy_read_status(phydev);
 
-       ar8216_read_port_link(priv, phydev->addr, &link);
+       ar8216_read_port_link(priv, phydev->mdio.addr, &link);
        phydev->link = !!link.link;
        if (!phydev->link)
                return 0;
@@ -2096,7 +2154,7 @@ ar8xxx_phy_read_status(struct phy_device *phydev)
 static int
 ar8xxx_phy_config_aneg(struct phy_device *phydev)
 {
-       if (phydev->addr == 0)
+       if (phydev->mdio.addr == 0)
                return 0;
 
        return genphy_config_aneg(phydev);
@@ -2151,15 +2209,15 @@ ar8xxx_phy_probe(struct phy_device *phydev)
        int ret;
 
        /* skip PHYs at unused adresses */
-       if (phydev->addr != 0 && phydev->addr != 4)
+       if (phydev->mdio.addr != 0 && phydev->mdio.addr != 4)
                return -ENODEV;
 
-       if (!ar8xxx_is_possible(phydev->bus))
+       if (!ar8xxx_is_possible(phydev->mdio.bus))
                return -ENODEV;
 
        mutex_lock(&ar8xxx_dev_list_lock);
        list_for_each_entry(priv, &ar8xxx_dev_list, list)
-               if (priv->mii_bus == phydev->bus)
+               if (priv->mii_bus == phydev->mdio.bus)
                        goto found;
 
        priv = ar8xxx_create();
@@ -2168,7 +2226,7 @@ ar8xxx_phy_probe(struct phy_device *phydev)
                goto unlock;
        }
 
-       priv->mii_bus = phydev->bus;
+       priv->mii_bus = phydev->mdio.bus;
 
        ret = ar8xxx_probe_switch(priv);
        if (ret)
@@ -2189,7 +2247,7 @@ ar8xxx_phy_probe(struct phy_device *phydev)
 found:
        priv->use_count++;
 
-       if (phydev->addr == 0) {
+       if (phydev->mdio.addr == 0) {
                if (ar8xxx_has_gige(priv)) {
                        phydev->supported = SUPPORTED_1000baseT_Full;
                        phydev->advertising = ADVERTISED_1000baseT_Full;
@@ -2270,44 +2328,28 @@ ar8xxx_phy_remove(struct phy_device *phydev)
        ar8xxx_free(priv);
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
 static int
 ar8xxx_phy_soft_reset(struct phy_device *phydev)
 {
        /* we don't need an extra reset */
        return 0;
 }
-#endif
-
-static struct phy_driver ar8xxx_phy_driver = {
-       .phy_id         = 0x004d0000,
-       .name           = "Atheros AR8216/AR8236/AR8316",
-       .phy_id_mask    = 0xffff0000,
-       .features       = PHY_BASIC_FEATURES,
-       .probe          = ar8xxx_phy_probe,
-       .remove         = ar8xxx_phy_remove,
-       .detach         = ar8xxx_phy_detach,
-       .config_init    = ar8xxx_phy_config_init,
-       .config_aneg    = ar8xxx_phy_config_aneg,
-       .read_status    = ar8xxx_phy_read_status,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
-       .soft_reset     = ar8xxx_phy_soft_reset,
-#endif
-       .driver         = { .owner = THIS_MODULE },
-};
-
-int __init
-ar8xxx_init(void)
-{
-       return phy_driver_register(&ar8xxx_phy_driver);
-}
 
-void __exit
-ar8xxx_exit(void)
-{
-       phy_driver_unregister(&ar8xxx_phy_driver);
-}
+static struct phy_driver ar8xxx_phy_driver[] = {
+       {
+               .phy_id         = 0x004d0000,
+               .name           = "Atheros AR8216/AR8236/AR8316",
+               .phy_id_mask    = 0xffff0000,
+               .features       = PHY_BASIC_FEATURES,
+               .probe          = ar8xxx_phy_probe,
+               .remove         = ar8xxx_phy_remove,
+               .detach         = ar8xxx_phy_detach,
+               .config_init    = ar8xxx_phy_config_init,
+               .config_aneg    = ar8xxx_phy_config_aneg,
+               .read_status    = ar8xxx_phy_read_status,
+               .soft_reset     = ar8xxx_phy_soft_reset,
+       }
+};
 
-module_init(ar8xxx_init);
-module_exit(ar8xxx_exit);
+module_phy_driver(ar8xxx_phy_driver);
 MODULE_LICENSE("GPL");