ath9k: fix tx queueing issues after background scans
[openwrt/staging/wigyori.git] / target / linux / brcm47xx / patches-3.10 / 780-b44-phylib.patch
1 --- a/drivers/net/ethernet/broadcom/Kconfig
2 +++ b/drivers/net/ethernet/broadcom/Kconfig
3 @@ -24,6 +24,7 @@ config B44
4 select SSB
5 select NET_CORE
6 select MII
7 + select PHYLIB
8 ---help---
9 If you have a network (Ethernet) controller of this type, say Y
10 or M and read the Ethernet-HOWTO, available from
11 --- a/drivers/net/ethernet/broadcom/b44.c
12 +++ b/drivers/net/ethernet/broadcom/b44.c
13 @@ -29,6 +29,7 @@
14 #include <linux/dma-mapping.h>
15 #include <linux/ssb/ssb.h>
16 #include <linux/slab.h>
17 +#include <linux/phy.h>
18
19 #include <asm/uaccess.h>
20 #include <asm/io.h>
21 @@ -300,21 +301,23 @@ static inline int b44_writephy(struct b4
22 }
23
24 /* miilib interface */
25 -static int b44_mii_read(struct net_device *dev, int phy_id, int location)
26 +static int b44_mii_read(struct mii_bus *bus, int phy_id, int location)
27 {
28 u32 val;
29 - struct b44 *bp = netdev_priv(dev);
30 + struct b44 *bp = bus->priv;
31 int rc = __b44_readphy(bp, phy_id, location, &val);
32 if (rc)
33 return 0xffffffff;
34 return val;
35 }
36
37 -static void b44_mii_write(struct net_device *dev, int phy_id, int location,
38 - int val)
39 +static int b44_mii_write(struct mii_bus *bus, int phy_id, int location,
40 + u16 val)
41 {
42 - struct b44 *bp = netdev_priv(dev);
43 + struct b44 *bp = bus->priv;
44 __b44_writephy(bp, phy_id, location, val);
45 +
46 + return 0;
47 }
48
49 static int b44_phy_reset(struct b44 *bp)
50 @@ -1831,102 +1834,24 @@ static int b44_get_settings(struct net_d
51 {
52 struct b44 *bp = netdev_priv(dev);
53
54 - cmd->supported = (SUPPORTED_Autoneg);
55 - cmd->supported |= (SUPPORTED_100baseT_Half |
56 - SUPPORTED_100baseT_Full |
57 - SUPPORTED_10baseT_Half |
58 - SUPPORTED_10baseT_Full |
59 - SUPPORTED_MII);
60 -
61 - cmd->advertising = 0;
62 - if (bp->flags & B44_FLAG_ADV_10HALF)
63 - cmd->advertising |= ADVERTISED_10baseT_Half;
64 - if (bp->flags & B44_FLAG_ADV_10FULL)
65 - cmd->advertising |= ADVERTISED_10baseT_Full;
66 - if (bp->flags & B44_FLAG_ADV_100HALF)
67 - cmd->advertising |= ADVERTISED_100baseT_Half;
68 - if (bp->flags & B44_FLAG_ADV_100FULL)
69 - cmd->advertising |= ADVERTISED_100baseT_Full;
70 - cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
71 - ethtool_cmd_speed_set(cmd, ((bp->flags & B44_FLAG_100_BASE_T) ?
72 - SPEED_100 : SPEED_10));
73 - cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ?
74 - DUPLEX_FULL : DUPLEX_HALF;
75 - cmd->port = 0;
76 - cmd->phy_address = bp->phy_addr;
77 - cmd->transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ?
78 - XCVR_INTERNAL : XCVR_EXTERNAL;
79 - cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
80 - AUTONEG_DISABLE : AUTONEG_ENABLE;
81 - if (cmd->autoneg == AUTONEG_ENABLE)
82 - cmd->advertising |= ADVERTISED_Autoneg;
83 - if (!netif_running(dev)){
84 - ethtool_cmd_speed_set(cmd, 0);
85 - cmd->duplex = 0xff;
86 - }
87 - cmd->maxtxpkt = 0;
88 - cmd->maxrxpkt = 0;
89 - return 0;
90 + return phy_ethtool_gset(bp->phydev, cmd);
91 }
92
93 static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
94 {
95 struct b44 *bp = netdev_priv(dev);
96 - u32 speed = ethtool_cmd_speed(cmd);
97 -
98 - /* We do not support gigabit. */
99 - if (cmd->autoneg == AUTONEG_ENABLE) {
100 - if (cmd->advertising &
101 - (ADVERTISED_1000baseT_Half |
102 - ADVERTISED_1000baseT_Full))
103 - return -EINVAL;
104 - } else if ((speed != SPEED_100 &&
105 - speed != SPEED_10) ||
106 - (cmd->duplex != DUPLEX_HALF &&
107 - cmd->duplex != DUPLEX_FULL)) {
108 - return -EINVAL;
109 - }
110 + int ret;
111
112 spin_lock_irq(&bp->lock);
113
114 - if (cmd->autoneg == AUTONEG_ENABLE) {
115 - bp->flags &= ~(B44_FLAG_FORCE_LINK |
116 - B44_FLAG_100_BASE_T |
117 - B44_FLAG_FULL_DUPLEX |
118 - B44_FLAG_ADV_10HALF |
119 - B44_FLAG_ADV_10FULL |
120 - B44_FLAG_ADV_100HALF |
121 - B44_FLAG_ADV_100FULL);
122 - if (cmd->advertising == 0) {
123 - bp->flags |= (B44_FLAG_ADV_10HALF |
124 - B44_FLAG_ADV_10FULL |
125 - B44_FLAG_ADV_100HALF |
126 - B44_FLAG_ADV_100FULL);
127 - } else {
128 - if (cmd->advertising & ADVERTISED_10baseT_Half)
129 - bp->flags |= B44_FLAG_ADV_10HALF;
130 - if (cmd->advertising & ADVERTISED_10baseT_Full)
131 - bp->flags |= B44_FLAG_ADV_10FULL;
132 - if (cmd->advertising & ADVERTISED_100baseT_Half)
133 - bp->flags |= B44_FLAG_ADV_100HALF;
134 - if (cmd->advertising & ADVERTISED_100baseT_Full)
135 - bp->flags |= B44_FLAG_ADV_100FULL;
136 - }
137 - } else {
138 - bp->flags |= B44_FLAG_FORCE_LINK;
139 - bp->flags &= ~(B44_FLAG_100_BASE_T | B44_FLAG_FULL_DUPLEX);
140 - if (speed == SPEED_100)
141 - bp->flags |= B44_FLAG_100_BASE_T;
142 - if (cmd->duplex == DUPLEX_FULL)
143 - bp->flags |= B44_FLAG_FULL_DUPLEX;
144 - }
145 -
146 if (netif_running(dev))
147 b44_setup_phy(bp);
148
149 + ret = phy_ethtool_sset(bp->phydev, cmd);
150 +
151 spin_unlock_irq(&bp->lock);
152
153 - return 0;
154 + return ret;
155 }
156
157 static void b44_get_ringparam(struct net_device *dev,
158 @@ -2102,20 +2027,74 @@ static const struct ethtool_ops b44_etht
159
160 static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
161 {
162 - struct mii_ioctl_data *data = if_mii(ifr);
163 struct b44 *bp = netdev_priv(dev);
164 int err = -EINVAL;
165
166 if (!netif_running(dev))
167 goto out;
168
169 + if (!bp->phydev)
170 + return -EINVAL;
171 +
172 spin_lock_irq(&bp->lock);
173 - err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
174 + err = phy_mii_ioctl(bp->phydev, ifr, cmd);
175 spin_unlock_irq(&bp->lock);
176 out:
177 return err;
178 }
179
180 +static void b44_adjust_link(struct net_device *dev)
181 +{
182 + struct b44 *bp = netdev_priv(dev);
183 + struct phy_device *phydev = bp->phydev;
184 + bool status_changed = 0;
185 +
186 + BUG_ON(!phydev);
187 +
188 + if (bp->old_link != phydev->link) {
189 + status_changed = 1;
190 + bp->old_link = phydev->link;
191 + }
192 +
193 + /* reflect duplex change */
194 + if (phydev->link && (bp->old_duplex != phydev->duplex)) {
195 + status_changed = 1;
196 + bp->old_duplex = phydev->duplex;
197 + }
198 +
199 + if (status_changed)
200 + phy_print_status(phydev);
201 +}
202 +
203 +static int b44_mii_probe(struct net_device *dev)
204 +{
205 + struct b44 *bp = netdev_priv(dev);
206 + struct phy_device *phydev = NULL;
207 + char phy_id[MII_BUS_ID_SIZE + 3];
208 +
209 + /* connect to PHY */
210 + snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
211 + bp->mii_bus->id, bp->phy_addr);
212 +
213 + phydev = phy_connect(dev, phy_id, &b44_adjust_link,
214 + PHY_INTERFACE_MODE_MII);
215 + if (IS_ERR(phydev)) {
216 + netdev_err(dev, "could not attach PHY: %s\n", phy_id);
217 + bp->phy_addr = B44_PHY_ADDR_NO_PHY;
218 + return PTR_ERR(phydev);
219 + }
220 +
221 + bp->phydev = phydev;
222 + bp->old_link = 0;
223 + bp->old_duplex = -1;
224 + bp->phy_addr = phydev->addr;
225 +
226 + netdev_info(dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
227 + phydev->drv->name, dev_name(&phydev->dev));
228 +
229 + return 0;
230 +}
231 +
232 static int b44_get_invariants(struct b44 *bp)
233 {
234 struct ssb_device *sdev = bp->sdev;
235 @@ -2235,12 +2214,40 @@ static int b44_init_one(struct ssb_devic
236 goto err_out_powerdown;
237 }
238
239 - bp->mii_if.dev = dev;
240 - bp->mii_if.mdio_read = b44_mii_read;
241 - bp->mii_if.mdio_write = b44_mii_write;
242 - bp->mii_if.phy_id = bp->phy_addr;
243 - bp->mii_if.phy_id_mask = 0x1f;
244 - bp->mii_if.reg_num_mask = 0x1f;
245 + bp->mii_bus = mdiobus_alloc();
246 + if (!bp->mii_bus) {
247 + dev_err(sdev->dev, "mdiobus_alloc() failed\n");
248 + err = -ENOMEM;
249 + goto err_out_powerdown;
250 + }
251 +
252 + bp->mii_bus->priv = bp;
253 + bp->mii_bus->read = b44_mii_read;
254 + bp->mii_bus->write = b44_mii_write;
255 + bp->mii_bus->name = "b44_eth_mii";
256 + bp->mii_bus->parent = sdev->dev;
257 + bp->mii_bus->phy_mask = ~(1 << bp->phy_addr);
258 + snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", instance);
259 + bp->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
260 + if (!bp->mii_bus->irq) {
261 + dev_err(sdev->dev, "mii_bus irq allocation failed\n");
262 + err = -ENOMEM;
263 + goto err_out_mdiobus;
264 + }
265 +
266 + memset(bp->mii_bus->irq, PHY_POLL, sizeof(int) * PHY_MAX_ADDR);
267 +
268 + err = mdiobus_register(bp->mii_bus);
269 + if (err) {
270 + dev_err(sdev->dev, "failed to register MII bus\n");
271 + goto err_out_mdiobus_irq;
272 + }
273 +
274 + err = b44_mii_probe(dev);
275 + if (err) {
276 + dev_err(sdev->dev, "failed to probe MII bus\n");
277 + goto err_out_mdiobus_unregister;
278 + }
279
280 /* By default, advertise all speed/duplex settings. */
281 bp->flags |= (B44_FLAG_ADV_10HALF | B44_FLAG_ADV_10FULL |
282 @@ -2272,6 +2279,16 @@ static int b44_init_one(struct ssb_devic
283
284 return 0;
285
286 +
287 +err_out_mdiobus_unregister:
288 + mdiobus_unregister(bp->mii_bus);
289 +
290 +err_out_mdiobus_irq:
291 + kfree(bp->mii_bus->irq);
292 +
293 +err_out_mdiobus:
294 + mdiobus_free(bp->mii_bus);
295 +
296 err_out_powerdown:
297 ssb_bus_may_powerdown(sdev->bus);
298
299 @@ -2285,8 +2302,12 @@ out:
300 static void b44_remove_one(struct ssb_device *sdev)
301 {
302 struct net_device *dev = ssb_get_drvdata(sdev);
303 + struct b44 *bp = netdev_priv(dev);
304
305 unregister_netdev(dev);
306 + mdiobus_unregister(bp->mii_bus);
307 + kfree(bp->mii_bus->irq);
308 + mdiobus_free(bp->mii_bus);
309 ssb_device_disable(sdev, 0);
310 ssb_bus_may_powerdown(sdev->bus);
311 free_netdev(dev);
312 --- a/drivers/net/ethernet/broadcom/b44.h
313 +++ b/drivers/net/ethernet/broadcom/b44.h
314 @@ -396,7 +396,10 @@ struct b44 {
315 u32 tx_pending;
316 u8 phy_addr;
317 u8 force_copybreak;
318 - struct mii_if_info mii_if;
319 + struct phy_device *phydev;
320 + struct mii_bus *mii_bus;
321 + int old_link;
322 + int old_duplex;
323 };
324
325 #endif /* _B44_H */