X-Git-Url: https://git.archive.openwrt.org/?a=blobdiff_plain;f=target%2Flinux%2Fgeneric%2Ffiles%2Fdrivers%2Fnet%2Fphy%2Far8216.c;h=c0b51e7c67434d5a3dee70f807d67c06abfcc57d;hb=dbeab3d4f98464c7c67832dbf38e35d5947442dd;hp=d980e24ee1b0bab579523a822c78fcadb4a07d85;hpb=2550d8c15548661cb7a96384d12b8b1a9bd55e28;p=openwrt.git diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c index d980e24ee1..c0b51e7c67 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -788,7 +788,7 @@ ar8316_hw_init(struct ar8216_priv *priv) u32 val, newval; struct mii_bus *bus; - val = priv->read(priv, 0x8); + val = priv->read(priv, AR8316_REG_POSTRIP); if (priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { if (priv->port4_phy) { @@ -812,7 +812,7 @@ ar8316_hw_init(struct ar8216_priv *priv) if (val == newval) goto out; - priv->write(priv, 0x8, newval); + priv->write(priv, AR8316_REG_POSTRIP, newval); /* Initialize the ports */ bus = priv->mii_bus; @@ -833,9 +833,10 @@ ar8316_hw_init(struct ar8216_priv *priv) ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL); mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); - msleep(1000); } + msleep(1000); + out: priv->initialized = true; return 0; @@ -1741,9 +1742,6 @@ ar8xxx_mib_init(struct ar8216_priv *priv) if (!priv->mib_stats) return -ENOMEM; - mutex_init(&priv->mib_lock); - INIT_DELAYED_WORK(&priv->mib_work, ar8xxx_mib_work_func); - return 0; } @@ -1758,13 +1756,89 @@ 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; cancel_delayed_work(&priv->mib_work); +} + +static struct ar8216_priv * +ar8xxx_create(void) +{ + struct ar8216_priv *priv; + + priv = kzalloc(sizeof(struct ar8216_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + mutex_init(&priv->reg_mutex); + mutex_init(&priv->mib_lock); + INIT_DELAYED_WORK(&priv->mib_work, ar8xxx_mib_work_func); + + return priv; +} + +static void +ar8xxx_free(struct ar8216_priv *priv) +{ kfree(priv->mib_stats); + kfree(priv); +} + +static struct ar8216_priv * +ar8xxx_create_mii(struct mii_bus *bus) +{ + struct ar8216_priv *priv; + + priv = ar8xxx_create(); + if (priv) { + priv->mii_bus = bus; + priv->read = ar8216_mii_read; + priv->write = ar8216_mii_write; + } + + return priv; +} + +static int +ar8xxx_probe_switch(struct ar8216_priv *priv) +{ + struct switch_dev *swdev; + int ret; + + ret = ar8216_id_chip(priv); + if (ret) + return ret; + + swdev = &priv->dev; + swdev->cpu_port = AR8216_PORT_CPU; + swdev->ops = &ar8216_sw_ops; + + if (chip_is_ar8316(priv)) { + swdev->name = "Atheros AR8316"; + swdev->vlans = AR8X16_MAX_VLANS; + swdev->ports = AR8216_NUM_PORTS; + } else if (chip_is_ar8236(priv)) { + swdev->name = "Atheros AR8236"; + swdev->vlans = AR8216_NUM_VLANS; + swdev->ports = AR8216_NUM_PORTS; + } else if (chip_is_ar8327(priv)) { + swdev->name = "Atheros AR8327"; + swdev->vlans = AR8X16_MAX_VLANS; + swdev->ports = AR8327_NUM_PORTS; + } else { + swdev->name = "Atheros AR8216"; + swdev->vlans = AR8216_NUM_VLANS; + swdev->ports = AR8216_NUM_PORTS; + } + + ret = ar8xxx_mib_init(priv); + if (ret) + return ret; + + return 0; } static int @@ -1776,43 +1850,41 @@ ar8216_config_init(struct phy_device *pdev) int ret; if (!priv) { - priv = kzalloc(sizeof(struct ar8216_priv), GFP_KERNEL); + priv = ar8xxx_create_mii(pdev->bus); if (priv == NULL) return -ENOMEM; - } - priv->mii_bus = pdev->bus; - priv->read = ar8216_mii_read; - priv->write = ar8216_mii_write; + ret = ar8xxx_probe_switch(priv); + if (ret) + goto err_free_priv; + } priv->phy = pdev; - ret = ar8216_id_chip(priv); - if (ret) - goto err_free_priv; + 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 (ar8xxx_has_gige(priv)) { - pdev->supported |= SUPPORTED_1000baseT_Full; - pdev->advertising |= ADVERTISED_1000baseT_Full; - } - if (chip_is_ar8316(priv)) { /* check if we're attaching to the switch twice */ pdev = pdev->bus->phy_map[0]; if (!pdev) { - kfree(priv); + ar8xxx_free(priv); return 0; } /* switch device has not been initialized, reuse priv */ if (!pdev->priv) { priv->port4_phy = true; + priv->dev.ports = (AR8216_NUM_PORTS - 1); pdev->priv = priv; return 0; } - kfree(priv); + ar8xxx_free(priv); /* switch device has been initialized, reinit */ priv = pdev->priv; @@ -1823,53 +1895,16 @@ ar8216_config_init(struct phy_device *pdev) return 0; } - kfree(priv); + ar8xxx_free(priv); return 0; } - if (ar8xxx_has_gige(priv)) - pdev->supported = SUPPORTED_1000baseT_Full; - else - pdev->supported = SUPPORTED_100baseT_Full; - pdev->advertising = pdev->supported; - - mutex_init(&priv->reg_mutex); - pdev->priv = priv; 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); - } - } else if (chip_is_ar8236(priv)) { - swdev->name = "Atheros AR8236"; - swdev->vlans = AR8216_NUM_VLANS; - swdev->ports = AR8216_NUM_PORTS; - } else if (chip_is_ar8327(priv)) { - swdev->name = "Atheros AR8327"; - swdev->vlans = AR8X16_MAX_VLANS; - swdev->ports = AR8327_NUM_PORTS; - } else { - swdev->name = "Atheros AR8216"; - swdev->vlans = AR8216_NUM_VLANS; - } - - ret = ar8xxx_mib_init(priv); - if (ret) - goto err_free_priv; - ret = register_switch(swdev, pdev->attached_dev); if (ret) - goto err_cleanup_mib; + goto err_free_priv; printk(KERN_INFO "%s: %s switch driver attached.\n", pdev->attached_dev->name, swdev->name); @@ -1884,10 +1919,9 @@ ar8216_config_init(struct phy_device *pdev) if (ret) goto err_unregister_switch; - dev->phy_ptr = priv; - /* VID fixup only needed on ar8216 */ - if (chip_is_ar8216(priv) && pdev->addr == 0) { + if (chip_is_ar8216(priv)) { + dev->phy_ptr = priv; dev->priv_flags |= IFF_NO_IP_ALIGN; dev->eth_mangle_rx = ar8216_mangle_rx; dev->eth_mangle_tx = ar8216_mangle_tx; @@ -1901,10 +1935,8 @@ ar8216_config_init(struct phy_device *pdev) err_unregister_switch: unregister_switch(&priv->dev); -err_cleanup_mib: - ar8xxx_mib_cleanup(priv); err_free_priv: - kfree(priv); + ar8xxx_free(priv); pdev->priv = NULL; return ret; } @@ -1960,23 +1992,65 @@ ar8216_config_aneg(struct phy_device *phydev) return genphy_config_aneg(phydev); } +static const u32 ar8xxx_phy_ids[] = { + 0x004dd033, + 0x004dd041, + 0x004dd042, +}; + +static bool +ar8xxx_phy_match(u32 phy_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ar8xxx_phy_ids); i++) + if (phy_id == ar8xxx_phy_ids[i]) + return true; + + return false; +} + +static bool +ar8xxx_is_possible(struct mii_bus *bus) +{ + unsigned i; + + for (i = 0; i < 4; i++) { + u32 phy_id; + + phy_id = mdiobus_read(bus, i, MII_PHYSID1) << 16; + phy_id |= mdiobus_read(bus, i, MII_PHYSID2); + if (!ar8xxx_phy_match(phy_id)) { + pr_debug("ar8xxx: unknown PHY at %s:%02x id:%08x\n", + dev_name(&bus->dev), i, phy_id); + return false; + } + } + + return true; +} + static int ar8216_probe(struct phy_device *pdev) { struct ar8216_priv *priv; int ret; - priv = kzalloc(sizeof(struct ar8216_priv), GFP_KERNEL); + /* skip PHYs at unused adresses */ + if (pdev->addr != 0 && pdev->addr != 4) + return -ENODEV; + + if (!ar8xxx_is_possible(pdev->bus)) + return -ENODEV; + + priv = ar8xxx_create_mii(pdev->bus); if (priv == NULL) return -ENOMEM; - priv->mii_bus = pdev->bus; - priv->read = ar8216_mii_read; - priv->write = ar8216_mii_write; priv->phy = pdev; - ret = ar8216_id_chip(priv); - kfree(priv); + ret = ar8xxx_probe_switch(priv); + ar8xxx_free(priv); return ret; } @@ -2008,8 +2082,8 @@ ar8216_remove(struct phy_device *pdev) if (pdev->addr == 0) unregister_switch(&priv->dev); - ar8xxx_mib_cleanup(priv); - kfree(priv); + ar8xxx_mib_stop(priv); + ar8xxx_free(priv); } static struct phy_driver ar8216_driver = {