root/src/linux/ar531x/linux-2.6.23/drivers/net/phy/mvswitch.c

Revision 11888, 10.4 kB (checked in by BrainSlayer, 8 months ago)

fix jhash support

Line 
1 /*
2  * Marvell 88E6060 switch driver
3  * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
4  * Copyright (c) 2008 Sebastian Gottschall <s.gottschall@dd-wrt.com> (just 88E6061 support)
5  *
6  * This program is free software; you can redistribute  it and/or modify it
7  * under  the terms of the GNU General Public License v2 as published by the
8  * Free Software Foundation
9  */
10 #include <linux/kernel.h>
11 #include <linux/string.h>
12 #include <linux/errno.h>
13 #include <linux/unistd.h>
14 #include <linux/slab.h>
15 #include <linux/interrupt.h>
16 #include <linux/init.h>
17 #include <linux/delay.h>
18 #include <linux/netdevice.h>
19 #include <linux/etherdevice.h>
20 #include <linux/skbuff.h>
21 #include <linux/spinlock.h>
22 #include <linux/mm.h>
23 #include <linux/module.h>
24 #include <linux/mii.h>
25 #include <linux/ethtool.h>
26 #include <linux/phy.h>
27 #include <linux/if_vlan.h>
28
29 #include <asm/io.h>
30 #include <asm/irq.h>
31 #include <asm/uaccess.h>
32 #include "mvswitch.h"
33
34 /* Undefine this to use trailer mode instead.
35  * I don't know if header mode works with all chips */
36 #define HEADER_MODE     1
37
38 MODULE_DESCRIPTION("Marvell 88E6060 Switch driver");
39 MODULE_AUTHOR("Felix Fietkau");
40 MODULE_LICENSE("GPL");
41
42 struct mvswitch_priv {
43         /* the driver's tx function */
44         int (*hardstart)(struct sk_buff *skb, struct net_device *dev);
45         struct vlan_group *grp;
46         u8 vlans[16];
47 };
48
49 #define to_mvsw(_phy) ((struct mvswitch_priv *) (_phy)->priv)
50
51 static inline u16
52 r16(struct phy_device *phydev, int addr, int reg)
53 {
54         return phydev->bus->read(phydev->bus, addr, reg);
55 }
56
57 static inline void
58 w16(struct phy_device *phydev, int addr, int reg, u16 val)
59 {
60         phydev->bus->write(phydev->bus, addr, reg, val);
61 }
62
63
64 static int
65 mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev)
66 {
67         struct mvswitch_priv *priv;
68         char *buf = NULL;
69         u16 vid;
70
71         priv = dev->phy_ptr;
72         if (unlikely(!priv))
73                 goto error;
74
75         if (unlikely(skb->len < 16))
76                 goto error;
77
78 #ifdef HEADER_MODE
79         if (__vlan_hwaccel_get_tag(skb, &vid))
80                 goto error;
81
82         if (skb_cloned(skb) || (skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) {
83                 if (pskb_expand_head(skb, MV_HEADER_SIZE, (skb->len < 62 ? 62 - skb->len : 0), GFP_ATOMIC))
84                         goto error_expand;
85                 if (skb->len < 62)
86                         skb->len = 62;
87         }
88         buf = skb_push(skb, MV_HEADER_SIZE);
89 #else
90         if (__vlan_get_tag(skb, &vid))
91                 goto error;
92
93         if (unlikely((vid > 15 || !priv->vlans[vid])))
94                 goto error;
95
96         if (skb->len <= 64) {
97                 if (pskb_expand_head(skb, 0, 64 + MV_TRAILER_SIZE - skb->len, GFP_ATOMIC))
98                         goto error_expand;
99
100                 buf = skb->data + 64;
101                 skb->len = 64 + MV_TRAILER_SIZE;
102         } else {
103                 if (skb_cloned(skb) || unlikely(skb_tailroom(skb) < 4)) {
104                         if (pskb_expand_head(skb, 0, 4, GFP_ATOMIC))
105                                 goto error_expand;
106                 }
107                 buf = skb_put(skb, 4);
108         }
109
110         /* move the ethernet header 4 bytes forward, overwriting the vlan tag */
111         memmove(skb->data + 4, skb->data, 12);
112         skb->data += 4;
113         skb->len -= 4;
114         skb->mac_header += 4;
115 #endif
116
117         if (!buf)
118                 goto error;
119
120
121 #ifdef HEADER_MODE
122         /* prepend the tag */
123         *((__be16 *) buf) = cpu_to_be16(
124                 ((vid << MV_HEADER_VLAN_S) & MV_HEADER_VLAN_M) |
125                 ((priv->vlans[vid] << MV_HEADER_PORTS_S) & MV_HEADER_PORTS_M)
126         );
127 #else
128         /* append the tag */
129         *((__be32 *) buf) = cpu_to_be32((
130                 (MV_TRAILER_OVERRIDE << MV_TRAILER_FLAGS_S) |
131                 ((priv->vlans[vid] & MV_TRAILER_PORTS_M) << MV_TRAILER_PORTS_S)
132         ));
133 #endif
134
135         return priv->hardstart(skb, dev);
136
137 error_expand:
138         if (net_ratelimit())
139                 printk("%s: failed to expand/update skb for the switch\n", dev->name);
140
141 error:
142         /* any errors? drop the packet! */
143         dev_kfree_skb_any(skb);
144         return 0;
145 }
146
147 static int
148 mvswitch_mangle_rx(struct sk_buff *skb, int napi)
149 {
150         struct mvswitch_priv *priv;
151         struct net_device *dev;
152         int vlan = -1;
153         unsigned char *buf;
154         int i;
155
156         dev = skb->dev;
157         if (!dev)
158                 goto error;
159
160         priv = dev->phy_ptr;
161         if (!priv)
162                 goto error;
163
164         if (!priv->grp)
165                 goto error;
166
167 #ifdef HEADER_MODE
168         buf = skb->data;
169         skb_pull(skb, MV_HEADER_SIZE);
170 #else
171         buf = skb->data + skb->len - MV_TRAILER_SIZE;
172         if (buf[0] != 0x80)
173                 goto error;
174 #endif
175
176         /* look for the vlan matching the incoming port */
177         for (i = 0; i < ARRAY_SIZE(priv->vlans); i++) {
178                 if ((1 << buf[1]) & priv->vlans[i])
179                         vlan = i;
180         }
181
182         if (vlan == -1)
183                 goto error;
184
185         skb->protocol = eth_type_trans(skb, skb->dev);
186
187         if (napi)
188                 return vlan_hwaccel_receive_skb(skb, priv->grp, vlan);
189         else
190                 return vlan_hwaccel_rx(skb, priv->grp, vlan);
191
192 error:
193         /* no vlan? eat the packet! */
194         dev_kfree_skb_any(skb);
195         return 0;
196 }
197
198
199 static int
200 mvswitch_netif_rx(struct sk_buff *skb)
201 {
202         return mvswitch_mangle_rx(skb, 0);
203 }
204
205 static int
206 mvswitch_netif_receive_skb(struct sk_buff *skb)
207 {
208         return mvswitch_mangle_rx(skb, 1);
209 }
210
211
212 static void
213 mvswitch_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
214 {
215         struct mvswitch_priv *priv = dev->phy_ptr;
216         priv->grp = grp;
217 }
218
219
220 static int
221 mvswitch_wait_mask(struct phy_device *pdev, int addr, int reg, u16 mask, u16 val)
222 {
223         int i = 100;
224         u16 r;
225
226         do {
227                 r = r16(pdev, addr, reg) & mask;
228                 if (r == val)
229                         return 0;
230         } while(--i > 0);
231         return -ETIMEDOUT;
232 }
233
234 static int
235 mvswitch_config_init(struct phy_device *pdev)
236 {
237         struct mvswitch_priv *priv = to_mvsw(pdev);
238         struct net_device *dev = pdev->attached_dev;
239         u8 vlmap = 0;
240         u16 reg;
241         int i;
242         u16 emask;
243         if (!dev)
244                 return -EINVAL;
245
246         printk("%s: Marvell 88E6060 PHY driver attached.\n", dev->name);
247         pdev->supported = ADVERTISED_100baseT_Full;
248         pdev->advertising = ADVERTISED_100baseT_Full;
249         dev->phy_ptr = priv;
250         dev->irq = PHY_POLL;
251         emask = MV_PORTCTRL_ENABLED;
252         reg = r16(pdev, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK; 
253         if (reg == MV_IDENT_VALUE2)
254             {
255             printk("%s: Marvell 88E6061 workaround enabled\n",dev->name);
256             emask = MV_PORTCTRL_ENABLED | MV_PORTCTRL_EGRESSALL;
257             }
258         /* initialize default vlans */
259         for (i = 0; i < MV_PORTS; i++)
260                 priv->vlans[(i == MV_WANPORT ? 1 : 0)] |= (1 << i);
261
262         /* before entering reset, disable all ports */
263         for (i = 0; i < MV_PORTS; i++)
264                 w16(pdev, MV_PORTREG(CONTROL, i), 0x00);
265
266         msleep(2); /* wait for the status change to settle in */
267
268         /* put the ATU in reset */
269         w16(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET);
270
271         i = mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET, 0);
272         if (i < 0) {
273                 printk("%s: Timeout waiting for the switch to reset.\n", dev->name);
274                 return i;
275         }
276
277         /* set the ATU flags */
278         w16(pdev, MV_SWITCHREG(ATU_CTRL),
279                 MV_ATUCTL_NO_LEARN |
280                 MV_ATUCTL_ATU_1K |
281                 MV_ATUCTL_AGETIME(MV_ATUCTL_AGETIME_MIN) /* minimum without disabling ageing */
282         );
283
284         /* initialize the cpu port */
285         w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT),
286 #ifdef HEADER_MODE
287                 MV_PORTCTRL_HEADER |
288 #else
289                 MV_PORTCTRL_RXTR |
290                 MV_PORTCTRL_TXTR |
291 #endif
292                 emask
293         );
294         /* wait for the phy change to settle in */
295         msleep(2);
296         for (i = 0; i < MV_PORTS; i++) {
297                 u8 pvid = 0;
298                 int j;
299
300                 vlmap = 0;
301
302                 /* look for the matching vlan */
303                 for (j = 0; j < ARRAY_SIZE(priv->vlans); j++) {
304                         if (priv->vlans[j] & (1 << i)) {
305                                 vlmap = priv->vlans[j];
306                                 pvid = j;
307                         }
308                 }
309                 /* leave port unconfigured if it's not part of a vlan */
310                 if (!vlmap)
311                         continue;
312
313                 /* add the cpu port to the allowed destinations list */
314                 vlmap |= (1 << MV_CPUPORT);
315
316                 /* take port out of its own vlan destination map */
317                 vlmap &= ~(1 << i);
318
319                 /* apply vlan settings */
320                 w16(pdev, MV_PORTREG(VLANMAP, i),
321                         MV_PORTVLAN_PORTS(vlmap) |
322                         MV_PORTVLAN_ID(i)
323                 );
324
325                 /* re-enable port */
326                 w16(pdev, MV_PORTREG(CONTROL, i),emask);
327         }
328
329         w16(pdev, MV_PORTREG(VLANMAP, MV_CPUPORT),
330                 MV_PORTVLAN_ID(MV_CPUPORT)
331         );
332
333         /* set the port association vector */
334         for (i = 0; i <= MV_PORTS; i++) {
335                 w16(pdev, MV_PORTREG(ASSOC, i),
336                         MV_PORTASSOC_PORTS(1 << i)
337                 );
338         }
339
340         /* init switch control */
341         w16(pdev, MV_SWITCHREG(CTRL),
342                 MV_SWITCHCTL_MSIZE |
343                 MV_SWITCHCTL_DROP
344         );
345
346         /* hook into the tx function */
347         pdev->pkt_align = 2;
348         priv->hardstart = dev->hard_start_xmit;
349         pdev->netif_receive_skb = mvswitch_netif_receive_skb;
350         pdev->netif_rx = mvswitch_netif_rx;
351         dev->hard_start_xmit = mvswitch_mangle_tx;
352         dev->vlan_rx_register = mvswitch_vlan_rx_register;
353 #ifdef HEADER_MODE
354         dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX;
355 #else
356         dev->features |= NETIF_F_HW_VLAN_RX;
357 #endif
358
359         return 0;
360 }
361
362 static int
363 mvswitch_read_status(struct phy_device *pdev)
364 {
365         pdev->speed = SPEED_100;
366         pdev->duplex = DUPLEX_FULL;
367         pdev->state = PHY_UP;
368
369         /* XXX ugly workaround: we can't force the switch
370          * to gracefully handle hosts moving from one port to another,
371          * so we have to regularly clear the ATU database */
372
373         /* wait for the ATU to become available */
374         mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0);
375
376         /* flush the ATU */
377         w16(pdev, MV_SWITCHREG(ATU_OP),
378                 MV_ATUOP_INPROGRESS |
379                 MV_ATUOP_FLUSH_ALL
380         );
381
382         /* wait for operation to complete */
383         mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0);
384
385         return 0;
386 }
387
388 static int
389 mvswitch_config_aneg(struct phy_device *phydev)
390 {
391         return 0;
392 }
393
394 static void
395 mvswitch_remove(struct phy_device *pdev)
396 {
397         struct mvswitch_priv *priv = to_mvsw(pdev);
398         struct net_device *dev = pdev->attached_dev;
399
400         /* restore old xmit handler */
401         if (priv->hardstart && dev)
402                 dev->hard_start_xmit = priv->hardstart;
403         dev->vlan_rx_register = NULL;
404         dev->vlan_rx_kill_vid = NULL;
405         dev->phy_ptr = NULL;
406         dev->features &= ~NETIF_F_HW_VLAN_RX;
407         kfree(priv);
408 }
409
410 static bool
411 mvswitch_detect(struct mii_bus *bus, int addr)
412 {
413         u16 reg;
414         int i;
415
416         /* we attach to phy id 31 to make sure that the late probe works */
417         if (addr != 31)
418                 return false;
419
420         /* look for the switch on the bus */
421         reg = bus->read(bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
422         if (reg != MV_IDENT_VALUE && reg != MV_IDENT_VALUE2)
423                 return false;
424
425         /*
426          * Now that we've established that the switch actually exists, let's
427          * get rid of the competition :)
428          */
429         for (i = 0; i < 31; i++) {
430                 if (!bus->phy_map[i])
431                         continue;
432
433                 device_unregister(&bus->phy_map[i]->dev);
434                 kfree(bus->phy_map[i]);
435                 bus->phy_map[i] = NULL;
436         }
437
438         return true;
439 }
440
441 static int
442 mvswitch_probe(struct phy_device *pdev)
443 {
444         struct mvswitch_priv *priv;
445
446         priv = kzalloc(sizeof(struct mvswitch_priv), GFP_KERNEL);
447         if (priv == NULL)
448                 return -ENOMEM;
449
450         pdev->priv = priv;
451
452         return 0;
453 }
454
455
456 static struct phy_driver mvswitch_driver = {
457         .name           = "Marvell 88E6060/88E6061",
458         .features       = PHY_BASIC_FEATURES,
459         .detect         = &mvswitch_detect,
460         .probe          = &mvswitch_probe,
461         .remove         = &mvswitch_remove,
462         .config_init    = &mvswitch_config_init,
463         .config_aneg    = &mvswitch_config_aneg,
464         .read_status    = &mvswitch_read_status,
465         .driver         = { .owner = THIS_MODULE,},
466 };
467
468 static int __init
469 mvswitch_init(void)
470 {
471         return phy_driver_register(&mvswitch_driver);
472 }
473
474 static void __exit
475 mvswitch_exit(void)
476 {
477         phy_driver_unregister(&mvswitch_driver);
478 }
479
480 module_init(mvswitch_init);
481 module_exit(mvswitch_exit);
Note: See TracBrowser for help on using the browser.