kernel: backport upstream inet fix
[openwrt.git] / target / linux / atheros / patches-3.10 / 220-enet_micrel_workaround.patch
1 --- a/drivers/net/ethernet/ar231x/ar231x.c
2 +++ b/drivers/net/ethernet/ar231x/ar231x.c
3 @@ -150,6 +150,7 @@ static int ar231x_mdiobus_write(struct m
4  static int ar231x_mdiobus_reset(struct mii_bus *bus);
5  static int ar231x_mdiobus_probe (struct net_device *dev);
6  static void ar231x_adjust_link(struct net_device *dev);
7 +static bool no_phy = false;
8  
9  #ifndef ERR
10  #define ERR(fmt, args...) printk("%s: " fmt, __func__, ##args)
11 @@ -182,6 +183,30 @@ static const struct net_device_ops ar231
12  #endif
13  };
14  
15 +static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
16 +{
17 +       int phy_reg;
18 +
19 +       /* Grab the bits from PHYIR1, and put them
20 +        * in the upper half */
21 +       phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
22 +
23 +       if (phy_reg < 0)
24 +               return -EIO;
25 +
26 +       *phy_id = (phy_reg & 0xffff) << 16;
27 +
28 +       /* Grab the bits from PHYIR2, and put them in the lower half */
29 +       phy_reg = mdiobus_read(bus, addr, MII_PHYSID2);
30 +
31 +       if (phy_reg < 0)
32 +               return -EIO;
33 +
34 +       *phy_id |= (phy_reg & 0xffff);
35 +
36 +       return 0;
37 +}
38 +
39  int ar231x_probe(struct platform_device *pdev)
40  {
41         struct net_device *dev;
42 @@ -299,6 +324,21 @@ int ar231x_probe(struct platform_device
43  
44         mdiobus_register(sp->mii_bus);
45  
46 +       /* Workaround for Micrel switch, which is only available on
47 +        * one PHY and cannot be configured through MDIO */
48 +       if (!no_phy) {
49 +               u32 phy_id = 0;
50 +               get_phy_id(sp->mii_bus, 1, &phy_id);
51 +               if (phy_id == 0x00221450)
52 +                       no_phy = true;
53 +       }
54 +       if (no_phy) {
55 +               sp->link = 1;
56 +               netif_carrier_on(dev);
57 +               return 0;
58 +       }
59 +       no_phy = true;
60 +
61         if (ar231x_mdiobus_probe(dev) != 0) {
62                 printk(KERN_ERR "%s: mdiobus_probe failed\n", dev->name);
63                 rx_tasklet_cleanup(dev);
64 @@ -355,8 +395,10 @@ static int ar231x_remove(struct platform
65         rx_tasklet_cleanup(dev);
66         ar231x_init_cleanup(dev);
67         unregister_netdev(dev);
68 -       mdiobus_unregister(sp->mii_bus);
69 -       mdiobus_free(sp->mii_bus);
70 +       if (sp->mii_bus) {
71 +               mdiobus_unregister(sp->mii_bus);
72 +               mdiobus_free(sp->mii_bus);
73 +       }
74         kfree(dev);
75         return 0;
76  }
77 @@ -1132,6 +1174,9 @@ static int ar231x_ioctl(struct net_devic
78         struct ar231x_private *sp = netdev_priv(dev);
79         int ret;
80  
81 +       if (!sp->phy_dev)
82 +               return -ENODEV;
83 +
84         switch (cmd) {
85  
86         case SIOCETHTOOL: