X-Git-Url: https://git.archive.openwrt.org/?p=openwrt.git;a=blobdiff_plain;f=target%2Flinux%2Fgeneric%2Ffiles%2Fdrivers%2Fnet%2Fphy%2Far8216.c;h=811e406f3a5dd91bc7d04ba111c036ed0ec8f9ad;hp=492963de1c5d8d92d86eed714a3e444fe45c6614;hb=d6c3cd0d2da1aa1bd34195369069a093686c1a22;hpb=0ee6eaa43bf3f462453726729ac6d95f0a475359 diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c index 492963de1c..811e406f3a 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -101,6 +101,9 @@ struct ar8216_priv { int mib_next_port; u64 *mib_stats; + struct list_head list; + unsigned int use_count; + /* all fields below are cleared on reset */ bool vlan; u16 vlan_id[AR8X16_MAX_VLANS]; @@ -198,6 +201,9 @@ static const struct ar8xxx_mib_desc ar8236_mibs[] = { MIB_DESC(1, AR8236_STATS_TXLATECOL, "TxLateCol"), }; +static DEFINE_MUTEX(ar8xxx_dev_list_lock); +static LIST_HEAD(ar8xxx_dev_list); + static inline struct ar8216_priv * swdev_to_ar8216(struct switch_dev *swdev) { @@ -794,18 +800,18 @@ ar8316_hw_init(struct ar8216_priv *priv) if (priv->port4_phy) { /* value taken from Ubiquiti RouterStation Pro */ newval = 0x81461bea; - printk(KERN_INFO "ar8316: Using port 4 as PHY\n"); + pr_info("ar8316: Using port 4 as PHY\n"); } else { newval = 0x01261be2; - printk(KERN_INFO "ar8316: Using port 4 as switch port\n"); + pr_info("ar8316: Using port 4 as switch port\n"); } } else if (priv->phy->interface == PHY_INTERFACE_MODE_GMII) { /* value taken from AVM Fritz!Box 7390 sources */ newval = 0x010e5b71; } else { /* no known value for phy interface */ - printk(KERN_ERR "ar8316: unsupported mii mode: %d.\n", - priv->phy->interface); + pr_err("ar8316: unsupported mii mode: %d.\n", + priv->phy->interface); return -EINVAL; } @@ -1689,9 +1695,8 @@ ar8216_id_chip(struct ar8216_priv *priv) priv->chip = &ar8327_chip; break; default: - printk(KERN_DEBUG - "ar8216: Unknown Atheros device [ver=%d, rev=%d]\n", - priv->chip_ver, priv->chip_rev); + pr_err("ar8216: Unknown Atheros device [ver=%d, rev=%d]\n", + priv->chip_ver, priv->chip_rev); return -ENODEV; } @@ -1756,7 +1761,7 @@ ar8xxx_mib_start(struct ar8216_priv *priv) } static void -ar8xxx_mib_cleanup(struct ar8216_priv *priv) +ar8xxx_mib_stop(struct ar8216_priv *priv) { if (!ar8xxx_has_mib_counters(priv)) return; @@ -1803,77 +1808,23 @@ ar8xxx_create_mii(struct mii_bus *bus) } static int -ar8216_config_init(struct phy_device *pdev) +ar8xxx_probe_switch(struct ar8216_priv *priv) { - struct ar8216_priv *priv = pdev->priv; - struct net_device *dev = pdev->attached_dev; struct switch_dev *swdev; int ret; - if (!priv) { - priv = ar8xxx_create_mii(pdev->bus); - if (priv == NULL) - return -ENOMEM; - - ret = ar8216_id_chip(priv); - if (ret) - goto err_free_priv; - } - - priv->phy = pdev; - - if (ar8xxx_has_gige(priv)) - pdev->supported = SUPPORTED_1000baseT_Full; - else - pdev->supported = SUPPORTED_100baseT_Full; - pdev->advertising = pdev->supported; - - if (pdev->addr != 0) { - if (chip_is_ar8316(priv)) { - /* check if we're attaching to the switch twice */ - pdev = pdev->bus->phy_map[0]; - if (!pdev) { - ar8xxx_free(priv); - return 0; - } - - /* switch device has not been initialized, reuse priv */ - if (!pdev->priv) { - priv->port4_phy = true; - pdev->priv = priv; - return 0; - } - - ar8xxx_free(priv); - - /* switch device has been initialized, reinit */ - priv = pdev->priv; - priv->dev.ports = (AR8216_NUM_PORTS - 1); - priv->initialized = false; - priv->port4_phy = true; - ar8316_hw_init(priv); - return 0; - } - - ar8xxx_free(priv); - return 0; - } - - pdev->priv = priv; + ret = ar8216_id_chip(priv); + if (ret) + return ret; swdev = &priv->dev; swdev->cpu_port = AR8216_PORT_CPU; swdev->ops = &ar8216_sw_ops; - swdev->ports = AR8216_NUM_PORTS; if (chip_is_ar8316(priv)) { swdev->name = "Atheros AR8316"; swdev->vlans = AR8X16_MAX_VLANS; - - if (priv->port4_phy) { - /* port 5 connected to the other mac, therefore unusable */ - swdev->ports = (AR8216_NUM_PORTS - 1); - } + swdev->ports = AR8216_NUM_PORTS; } else if (chip_is_ar8236(priv)) { swdev->name = "Atheros AR8236"; swdev->vlans = AR8216_NUM_VLANS; @@ -1885,18 +1836,50 @@ ar8216_config_init(struct phy_device *pdev) } else { swdev->name = "Atheros AR8216"; swdev->vlans = AR8216_NUM_VLANS; + swdev->ports = AR8216_NUM_PORTS; } ret = ar8xxx_mib_init(priv); if (ret) - goto err_free_priv; + return ret; + + return 0; +} + +static int +ar8216_config_init(struct phy_device *phydev) +{ + struct ar8216_priv *priv = phydev->priv; + struct net_device *dev = phydev->attached_dev; + struct switch_dev *swdev; + int ret; - ret = register_switch(swdev, pdev->attached_dev); + if (WARN_ON(!priv)) + return -ENODEV; + + priv->phy = phydev; + + if (phydev->addr != 0) { + if (chip_is_ar8316(priv)) { + /* switch device has been initialized, reinit */ + priv->dev.ports = (AR8216_NUM_PORTS - 1); + priv->initialized = false; + priv->port4_phy = true; + ar8316_hw_init(priv); + return 0; + } + + return 0; + } + + swdev = &priv->dev; + swdev->alias = dev_name(&priv->mii_bus->dev); + ret = register_switch(swdev, NULL); if (ret) - goto err_free_priv; + goto err; - printk(KERN_INFO "%s: %s switch driver attached.\n", - pdev->attached_dev->name, swdev->name); + pr_info("%s: %s switch registered on %s\n", + swdev->devname, swdev->name, dev_name(&priv->mii_bus->dev)); priv->init = true; @@ -1924,9 +1907,7 @@ ar8216_config_init(struct phy_device *pdev) err_unregister_switch: unregister_switch(&priv->dev); -err_free_priv: - ar8xxx_free(priv); - pdev->priv = NULL; +err: return ret; } @@ -2020,34 +2001,69 @@ ar8xxx_is_possible(struct mii_bus *bus) } static int -ar8216_probe(struct phy_device *pdev) +ar8216_probe(struct phy_device *phydev) { struct ar8216_priv *priv; int ret; /* skip PHYs at unused adresses */ - if (pdev->addr != 0 && pdev->addr != 4) + if (phydev->addr != 0 && phydev->addr != 4) return -ENODEV; - if (!ar8xxx_is_possible(pdev->bus)) + if (!ar8xxx_is_possible(phydev->bus)) return -ENODEV; - priv = ar8xxx_create_mii(pdev->bus); - if (priv == NULL) - return -ENOMEM; + mutex_lock(&ar8xxx_dev_list_lock); + list_for_each_entry(priv, &ar8xxx_dev_list, list) + if (priv->mii_bus == phydev->bus) + goto found; - priv->phy = pdev; + priv = ar8xxx_create_mii(phydev->bus); + if (priv == NULL) { + ret = -ENOMEM; + goto unlock; + } - ret = ar8216_id_chip(priv); - ar8xxx_free(priv); + ret = ar8xxx_probe_switch(priv); + if (ret) + goto free_priv; + +found: + if (phydev->addr == 0) { + if (ar8xxx_has_gige(priv)) { + phydev->supported = SUPPORTED_1000baseT_Full; + phydev->advertising = ADVERTISED_1000baseT_Full; + } else { + phydev->supported = SUPPORTED_100baseT_Full; + phydev->advertising = ADVERTISED_100baseT_Full; + } + } else { + if (ar8xxx_has_gige(priv)) { + phydev->supported |= SUPPORTED_1000baseT_Full; + phydev->advertising |= ADVERTISED_1000baseT_Full; + } + } + + phydev->priv = priv; + priv->use_count++; + list_add(&priv->list, &ar8xxx_dev_list); + + mutex_unlock(&ar8xxx_dev_list_lock); + + return 0; + +free_priv: + ar8xxx_free(priv); +unlock: + mutex_unlock(&ar8xxx_dev_list_lock); return ret; } static void -ar8216_detach(struct phy_device *pdev) +ar8216_detach(struct phy_device *phydev) { - struct net_device *dev = pdev->attached_dev; + struct net_device *dev = phydev->attached_dev; if (!dev) return; @@ -2059,19 +2075,23 @@ ar8216_detach(struct phy_device *pdev) } static void -ar8216_remove(struct phy_device *pdev) +ar8216_remove(struct phy_device *phydev) { - struct ar8216_priv *priv = pdev->priv; + struct ar8216_priv *priv = phydev->priv; - if (!priv) + if (WARN_ON(!priv)) return; - pdev->priv = NULL; + phydev->priv = NULL; + if (--priv->use_count > 0) + return; - if (pdev->addr == 0) - unregister_switch(&priv->dev); + mutex_lock(&ar8xxx_dev_list_lock); + list_del(&priv->list); + mutex_unlock(&ar8xxx_dev_list_lock); - ar8xxx_mib_cleanup(priv); + unregister_switch(&priv->dev); + ar8xxx_mib_stop(priv); ar8xxx_free(priv); }