--- a/drivers/net/ethernet/ar231x/ar231x.c +++ b/drivers/net/ethernet/ar231x/ar231x.c @@ -150,6 +150,7 @@ static int ar231x_mdiobus_write(struct m static int ar231x_mdiobus_reset(struct mii_bus *bus); static int ar231x_mdiobus_probe (struct net_device *dev); static void ar231x_adjust_link(struct net_device *dev); +static bool no_phy = false; #ifndef ERR #define ERR(fmt, args...) printk("%s: " fmt, __func__, ##args) @@ -182,6 +183,32 @@ static const struct net_device_ops ar231 #endif }; +static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id) +{ + int phy_reg; + + /** + * Grab the bits from PHYIR1, and put them + * in the upper half. + */ + phy_reg = mdiobus_read(bus, addr, MII_PHYSID1); + + if (phy_reg < 0) + return -EIO; + + *phy_id = (phy_reg & 0xffff) << 16; + + /* Grab the bits from PHYIR2, and put them in the lower half */ + phy_reg = mdiobus_read(bus, addr, MII_PHYSID2); + + if (phy_reg < 0) + return -EIO; + + *phy_id |= (phy_reg & 0xffff); + + return 0; +} + int ar231x_probe(struct platform_device *pdev) { struct net_device *dev; @@ -297,6 +324,23 @@ int ar231x_probe(struct platform_device mdiobus_register(sp->mii_bus); + /** + * Workaround for Micrel switch, which is only available on + * one PHY and cannot be configured through MDIO. + */ + if (!no_phy) { + u32 phy_id = 0; + get_phy_id(sp->mii_bus, 1, &phy_id); + if (phy_id == 0x00221450) + no_phy = true; + } + if (no_phy) { + sp->link = 1; + netif_carrier_on(dev); + return 0; + } + no_phy = true; + if (ar231x_mdiobus_probe(dev) != 0) { printk(KERN_ERR "%s: mdiobus_probe failed\n", dev->name); rx_tasklet_cleanup(dev); @@ -353,8 +397,10 @@ static int ar231x_remove(struct platform rx_tasklet_cleanup(dev); ar231x_init_cleanup(dev); unregister_netdev(dev); - mdiobus_unregister(sp->mii_bus); - mdiobus_free(sp->mii_bus); + if (sp->mii_bus) { + mdiobus_unregister(sp->mii_bus); + mdiobus_free(sp->mii_bus); + } kfree(dev); return 0; } @@ -1120,6 +1166,9 @@ static int ar231x_ioctl(struct net_devic struct ar231x_private *sp = netdev_priv(dev); int ret; + if (!sp->phy_dev) + return -ENODEV; + switch (cmd) { case SIOCETHTOOL: