Index: linux-2.6.32.7/drivers/net/ar231x.c =================================================================== --- linux-2.6.32.7.orig/drivers/net/ar231x.c 2010-02-03 17:02:28.998430523 +0100 +++ linux-2.6.32.7/drivers/net/ar231x.c 2010-02-03 17:03:01.346429245 +0100 @@ -148,6 +148,7 @@ 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) @@ -278,6 +279,21 @@ 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); @@ -334,8 +350,10 @@ 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; } @@ -836,7 +854,12 @@ dev->stats.rx_bytes += skb->len; /* pass the packet to upper layers */ - sp->rx(skb); + if (sp->rx) { + sp->rx(skb); + } else { + skb->protocol = eth_type_trans(skb, skb->dev); + netif_rx(skb); + } skb_new->dev = dev; /* 16 bit align */ @@ -1123,6 +1146,9 @@ struct ar231x_private *sp = netdev_priv(dev); int ret; + if (!sp->phy_dev) + return -ENODEV; + switch (cmd) { case SIOCETHTOOL: