diff options
Diffstat (limited to 'net/dsa')
-rw-r--r-- | net/dsa/dsa.c | 177 | ||||
-rw-r--r-- | net/dsa/dsa_priv.h | 97 | ||||
-rw-r--r-- | net/dsa/mv88e6060.c | 12 | ||||
-rw-r--r-- | net/dsa/mv88e6123_61_65.c | 92 | ||||
-rw-r--r-- | net/dsa/mv88e6131.c | 78 | ||||
-rw-r--r-- | net/dsa/slave.c | 25 | ||||
-rw-r--r-- | net/dsa/tag_dsa.c | 30 | ||||
-rw-r--r-- | net/dsa/tag_edsa.c | 30 | ||||
-rw-r--r-- | net/dsa/tag_trailer.c | 10 |
9 files changed, 363 insertions, 188 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 33e99462023a..71489f69a42c 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * net/dsa/dsa.c - Hardware switch handling | 2 | * net/dsa/dsa.c - Hardware switch handling |
3 | * Copyright (c) 2008 Marvell Semiconductor | 3 | * Copyright (c) 2008-2009 Marvell Semiconductor |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -67,12 +67,13 @@ dsa_switch_probe(struct mii_bus *bus, int sw_addr, char **_name) | |||
67 | 67 | ||
68 | /* basic switch operations **************************************************/ | 68 | /* basic switch operations **************************************************/ |
69 | static struct dsa_switch * | 69 | static struct dsa_switch * |
70 | dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd, | 70 | dsa_switch_setup(struct dsa_switch_tree *dst, int index, |
71 | struct mii_bus *bus, struct net_device *dev) | 71 | struct device *parent, struct mii_bus *bus) |
72 | { | 72 | { |
73 | struct dsa_chip_data *pd = dst->pd->chip + index; | ||
74 | struct dsa_switch_driver *drv; | ||
73 | struct dsa_switch *ds; | 75 | struct dsa_switch *ds; |
74 | int ret; | 76 | int ret; |
75 | struct dsa_switch_driver *drv; | ||
76 | char *name; | 77 | char *name; |
77 | int i; | 78 | int i; |
78 | 79 | ||
@@ -81,11 +82,12 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd, | |||
81 | */ | 82 | */ |
82 | drv = dsa_switch_probe(bus, pd->sw_addr, &name); | 83 | drv = dsa_switch_probe(bus, pd->sw_addr, &name); |
83 | if (drv == NULL) { | 84 | if (drv == NULL) { |
84 | printk(KERN_ERR "%s: could not detect attached switch\n", | 85 | printk(KERN_ERR "%s[%d]: could not detect attached switch\n", |
85 | dev->name); | 86 | dst->master_netdev->name, index); |
86 | return ERR_PTR(-EINVAL); | 87 | return ERR_PTR(-EINVAL); |
87 | } | 88 | } |
88 | printk(KERN_INFO "%s: detected a %s switch\n", dev->name, name); | 89 | printk(KERN_INFO "%s[%d]: detected a %s switch\n", |
90 | dst->master_netdev->name, index, name); | ||
89 | 91 | ||
90 | 92 | ||
91 | /* | 93 | /* |
@@ -95,18 +97,16 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd, | |||
95 | if (ds == NULL) | 97 | if (ds == NULL) |
96 | return ERR_PTR(-ENOMEM); | 98 | return ERR_PTR(-ENOMEM); |
97 | 99 | ||
98 | ds->pd = pd; | 100 | ds->dst = dst; |
99 | ds->master_netdev = dev; | 101 | ds->index = index; |
100 | ds->master_mii_bus = bus; | 102 | ds->pd = dst->pd->chip + index; |
101 | |||
102 | ds->drv = drv; | 103 | ds->drv = drv; |
103 | ds->tag_protocol = drv->tag_protocol; | 104 | ds->master_mii_bus = bus; |
104 | 105 | ||
105 | 106 | ||
106 | /* | 107 | /* |
107 | * Validate supplied switch configuration. | 108 | * Validate supplied switch configuration. |
108 | */ | 109 | */ |
109 | ds->cpu_port = -1; | ||
110 | for (i = 0; i < DSA_MAX_PORTS; i++) { | 110 | for (i = 0; i < DSA_MAX_PORTS; i++) { |
111 | char *name; | 111 | char *name; |
112 | 112 | ||
@@ -115,32 +115,28 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd, | |||
115 | continue; | 115 | continue; |
116 | 116 | ||
117 | if (!strcmp(name, "cpu")) { | 117 | if (!strcmp(name, "cpu")) { |
118 | if (ds->cpu_port != -1) { | 118 | if (dst->cpu_switch != -1) { |
119 | printk(KERN_ERR "multiple cpu ports?!\n"); | 119 | printk(KERN_ERR "multiple cpu ports?!\n"); |
120 | ret = -EINVAL; | 120 | ret = -EINVAL; |
121 | goto out; | 121 | goto out; |
122 | } | 122 | } |
123 | ds->cpu_port = i; | 123 | dst->cpu_switch = index; |
124 | dst->cpu_port = i; | ||
125 | } else if (!strcmp(name, "dsa")) { | ||
126 | ds->dsa_port_mask |= 1 << i; | ||
124 | } else { | 127 | } else { |
125 | ds->valid_port_mask |= 1 << i; | 128 | ds->phys_port_mask |= 1 << i; |
126 | } | 129 | } |
127 | } | 130 | } |
128 | 131 | ||
129 | if (ds->cpu_port == -1) { | ||
130 | printk(KERN_ERR "no cpu port?!\n"); | ||
131 | ret = -EINVAL; | ||
132 | goto out; | ||
133 | } | ||
134 | |||
135 | 132 | ||
136 | /* | 133 | /* |
137 | * If we use a tagging format that doesn't have an ethertype | 134 | * If the CPU connects to this switch, set the switch tree |
138 | * field, make sure that all packets from this point on get | 135 | * tagging protocol to the preferred tagging format of this |
139 | * sent to the tag format's receive function. (Which will | 136 | * switch. |
140 | * discard received packets until we set ds->ports[] below.) | ||
141 | */ | 137 | */ |
142 | wmb(); | 138 | if (ds->dst->cpu_switch == index) |
143 | dev->dsa_ptr = (void *)ds; | 139 | ds->dst->tag_protocol = drv->tag_protocol; |
144 | 140 | ||
145 | 141 | ||
146 | /* | 142 | /* |
@@ -150,7 +146,7 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd, | |||
150 | if (ret < 0) | 146 | if (ret < 0) |
151 | goto out; | 147 | goto out; |
152 | 148 | ||
153 | ret = drv->set_addr(ds, dev->dev_addr); | 149 | ret = drv->set_addr(ds, dst->master_netdev->dev_addr); |
154 | if (ret < 0) | 150 | if (ret < 0) |
155 | goto out; | 151 | goto out; |
156 | 152 | ||
@@ -169,18 +165,18 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd, | |||
169 | /* | 165 | /* |
170 | * Create network devices for physical switch ports. | 166 | * Create network devices for physical switch ports. |
171 | */ | 167 | */ |
172 | wmb(); | ||
173 | for (i = 0; i < DSA_MAX_PORTS; i++) { | 168 | for (i = 0; i < DSA_MAX_PORTS; i++) { |
174 | struct net_device *slave_dev; | 169 | struct net_device *slave_dev; |
175 | 170 | ||
176 | if (!(ds->valid_port_mask & (1 << i))) | 171 | if (!(ds->phys_port_mask & (1 << i))) |
177 | continue; | 172 | continue; |
178 | 173 | ||
179 | slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]); | 174 | slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]); |
180 | if (slave_dev == NULL) { | 175 | if (slave_dev == NULL) { |
181 | printk(KERN_ERR "%s: can't create dsa slave " | 176 | printk(KERN_ERR "%s[%d]: can't create dsa " |
182 | "device for port %d(%s)\n", | 177 | "slave device for port %d(%s)\n", |
183 | dev->name, i, pd->port_names[i]); | 178 | dst->master_netdev->name, |
179 | index, i, pd->port_names[i]); | ||
184 | continue; | 180 | continue; |
185 | } | 181 | } |
186 | 182 | ||
@@ -192,7 +188,6 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd, | |||
192 | out_free: | 188 | out_free: |
193 | mdiobus_free(ds->slave_mii_bus); | 189 | mdiobus_free(ds->slave_mii_bus); |
194 | out: | 190 | out: |
195 | dev->dsa_ptr = NULL; | ||
196 | kfree(ds); | 191 | kfree(ds); |
197 | return ERR_PTR(ret); | 192 | return ERR_PTR(ret); |
198 | } | 193 | } |
@@ -212,35 +207,42 @@ static void dsa_switch_destroy(struct dsa_switch *ds) | |||
212 | */ | 207 | */ |
213 | bool dsa_uses_dsa_tags(void *dsa_ptr) | 208 | bool dsa_uses_dsa_tags(void *dsa_ptr) |
214 | { | 209 | { |
215 | struct dsa_switch *ds = dsa_ptr; | 210 | struct dsa_switch_tree *dst = dsa_ptr; |
216 | 211 | ||
217 | return !!(ds->tag_protocol == htons(ETH_P_DSA)); | 212 | return !!(dst->tag_protocol == htons(ETH_P_DSA)); |
218 | } | 213 | } |
219 | 214 | ||
220 | bool dsa_uses_trailer_tags(void *dsa_ptr) | 215 | bool dsa_uses_trailer_tags(void *dsa_ptr) |
221 | { | 216 | { |
222 | struct dsa_switch *ds = dsa_ptr; | 217 | struct dsa_switch_tree *dst = dsa_ptr; |
223 | 218 | ||
224 | return !!(ds->tag_protocol == htons(ETH_P_TRAILER)); | 219 | return !!(dst->tag_protocol == htons(ETH_P_TRAILER)); |
225 | } | 220 | } |
226 | 221 | ||
227 | 222 | ||
228 | /* link polling *************************************************************/ | 223 | /* link polling *************************************************************/ |
229 | static void dsa_link_poll_work(struct work_struct *ugly) | 224 | static void dsa_link_poll_work(struct work_struct *ugly) |
230 | { | 225 | { |
231 | struct dsa_switch *ds; | 226 | struct dsa_switch_tree *dst; |
227 | int i; | ||
228 | |||
229 | dst = container_of(ugly, struct dsa_switch_tree, link_poll_work); | ||
232 | 230 | ||
233 | ds = container_of(ugly, struct dsa_switch, link_poll_work); | 231 | for (i = 0; i < dst->pd->nr_chips; i++) { |
232 | struct dsa_switch *ds = dst->ds[i]; | ||
234 | 233 | ||
235 | ds->drv->poll_link(ds); | 234 | if (ds != NULL && ds->drv->poll_link != NULL) |
236 | mod_timer(&ds->link_poll_timer, round_jiffies(jiffies + HZ)); | 235 | ds->drv->poll_link(ds); |
236 | } | ||
237 | |||
238 | mod_timer(&dst->link_poll_timer, round_jiffies(jiffies + HZ)); | ||
237 | } | 239 | } |
238 | 240 | ||
239 | static void dsa_link_poll_timer(unsigned long _ds) | 241 | static void dsa_link_poll_timer(unsigned long _dst) |
240 | { | 242 | { |
241 | struct dsa_switch *ds = (void *)_ds; | 243 | struct dsa_switch_tree *dst = (void *)_dst; |
242 | 244 | ||
243 | schedule_work(&ds->link_poll_work); | 245 | schedule_work(&dst->link_poll_work); |
244 | } | 246 | } |
245 | 247 | ||
246 | 248 | ||
@@ -303,18 +305,14 @@ static int dsa_probe(struct platform_device *pdev) | |||
303 | static int dsa_version_printed; | 305 | static int dsa_version_printed; |
304 | struct dsa_platform_data *pd = pdev->dev.platform_data; | 306 | struct dsa_platform_data *pd = pdev->dev.platform_data; |
305 | struct net_device *dev; | 307 | struct net_device *dev; |
306 | struct mii_bus *bus; | 308 | struct dsa_switch_tree *dst; |
307 | struct dsa_switch *ds; | 309 | int i; |
308 | 310 | ||
309 | if (!dsa_version_printed++) | 311 | if (!dsa_version_printed++) |
310 | printk(KERN_NOTICE "Distributed Switch Architecture " | 312 | printk(KERN_NOTICE "Distributed Switch Architecture " |
311 | "driver version %s\n", dsa_driver_version); | 313 | "driver version %s\n", dsa_driver_version); |
312 | 314 | ||
313 | if (pd == NULL || pd->mii_bus == NULL || pd->netdev == NULL) | 315 | if (pd == NULL || pd->netdev == NULL) |
314 | return -EINVAL; | ||
315 | |||
316 | bus = dev_to_mii_bus(pd->mii_bus); | ||
317 | if (bus == NULL) | ||
318 | return -EINVAL; | 316 | return -EINVAL; |
319 | 317 | ||
320 | dev = dev_to_net_device(pd->netdev); | 318 | dev = dev_to_net_device(pd->netdev); |
@@ -326,36 +324,79 @@ static int dsa_probe(struct platform_device *pdev) | |||
326 | return -EEXIST; | 324 | return -EEXIST; |
327 | } | 325 | } |
328 | 326 | ||
329 | ds = dsa_switch_setup(&pdev->dev, pd, bus, dev); | 327 | dst = kzalloc(sizeof(*dst), GFP_KERNEL); |
330 | if (IS_ERR(ds)) { | 328 | if (dst == NULL) { |
331 | dev_put(dev); | 329 | dev_put(dev); |
332 | return PTR_ERR(ds); | 330 | return -ENOMEM; |
333 | } | 331 | } |
334 | 332 | ||
335 | if (ds->drv->poll_link != NULL) { | 333 | platform_set_drvdata(pdev, dst); |
336 | INIT_WORK(&ds->link_poll_work, dsa_link_poll_work); | 334 | |
337 | init_timer(&ds->link_poll_timer); | 335 | dst->pd = pd; |
338 | ds->link_poll_timer.data = (unsigned long)ds; | 336 | dst->master_netdev = dev; |
339 | ds->link_poll_timer.function = dsa_link_poll_timer; | 337 | dst->cpu_switch = -1; |
340 | ds->link_poll_timer.expires = round_jiffies(jiffies + HZ); | 338 | dst->cpu_port = -1; |
341 | add_timer(&ds->link_poll_timer); | 339 | |
340 | for (i = 0; i < pd->nr_chips; i++) { | ||
341 | struct mii_bus *bus; | ||
342 | struct dsa_switch *ds; | ||
343 | |||
344 | bus = dev_to_mii_bus(pd->chip[i].mii_bus); | ||
345 | if (bus == NULL) { | ||
346 | printk(KERN_ERR "%s[%d]: no mii bus found for " | ||
347 | "dsa switch\n", dev->name, i); | ||
348 | continue; | ||
349 | } | ||
350 | |||
351 | ds = dsa_switch_setup(dst, i, &pdev->dev, bus); | ||
352 | if (IS_ERR(ds)) { | ||
353 | printk(KERN_ERR "%s[%d]: couldn't create dsa switch " | ||
354 | "instance (error %ld)\n", dev->name, i, | ||
355 | PTR_ERR(ds)); | ||
356 | continue; | ||
357 | } | ||
358 | |||
359 | dst->ds[i] = ds; | ||
360 | if (ds->drv->poll_link != NULL) | ||
361 | dst->link_poll_needed = 1; | ||
342 | } | 362 | } |
343 | 363 | ||
344 | platform_set_drvdata(pdev, ds); | 364 | /* |
365 | * If we use a tagging format that doesn't have an ethertype | ||
366 | * field, make sure that all packets from this point on get | ||
367 | * sent to the tag format's receive function. | ||
368 | */ | ||
369 | wmb(); | ||
370 | dev->dsa_ptr = (void *)dst; | ||
371 | |||
372 | if (dst->link_poll_needed) { | ||
373 | INIT_WORK(&dst->link_poll_work, dsa_link_poll_work); | ||
374 | init_timer(&dst->link_poll_timer); | ||
375 | dst->link_poll_timer.data = (unsigned long)dst; | ||
376 | dst->link_poll_timer.function = dsa_link_poll_timer; | ||
377 | dst->link_poll_timer.expires = round_jiffies(jiffies + HZ); | ||
378 | add_timer(&dst->link_poll_timer); | ||
379 | } | ||
345 | 380 | ||
346 | return 0; | 381 | return 0; |
347 | } | 382 | } |
348 | 383 | ||
349 | static int dsa_remove(struct platform_device *pdev) | 384 | static int dsa_remove(struct platform_device *pdev) |
350 | { | 385 | { |
351 | struct dsa_switch *ds = platform_get_drvdata(pdev); | 386 | struct dsa_switch_tree *dst = platform_get_drvdata(pdev); |
387 | int i; | ||
352 | 388 | ||
353 | if (ds->drv->poll_link != NULL) | 389 | if (dst->link_poll_needed) |
354 | del_timer_sync(&ds->link_poll_timer); | 390 | del_timer_sync(&dst->link_poll_timer); |
355 | 391 | ||
356 | flush_scheduled_work(); | 392 | flush_scheduled_work(); |
357 | 393 | ||
358 | dsa_switch_destroy(ds); | 394 | for (i = 0; i < dst->pd->nr_chips; i++) { |
395 | struct dsa_switch *ds = dst->ds[i]; | ||
396 | |||
397 | if (ds != NULL) | ||
398 | dsa_switch_destroy(ds); | ||
399 | } | ||
359 | 400 | ||
360 | return 0; | 401 | return 0; |
361 | } | 402 | } |
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 7063378a1ebf..41055f33d28a 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * net/dsa/dsa_priv.h - Hardware switch handling | 2 | * net/dsa/dsa_priv.h - Hardware switch handling |
3 | * Copyright (c) 2008 Marvell Semiconductor | 3 | * Copyright (c) 2008-2009 Marvell Semiconductor |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -19,42 +19,107 @@ | |||
19 | 19 | ||
20 | struct dsa_switch { | 20 | struct dsa_switch { |
21 | /* | 21 | /* |
22 | * Configuration data for the platform device that owns | 22 | * Parent switch tree, and switch index. |
23 | * this dsa switch instance. | ||
24 | */ | 23 | */ |
25 | struct dsa_platform_data *pd; | 24 | struct dsa_switch_tree *dst; |
25 | int index; | ||
26 | 26 | ||
27 | /* | 27 | /* |
28 | * References to network device and mii bus to use. | 28 | * Configuration data for this switch. |
29 | */ | 29 | */ |
30 | struct net_device *master_netdev; | 30 | struct dsa_chip_data *pd; |
31 | struct mii_bus *master_mii_bus; | ||
32 | 31 | ||
33 | /* | 32 | /* |
34 | * The used switch driver and frame tagging type. | 33 | * The used switch driver. |
35 | */ | 34 | */ |
36 | struct dsa_switch_driver *drv; | 35 | struct dsa_switch_driver *drv; |
37 | __be16 tag_protocol; | 36 | |
37 | /* | ||
38 | * Reference to mii bus to use. | ||
39 | */ | ||
40 | struct mii_bus *master_mii_bus; | ||
38 | 41 | ||
39 | /* | 42 | /* |
40 | * Slave mii_bus and devices for the individual ports. | 43 | * Slave mii_bus and devices for the individual ports. |
41 | */ | 44 | */ |
42 | int cpu_port; | 45 | u32 dsa_port_mask; |
43 | u32 valid_port_mask; | 46 | u32 phys_port_mask; |
44 | struct mii_bus *slave_mii_bus; | 47 | struct mii_bus *slave_mii_bus; |
45 | struct net_device *ports[DSA_MAX_PORTS]; | 48 | struct net_device *ports[DSA_MAX_PORTS]; |
49 | }; | ||
50 | |||
51 | struct dsa_switch_tree { | ||
52 | /* | ||
53 | * Configuration data for the platform device that owns | ||
54 | * this dsa switch tree instance. | ||
55 | */ | ||
56 | struct dsa_platform_data *pd; | ||
57 | |||
58 | /* | ||
59 | * Reference to network device to use, and which tagging | ||
60 | * protocol to use. | ||
61 | */ | ||
62 | struct net_device *master_netdev; | ||
63 | __be16 tag_protocol; | ||
64 | |||
65 | /* | ||
66 | * The switch and port to which the CPU is attached. | ||
67 | */ | ||
68 | s8 cpu_switch; | ||
69 | s8 cpu_port; | ||
46 | 70 | ||
47 | /* | 71 | /* |
48 | * Link state polling. | 72 | * Link state polling. |
49 | */ | 73 | */ |
50 | struct work_struct link_poll_work; | 74 | int link_poll_needed; |
51 | struct timer_list link_poll_timer; | 75 | struct work_struct link_poll_work; |
76 | struct timer_list link_poll_timer; | ||
77 | |||
78 | /* | ||
79 | * Data for the individual switch chips. | ||
80 | */ | ||
81 | struct dsa_switch *ds[DSA_MAX_SWITCHES]; | ||
52 | }; | 82 | }; |
53 | 83 | ||
84 | static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p) | ||
85 | { | ||
86 | return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port); | ||
87 | } | ||
88 | |||
89 | static inline u8 dsa_upstream_port(struct dsa_switch *ds) | ||
90 | { | ||
91 | struct dsa_switch_tree *dst = ds->dst; | ||
92 | |||
93 | /* | ||
94 | * If this is the root switch (i.e. the switch that connects | ||
95 | * to the CPU), return the cpu port number on this switch. | ||
96 | * Else return the (DSA) port number that connects to the | ||
97 | * switch that is one hop closer to the cpu. | ||
98 | */ | ||
99 | if (dst->cpu_switch == ds->index) | ||
100 | return dst->cpu_port; | ||
101 | else | ||
102 | return ds->pd->rtable[dst->cpu_switch]; | ||
103 | } | ||
104 | |||
54 | struct dsa_slave_priv { | 105 | struct dsa_slave_priv { |
106 | /* | ||
107 | * The linux network interface corresponding to this | ||
108 | * switch port. | ||
109 | */ | ||
55 | struct net_device *dev; | 110 | struct net_device *dev; |
111 | |||
112 | /* | ||
113 | * Which switch this port is a part of, and the port index | ||
114 | * for this port. | ||
115 | */ | ||
56 | struct dsa_switch *parent; | 116 | struct dsa_switch *parent; |
57 | int port; | 117 | u8 port; |
118 | |||
119 | /* | ||
120 | * The phylib phy_device pointer for the PHY connected | ||
121 | * to this port. | ||
122 | */ | ||
58 | struct phy_device *phy; | 123 | struct phy_device *phy; |
59 | }; | 124 | }; |
60 | 125 | ||
diff --git a/net/dsa/mv88e6060.c b/net/dsa/mv88e6060.c index 85081ae9fe89..83277f463af7 100644 --- a/net/dsa/mv88e6060.c +++ b/net/dsa/mv88e6060.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips | 2 | * net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips |
3 | * Copyright (c) 2008 Marvell Semiconductor | 3 | * Copyright (c) 2008-2009 Marvell Semiconductor |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -81,7 +81,7 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds) | |||
81 | /* | 81 | /* |
82 | * Reset the switch. | 82 | * Reset the switch. |
83 | */ | 83 | */ |
84 | REG_WRITE(REG_GLOBAL, 0x0A, 0xa130); | 84 | REG_WRITE(REG_GLOBAL, 0x0a, 0xa130); |
85 | 85 | ||
86 | /* | 86 | /* |
87 | * Wait up to one second for reset to complete. | 87 | * Wait up to one second for reset to complete. |
@@ -128,7 +128,7 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p) | |||
128 | * state to Forwarding. Additionally, if this is the CPU | 128 | * state to Forwarding. Additionally, if this is the CPU |
129 | * port, enable Ingress and Egress Trailer tagging mode. | 129 | * port, enable Ingress and Egress Trailer tagging mode. |
130 | */ | 130 | */ |
131 | REG_WRITE(addr, 0x04, (p == ds->cpu_port) ? 0x4103 : 0x0003); | 131 | REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ? 0x4103 : 0x0003); |
132 | 132 | ||
133 | /* | 133 | /* |
134 | * Port based VLAN map: give each port its own address | 134 | * Port based VLAN map: give each port its own address |
@@ -138,9 +138,9 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p) | |||
138 | */ | 138 | */ |
139 | REG_WRITE(addr, 0x06, | 139 | REG_WRITE(addr, 0x06, |
140 | ((p & 0xf) << 12) | | 140 | ((p & 0xf) << 12) | |
141 | ((p == ds->cpu_port) ? | 141 | (dsa_is_cpu_port(ds, p) ? |
142 | ds->valid_port_mask : | 142 | ds->phys_port_mask : |
143 | (1 << ds->cpu_port))); | 143 | (1 << ds->dst->cpu_port))); |
144 | 144 | ||
145 | /* | 145 | /* |
146 | * Port Association Vector: when learning source addresses | 146 | * Port Association Vector: when learning source addresses |
diff --git a/net/dsa/mv88e6123_61_65.c b/net/dsa/mv88e6123_61_65.c index 100318722214..52faaa21a4d9 100644 --- a/net/dsa/mv88e6123_61_65.c +++ b/net/dsa/mv88e6123_61_65.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * net/dsa/mv88e6123_61_65.c - Marvell 88e6123/6161/6165 switch chip support | 2 | * net/dsa/mv88e6123_61_65.c - Marvell 88e6123/6161/6165 switch chip support |
3 | * Copyright (c) 2008 Marvell Semiconductor | 3 | * Copyright (c) 2008-2009 Marvell Semiconductor |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -98,17 +98,17 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds) | |||
98 | return ret; | 98 | return ret; |
99 | 99 | ||
100 | /* | 100 | /* |
101 | * Configure the cpu port, and configure the cpu port as the | 101 | * Configure the upstream port, and configure the upstream |
102 | * port to which ingress and egress monitor frames are to be | 102 | * port as the port to which ingress and egress monitor frames |
103 | * sent. | 103 | * are to be sent. |
104 | */ | 104 | */ |
105 | REG_WRITE(REG_GLOBAL, 0x1a, (ds->cpu_port * 0x1110)); | 105 | REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110)); |
106 | 106 | ||
107 | /* | 107 | /* |
108 | * Disable remote management for now, and set the switch's | 108 | * Disable remote management for now, and set the switch's |
109 | * DSA device number to zero. | 109 | * DSA device number. |
110 | */ | 110 | */ |
111 | REG_WRITE(REG_GLOBAL, 0x1c, 0x0000); | 111 | REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f); |
112 | 112 | ||
113 | /* | 113 | /* |
114 | * Send all frames with destination addresses matching | 114 | * Send all frames with destination addresses matching |
@@ -133,10 +133,17 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds) | |||
133 | REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff); | 133 | REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff); |
134 | 134 | ||
135 | /* | 135 | /* |
136 | * Map all DSA device IDs to the CPU port. | 136 | * Program the DSA routing table. |
137 | */ | 137 | */ |
138 | for (i = 0; i < 32; i++) | 138 | for (i = 0; i < 32; i++) { |
139 | REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | ds->cpu_port); | 139 | int nexthop; |
140 | |||
141 | nexthop = 0x1f; | ||
142 | if (i != ds->index && i < ds->dst->pd->nr_chips) | ||
143 | nexthop = ds->pd->rtable[i] & 0x1f; | ||
144 | |||
145 | REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop); | ||
146 | } | ||
140 | 147 | ||
141 | /* | 148 | /* |
142 | * Clear all trunk masks. | 149 | * Clear all trunk masks. |
@@ -176,12 +183,18 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds) | |||
176 | static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p) | 183 | static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p) |
177 | { | 184 | { |
178 | int addr = REG_PORT(p); | 185 | int addr = REG_PORT(p); |
186 | u16 val; | ||
179 | 187 | ||
180 | /* | 188 | /* |
181 | * MAC Forcing register: don't force link, speed, duplex | 189 | * MAC Forcing register: don't force link, speed, duplex |
182 | * or flow control state to any particular values. | 190 | * or flow control state to any particular values on physical |
191 | * ports, but force the CPU port and all DSA ports to 1000 Mb/s | ||
192 | * full duplex. | ||
183 | */ | 193 | */ |
184 | REG_WRITE(addr, 0x01, 0x0003); | 194 | if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p)) |
195 | REG_WRITE(addr, 0x01, 0x003e); | ||
196 | else | ||
197 | REG_WRITE(addr, 0x01, 0x0003); | ||
185 | 198 | ||
186 | /* | 199 | /* |
187 | * Do not limit the period of time that this port can be | 200 | * Do not limit the period of time that this port can be |
@@ -192,37 +205,50 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p) | |||
192 | 205 | ||
193 | /* | 206 | /* |
194 | * Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, | 207 | * Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, |
195 | * configure the requested (DSA/EDSA) tagging mode if this is | 208 | * disable Header mode, enable IGMP/MLD snooping, disable VLAN |
196 | * the CPU port, disable Header mode, enable IGMP/MLD snooping, | 209 | * tunneling, determine priority by looking at 802.1p and IP |
197 | * disable VLAN tunneling, determine priority by looking at | 210 | * priority fields (IP prio has precedence), and set STP state |
198 | * 802.1p and IP priority fields (IP prio has precedence), and | 211 | * to Forwarding. |
199 | * set STP state to Forwarding. Finally, if this is the CPU | 212 | * |
200 | * port, additionally enable forwarding of unknown unicast and | 213 | * If this is the CPU link, use DSA or EDSA tagging depending |
201 | * multicast addresses. | 214 | * on which tagging mode was configured. |
202 | */ | 215 | * |
203 | REG_WRITE(addr, 0x04, | 216 | * If this is a link to another switch, use DSA tagging mode. |
204 | (p == ds->cpu_port) ? | 217 | * |
205 | (ds->tag_protocol == htons(ETH_P_DSA)) ? | 218 | * If this is the upstream port for this switch, enable |
206 | 0x053f : 0x373f : | 219 | * forwarding of unknown unicasts and multicasts. |
207 | 0x0433); | 220 | */ |
221 | val = 0x0433; | ||
222 | if (dsa_is_cpu_port(ds, p)) { | ||
223 | if (ds->dst->tag_protocol == htons(ETH_P_EDSA)) | ||
224 | val |= 0x3300; | ||
225 | else | ||
226 | val |= 0x0100; | ||
227 | } | ||
228 | if (ds->dsa_port_mask & (1 << p)) | ||
229 | val |= 0x0100; | ||
230 | if (p == dsa_upstream_port(ds)) | ||
231 | val |= 0x000c; | ||
232 | REG_WRITE(addr, 0x04, val); | ||
208 | 233 | ||
209 | /* | 234 | /* |
210 | * Port Control 1: disable trunking. Also, if this is the | 235 | * Port Control 1: disable trunking. Also, if this is the |
211 | * CPU port, enable learn messages to be sent to this port. | 236 | * CPU port, enable learn messages to be sent to this port. |
212 | */ | 237 | */ |
213 | REG_WRITE(addr, 0x05, (p == ds->cpu_port) ? 0x8000 : 0x0000); | 238 | REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000); |
214 | 239 | ||
215 | /* | 240 | /* |
216 | * Port based VLAN map: give each port its own address | 241 | * Port based VLAN map: give each port its own address |
217 | * database, allow the CPU port to talk to each of the 'real' | 242 | * database, allow the CPU port to talk to each of the 'real' |
218 | * ports, and allow each of the 'real' ports to only talk to | 243 | * ports, and allow each of the 'real' ports to only talk to |
219 | * the CPU port. | 244 | * the upstream port. |
220 | */ | 245 | */ |
221 | REG_WRITE(addr, 0x06, | 246 | val = (p & 0xf) << 12; |
222 | ((p & 0xf) << 12) | | 247 | if (dsa_is_cpu_port(ds, p)) |
223 | ((p == ds->cpu_port) ? | 248 | val |= ds->phys_port_mask; |
224 | ds->valid_port_mask : | 249 | else |
225 | (1 << ds->cpu_port))); | 250 | val |= 1 << dsa_upstream_port(ds); |
251 | REG_WRITE(addr, 0x06, val); | ||
226 | 252 | ||
227 | /* | 253 | /* |
228 | * Default VLAN ID and priority: don't set a default VLAN | 254 | * Default VLAN ID and priority: don't set a default VLAN |
diff --git a/net/dsa/mv88e6131.c b/net/dsa/mv88e6131.c index 002995721ecf..bb2b41bc854e 100644 --- a/net/dsa/mv88e6131.c +++ b/net/dsa/mv88e6131.c | |||
@@ -102,17 +102,17 @@ static int mv88e6131_setup_global(struct dsa_switch *ds) | |||
102 | REG_WRITE(REG_GLOBAL, 0x19, 0x8100); | 102 | REG_WRITE(REG_GLOBAL, 0x19, 0x8100); |
103 | 103 | ||
104 | /* | 104 | /* |
105 | * Disable ARP mirroring, and configure the cpu port as the | 105 | * Disable ARP mirroring, and configure the upstream port as |
106 | * port to which ingress and egress monitor frames are to be | 106 | * the port to which ingress and egress monitor frames are to |
107 | * sent. | 107 | * be sent. |
108 | */ | 108 | */ |
109 | REG_WRITE(REG_GLOBAL, 0x1a, (ds->cpu_port * 0x1100) | 0x00f0); | 109 | REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1100) | 0x00f0); |
110 | 110 | ||
111 | /* | 111 | /* |
112 | * Disable cascade port functionality, and set the switch's | 112 | * Disable cascade port functionality, and set the switch's |
113 | * DSA device number to zero. | 113 | * DSA device number. |
114 | */ | 114 | */ |
115 | REG_WRITE(REG_GLOBAL, 0x1c, 0xe000); | 115 | REG_WRITE(REG_GLOBAL, 0x1c, 0xe000 | (ds->index & 0x1f)); |
116 | 116 | ||
117 | /* | 117 | /* |
118 | * Send all frames with destination addresses matching | 118 | * Send all frames with destination addresses matching |
@@ -129,10 +129,17 @@ static int mv88e6131_setup_global(struct dsa_switch *ds) | |||
129 | REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff); | 129 | REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff); |
130 | 130 | ||
131 | /* | 131 | /* |
132 | * Map all DSA device IDs to the CPU port. | 132 | * Program the DSA routing table. |
133 | */ | 133 | */ |
134 | for (i = 0; i < 32; i++) | 134 | for (i = 0; i < 32; i++) { |
135 | REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | ds->cpu_port); | 135 | int nexthop; |
136 | |||
137 | nexthop = 0x1f; | ||
138 | if (i != ds->index && i < ds->dst->pd->nr_chips) | ||
139 | nexthop = ds->pd->rtable[i] & 0x1f; | ||
140 | |||
141 | REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop); | ||
142 | } | ||
136 | 143 | ||
137 | /* | 144 | /* |
138 | * Clear all trunk masks. | 145 | * Clear all trunk masks. |
@@ -158,13 +165,15 @@ static int mv88e6131_setup_global(struct dsa_switch *ds) | |||
158 | static int mv88e6131_setup_port(struct dsa_switch *ds, int p) | 165 | static int mv88e6131_setup_port(struct dsa_switch *ds, int p) |
159 | { | 166 | { |
160 | int addr = REG_PORT(p); | 167 | int addr = REG_PORT(p); |
168 | u16 val; | ||
161 | 169 | ||
162 | /* | 170 | /* |
163 | * MAC Forcing register: don't force link, speed, duplex | 171 | * MAC Forcing register: don't force link, speed, duplex |
164 | * or flow control state to any particular values on physical | 172 | * or flow control state to any particular values on physical |
165 | * ports, but force the CPU port to 1000 Mb/s full duplex. | 173 | * ports, but force the CPU port and all DSA ports to 1000 Mb/s |
174 | * full duplex. | ||
166 | */ | 175 | */ |
167 | if (p == ds->cpu_port) | 176 | if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p)) |
168 | REG_WRITE(addr, 0x01, 0x003e); | 177 | REG_WRITE(addr, 0x01, 0x003e); |
169 | else | 178 | else |
170 | REG_WRITE(addr, 0x01, 0x0003); | 179 | REG_WRITE(addr, 0x01, 0x0003); |
@@ -175,29 +184,40 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) | |||
175 | * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN | 184 | * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN |
176 | * tunneling, determine priority by looking at 802.1p and | 185 | * tunneling, determine priority by looking at 802.1p and |
177 | * IP priority fields (IP prio has precedence), and set STP | 186 | * IP priority fields (IP prio has precedence), and set STP |
178 | * state to Forwarding. Finally, if this is the CPU port, | 187 | * state to Forwarding. |
179 | * additionally enable DSA tagging and forwarding of unknown | 188 | * |
180 | * unicast addresses. | 189 | * If this is the upstream port for this switch, enable |
190 | * forwarding of unknown unicasts, and enable DSA tagging | ||
191 | * mode. | ||
192 | * | ||
193 | * If this is the link to another switch, use DSA tagging | ||
194 | * mode, but do not enable forwarding of unknown unicasts. | ||
181 | */ | 195 | */ |
182 | REG_WRITE(addr, 0x04, (p == ds->cpu_port) ? 0x0537 : 0x0433); | 196 | val = 0x0433; |
197 | if (p == dsa_upstream_port(ds)) | ||
198 | val |= 0x0104; | ||
199 | if (ds->dsa_port_mask & (1 << p)) | ||
200 | val |= 0x0100; | ||
201 | REG_WRITE(addr, 0x04, val); | ||
183 | 202 | ||
184 | /* | 203 | /* |
185 | * Port Control 1: disable trunking. Also, if this is the | 204 | * Port Control 1: disable trunking. Also, if this is the |
186 | * CPU port, enable learn messages to be sent to this port. | 205 | * CPU port, enable learn messages to be sent to this port. |
187 | */ | 206 | */ |
188 | REG_WRITE(addr, 0x05, (p == ds->cpu_port) ? 0x8000 : 0x0000); | 207 | REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000); |
189 | 208 | ||
190 | /* | 209 | /* |
191 | * Port based VLAN map: give each port its own address | 210 | * Port based VLAN map: give each port its own address |
192 | * database, allow the CPU port to talk to each of the 'real' | 211 | * database, allow the CPU port to talk to each of the 'real' |
193 | * ports, and allow each of the 'real' ports to only talk to | 212 | * ports, and allow each of the 'real' ports to only talk to |
194 | * the CPU port. | 213 | * the upstream port. |
195 | */ | 214 | */ |
196 | REG_WRITE(addr, 0x06, | 215 | val = (p & 0xf) << 12; |
197 | ((p & 0xf) << 12) | | 216 | if (dsa_is_cpu_port(ds, p)) |
198 | ((p == ds->cpu_port) ? | 217 | val |= ds->phys_port_mask; |
199 | ds->valid_port_mask : | 218 | else |
200 | (1 << ds->cpu_port))); | 219 | val |= 1 << dsa_upstream_port(ds); |
220 | REG_WRITE(addr, 0x06, val); | ||
201 | 221 | ||
202 | /* | 222 | /* |
203 | * Default VLAN ID and priority: don't set a default VLAN | 223 | * Default VLAN ID and priority: don't set a default VLAN |
@@ -213,13 +233,15 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) | |||
213 | * untagged frames on this port, do a destination address | 233 | * untagged frames on this port, do a destination address |
214 | * lookup on received packets as usual, don't send a copy | 234 | * lookup on received packets as usual, don't send a copy |
215 | * of all transmitted/received frames on this port to the | 235 | * of all transmitted/received frames on this port to the |
216 | * CPU, and configure the CPU port number. Also, if this | 236 | * CPU, and configure the upstream port number. |
217 | * is the CPU port, enable forwarding of unknown multicast | 237 | * |
218 | * addresses. | 238 | * If this is the upstream port for this switch, enable |
239 | * forwarding of unknown multicast addresses. | ||
219 | */ | 240 | */ |
220 | REG_WRITE(addr, 0x08, | 241 | val = 0x0080 | dsa_upstream_port(ds); |
221 | ((p == ds->cpu_port) ? 0x00c0 : 0x0080) | | 242 | if (p == dsa_upstream_port(ds)) |
222 | ds->cpu_port); | 243 | val |= 0x0040; |
244 | REG_WRITE(addr, 0x08, val); | ||
223 | 245 | ||
224 | /* | 246 | /* |
225 | * Rate Control: disable ingress rate limiting. | 247 | * Rate Control: disable ingress rate limiting. |
diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 99114e5b32e4..ed131181215d 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * net/dsa/slave.c - Slave device handling | 2 | * net/dsa/slave.c - Slave device handling |
3 | * Copyright (c) 2008 Marvell Semiconductor | 3 | * Copyright (c) 2008-2009 Marvell Semiconductor |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -19,7 +19,7 @@ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) | |||
19 | { | 19 | { |
20 | struct dsa_switch *ds = bus->priv; | 20 | struct dsa_switch *ds = bus->priv; |
21 | 21 | ||
22 | if (ds->valid_port_mask & (1 << addr)) | 22 | if (ds->phys_port_mask & (1 << addr)) |
23 | return ds->drv->phy_read(ds, addr, reg); | 23 | return ds->drv->phy_read(ds, addr, reg); |
24 | 24 | ||
25 | return 0xffff; | 25 | return 0xffff; |
@@ -29,7 +29,7 @@ static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val) | |||
29 | { | 29 | { |
30 | struct dsa_switch *ds = bus->priv; | 30 | struct dsa_switch *ds = bus->priv; |
31 | 31 | ||
32 | if (ds->valid_port_mask & (1 << addr)) | 32 | if (ds->phys_port_mask & (1 << addr)) |
33 | return ds->drv->phy_write(ds, addr, reg, val); | 33 | return ds->drv->phy_write(ds, addr, reg, val); |
34 | 34 | ||
35 | return 0; | 35 | return 0; |
@@ -43,7 +43,7 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds) | |||
43 | ds->slave_mii_bus->write = dsa_slave_phy_write; | 43 | ds->slave_mii_bus->write = dsa_slave_phy_write; |
44 | snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s:%.2x", | 44 | snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s:%.2x", |
45 | ds->master_mii_bus->id, ds->pd->sw_addr); | 45 | ds->master_mii_bus->id, ds->pd->sw_addr); |
46 | ds->slave_mii_bus->parent = &(ds->master_mii_bus->dev); | 46 | ds->slave_mii_bus->parent = &ds->master_mii_bus->dev; |
47 | } | 47 | } |
48 | 48 | ||
49 | 49 | ||
@@ -51,9 +51,8 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds) | |||
51 | static int dsa_slave_init(struct net_device *dev) | 51 | static int dsa_slave_init(struct net_device *dev) |
52 | { | 52 | { |
53 | struct dsa_slave_priv *p = netdev_priv(dev); | 53 | struct dsa_slave_priv *p = netdev_priv(dev); |
54 | struct net_device *master = p->parent->master_netdev; | ||
55 | 54 | ||
56 | dev->iflink = master->ifindex; | 55 | dev->iflink = p->parent->dst->master_netdev->ifindex; |
57 | 56 | ||
58 | return 0; | 57 | return 0; |
59 | } | 58 | } |
@@ -61,7 +60,7 @@ static int dsa_slave_init(struct net_device *dev) | |||
61 | static int dsa_slave_open(struct net_device *dev) | 60 | static int dsa_slave_open(struct net_device *dev) |
62 | { | 61 | { |
63 | struct dsa_slave_priv *p = netdev_priv(dev); | 62 | struct dsa_slave_priv *p = netdev_priv(dev); |
64 | struct net_device *master = p->parent->master_netdev; | 63 | struct net_device *master = p->parent->dst->master_netdev; |
65 | int err; | 64 | int err; |
66 | 65 | ||
67 | if (!(master->flags & IFF_UP)) | 66 | if (!(master->flags & IFF_UP)) |
@@ -99,7 +98,7 @@ out: | |||
99 | static int dsa_slave_close(struct net_device *dev) | 98 | static int dsa_slave_close(struct net_device *dev) |
100 | { | 99 | { |
101 | struct dsa_slave_priv *p = netdev_priv(dev); | 100 | struct dsa_slave_priv *p = netdev_priv(dev); |
102 | struct net_device *master = p->parent->master_netdev; | 101 | struct net_device *master = p->parent->dst->master_netdev; |
103 | 102 | ||
104 | dev_mc_unsync(master, dev); | 103 | dev_mc_unsync(master, dev); |
105 | dev_unicast_unsync(master, dev); | 104 | dev_unicast_unsync(master, dev); |
@@ -117,7 +116,7 @@ static int dsa_slave_close(struct net_device *dev) | |||
117 | static void dsa_slave_change_rx_flags(struct net_device *dev, int change) | 116 | static void dsa_slave_change_rx_flags(struct net_device *dev, int change) |
118 | { | 117 | { |
119 | struct dsa_slave_priv *p = netdev_priv(dev); | 118 | struct dsa_slave_priv *p = netdev_priv(dev); |
120 | struct net_device *master = p->parent->master_netdev; | 119 | struct net_device *master = p->parent->dst->master_netdev; |
121 | 120 | ||
122 | if (change & IFF_ALLMULTI) | 121 | if (change & IFF_ALLMULTI) |
123 | dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1); | 122 | dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1); |
@@ -128,7 +127,7 @@ static void dsa_slave_change_rx_flags(struct net_device *dev, int change) | |||
128 | static void dsa_slave_set_rx_mode(struct net_device *dev) | 127 | static void dsa_slave_set_rx_mode(struct net_device *dev) |
129 | { | 128 | { |
130 | struct dsa_slave_priv *p = netdev_priv(dev); | 129 | struct dsa_slave_priv *p = netdev_priv(dev); |
131 | struct net_device *master = p->parent->master_netdev; | 130 | struct net_device *master = p->parent->dst->master_netdev; |
132 | 131 | ||
133 | dev_mc_sync(master, dev); | 132 | dev_mc_sync(master, dev); |
134 | dev_unicast_sync(master, dev); | 133 | dev_unicast_sync(master, dev); |
@@ -137,7 +136,7 @@ static void dsa_slave_set_rx_mode(struct net_device *dev) | |||
137 | static int dsa_slave_set_mac_address(struct net_device *dev, void *a) | 136 | static int dsa_slave_set_mac_address(struct net_device *dev, void *a) |
138 | { | 137 | { |
139 | struct dsa_slave_priv *p = netdev_priv(dev); | 138 | struct dsa_slave_priv *p = netdev_priv(dev); |
140 | struct net_device *master = p->parent->master_netdev; | 139 | struct net_device *master = p->parent->dst->master_netdev; |
141 | struct sockaddr *addr = a; | 140 | struct sockaddr *addr = a; |
142 | int err; | 141 | int err; |
143 | 142 | ||
@@ -341,7 +340,7 @@ struct net_device * | |||
341 | dsa_slave_create(struct dsa_switch *ds, struct device *parent, | 340 | dsa_slave_create(struct dsa_switch *ds, struct device *parent, |
342 | int port, char *name) | 341 | int port, char *name) |
343 | { | 342 | { |
344 | struct net_device *master = ds->master_netdev; | 343 | struct net_device *master = ds->dst->master_netdev; |
345 | struct net_device *slave_dev; | 344 | struct net_device *slave_dev; |
346 | struct dsa_slave_priv *p; | 345 | struct dsa_slave_priv *p; |
347 | int ret; | 346 | int ret; |
@@ -356,7 +355,7 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent, | |||
356 | memcpy(slave_dev->dev_addr, master->dev_addr, ETH_ALEN); | 355 | memcpy(slave_dev->dev_addr, master->dev_addr, ETH_ALEN); |
357 | slave_dev->tx_queue_len = 0; | 356 | slave_dev->tx_queue_len = 0; |
358 | 357 | ||
359 | switch (ds->tag_protocol) { | 358 | switch (ds->dst->tag_protocol) { |
360 | #ifdef CONFIG_NET_DSA_TAG_DSA | 359 | #ifdef CONFIG_NET_DSA_TAG_DSA |
361 | case htons(ETH_P_DSA): | 360 | case htons(ETH_P_DSA): |
362 | slave_dev->netdev_ops = &dsa_netdev_ops; | 361 | slave_dev->netdev_ops = &dsa_netdev_ops; |
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c index 0b8a91ddff44..8fa25bafe6ca 100644 --- a/net/dsa/tag_dsa.c +++ b/net/dsa/tag_dsa.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * net/dsa/tag_dsa.c - (Non-ethertype) DSA tagging | 2 | * net/dsa/tag_dsa.c - (Non-ethertype) DSA tagging |
3 | * Copyright (c) 2008 Marvell Semiconductor | 3 | * Copyright (c) 2008-2009 Marvell Semiconductor |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -36,7 +36,7 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev) | |||
36 | * Construct tagged FROM_CPU DSA tag from 802.1q tag. | 36 | * Construct tagged FROM_CPU DSA tag from 802.1q tag. |
37 | */ | 37 | */ |
38 | dsa_header = skb->data + 2 * ETH_ALEN; | 38 | dsa_header = skb->data + 2 * ETH_ALEN; |
39 | dsa_header[0] = 0x60; | 39 | dsa_header[0] = 0x60 | p->parent->index; |
40 | dsa_header[1] = p->port << 3; | 40 | dsa_header[1] = p->port << 3; |
41 | 41 | ||
42 | /* | 42 | /* |
@@ -57,7 +57,7 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev) | |||
57 | * Construct untagged FROM_CPU DSA tag. | 57 | * Construct untagged FROM_CPU DSA tag. |
58 | */ | 58 | */ |
59 | dsa_header = skb->data + 2 * ETH_ALEN; | 59 | dsa_header = skb->data + 2 * ETH_ALEN; |
60 | dsa_header[0] = 0x40; | 60 | dsa_header[0] = 0x40 | p->parent->index; |
61 | dsa_header[1] = p->port << 3; | 61 | dsa_header[1] = p->port << 3; |
62 | dsa_header[2] = 0x00; | 62 | dsa_header[2] = 0x00; |
63 | dsa_header[3] = 0x00; | 63 | dsa_header[3] = 0x00; |
@@ -65,7 +65,7 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev) | |||
65 | 65 | ||
66 | skb->protocol = htons(ETH_P_DSA); | 66 | skb->protocol = htons(ETH_P_DSA); |
67 | 67 | ||
68 | skb->dev = p->parent->master_netdev; | 68 | skb->dev = p->parent->dst->master_netdev; |
69 | dev_queue_xmit(skb); | 69 | dev_queue_xmit(skb); |
70 | 70 | ||
71 | return NETDEV_TX_OK; | 71 | return NETDEV_TX_OK; |
@@ -78,11 +78,13 @@ out_free: | |||
78 | static int dsa_rcv(struct sk_buff *skb, struct net_device *dev, | 78 | static int dsa_rcv(struct sk_buff *skb, struct net_device *dev, |
79 | struct packet_type *pt, struct net_device *orig_dev) | 79 | struct packet_type *pt, struct net_device *orig_dev) |
80 | { | 80 | { |
81 | struct dsa_switch *ds = dev->dsa_ptr; | 81 | struct dsa_switch_tree *dst = dev->dsa_ptr; |
82 | struct dsa_switch *ds; | ||
82 | u8 *dsa_header; | 83 | u8 *dsa_header; |
84 | int source_device; | ||
83 | int source_port; | 85 | int source_port; |
84 | 86 | ||
85 | if (unlikely(ds == NULL)) | 87 | if (unlikely(dst == NULL)) |
86 | goto out_drop; | 88 | goto out_drop; |
87 | 89 | ||
88 | skb = skb_unshare(skb, GFP_ATOMIC); | 90 | skb = skb_unshare(skb, GFP_ATOMIC); |
@@ -98,16 +100,24 @@ static int dsa_rcv(struct sk_buff *skb, struct net_device *dev, | |||
98 | dsa_header = skb->data - 2; | 100 | dsa_header = skb->data - 2; |
99 | 101 | ||
100 | /* | 102 | /* |
101 | * Check that frame type is either TO_CPU or FORWARD, and | 103 | * Check that frame type is either TO_CPU or FORWARD. |
102 | * that the source device is zero. | ||
103 | */ | 104 | */ |
104 | if ((dsa_header[0] & 0xdf) != 0x00 && (dsa_header[0] & 0xdf) != 0xc0) | 105 | if ((dsa_header[0] & 0xc0) != 0x00 && (dsa_header[0] & 0xc0) != 0xc0) |
105 | goto out_drop; | 106 | goto out_drop; |
106 | 107 | ||
107 | /* | 108 | /* |
108 | * Check that the source port is a registered DSA port. | 109 | * Determine source device and port. |
109 | */ | 110 | */ |
111 | source_device = dsa_header[0] & 0x1f; | ||
110 | source_port = (dsa_header[1] >> 3) & 0x1f; | 112 | source_port = (dsa_header[1] >> 3) & 0x1f; |
113 | |||
114 | /* | ||
115 | * Check that the source device exists and that the source | ||
116 | * port is a registered DSA port. | ||
117 | */ | ||
118 | if (source_device >= dst->pd->nr_chips) | ||
119 | goto out_drop; | ||
120 | ds = dst->ds[source_device]; | ||
111 | if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL) | 121 | if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL) |
112 | goto out_drop; | 122 | goto out_drop; |
113 | 123 | ||
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c index 16fcb6d196d4..815607bd286f 100644 --- a/net/dsa/tag_edsa.c +++ b/net/dsa/tag_edsa.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * net/dsa/tag_edsa.c - Ethertype DSA tagging | 2 | * net/dsa/tag_edsa.c - Ethertype DSA tagging |
3 | * Copyright (c) 2008 Marvell Semiconductor | 3 | * Copyright (c) 2008-2009 Marvell Semiconductor |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -45,7 +45,7 @@ int edsa_xmit(struct sk_buff *skb, struct net_device *dev) | |||
45 | edsa_header[1] = ETH_P_EDSA & 0xff; | 45 | edsa_header[1] = ETH_P_EDSA & 0xff; |
46 | edsa_header[2] = 0x00; | 46 | edsa_header[2] = 0x00; |
47 | edsa_header[3] = 0x00; | 47 | edsa_header[3] = 0x00; |
48 | edsa_header[4] = 0x60; | 48 | edsa_header[4] = 0x60 | p->parent->index; |
49 | edsa_header[5] = p->port << 3; | 49 | edsa_header[5] = p->port << 3; |
50 | 50 | ||
51 | /* | 51 | /* |
@@ -70,7 +70,7 @@ int edsa_xmit(struct sk_buff *skb, struct net_device *dev) | |||
70 | edsa_header[1] = ETH_P_EDSA & 0xff; | 70 | edsa_header[1] = ETH_P_EDSA & 0xff; |
71 | edsa_header[2] = 0x00; | 71 | edsa_header[2] = 0x00; |
72 | edsa_header[3] = 0x00; | 72 | edsa_header[3] = 0x00; |
73 | edsa_header[4] = 0x40; | 73 | edsa_header[4] = 0x40 | p->parent->index; |
74 | edsa_header[5] = p->port << 3; | 74 | edsa_header[5] = p->port << 3; |
75 | edsa_header[6] = 0x00; | 75 | edsa_header[6] = 0x00; |
76 | edsa_header[7] = 0x00; | 76 | edsa_header[7] = 0x00; |
@@ -78,7 +78,7 @@ int edsa_xmit(struct sk_buff *skb, struct net_device *dev) | |||
78 | 78 | ||
79 | skb->protocol = htons(ETH_P_EDSA); | 79 | skb->protocol = htons(ETH_P_EDSA); |
80 | 80 | ||
81 | skb->dev = p->parent->master_netdev; | 81 | skb->dev = p->parent->dst->master_netdev; |
82 | dev_queue_xmit(skb); | 82 | dev_queue_xmit(skb); |
83 | 83 | ||
84 | return NETDEV_TX_OK; | 84 | return NETDEV_TX_OK; |
@@ -91,11 +91,13 @@ out_free: | |||
91 | static int edsa_rcv(struct sk_buff *skb, struct net_device *dev, | 91 | static int edsa_rcv(struct sk_buff *skb, struct net_device *dev, |
92 | struct packet_type *pt, struct net_device *orig_dev) | 92 | struct packet_type *pt, struct net_device *orig_dev) |
93 | { | 93 | { |
94 | struct dsa_switch *ds = dev->dsa_ptr; | 94 | struct dsa_switch_tree *dst = dev->dsa_ptr; |
95 | struct dsa_switch *ds; | ||
95 | u8 *edsa_header; | 96 | u8 *edsa_header; |
97 | int source_device; | ||
96 | int source_port; | 98 | int source_port; |
97 | 99 | ||
98 | if (unlikely(ds == NULL)) | 100 | if (unlikely(dst == NULL)) |
99 | goto out_drop; | 101 | goto out_drop; |
100 | 102 | ||
101 | skb = skb_unshare(skb, GFP_ATOMIC); | 103 | skb = skb_unshare(skb, GFP_ATOMIC); |
@@ -111,16 +113,24 @@ static int edsa_rcv(struct sk_buff *skb, struct net_device *dev, | |||
111 | edsa_header = skb->data + 2; | 113 | edsa_header = skb->data + 2; |
112 | 114 | ||
113 | /* | 115 | /* |
114 | * Check that frame type is either TO_CPU or FORWARD, and | 116 | * Check that frame type is either TO_CPU or FORWARD. |
115 | * that the source device is zero. | ||
116 | */ | 117 | */ |
117 | if ((edsa_header[0] & 0xdf) != 0x00 && (edsa_header[0] & 0xdf) != 0xc0) | 118 | if ((edsa_header[0] & 0xc0) != 0x00 && (edsa_header[0] & 0xc0) != 0xc0) |
118 | goto out_drop; | 119 | goto out_drop; |
119 | 120 | ||
120 | /* | 121 | /* |
121 | * Check that the source port is a registered DSA port. | 122 | * Determine source device and port. |
122 | */ | 123 | */ |
124 | source_device = edsa_header[0] & 0x1f; | ||
123 | source_port = (edsa_header[1] >> 3) & 0x1f; | 125 | source_port = (edsa_header[1] >> 3) & 0x1f; |
126 | |||
127 | /* | ||
128 | * Check that the source device exists and that the source | ||
129 | * port is a registered DSA port. | ||
130 | */ | ||
131 | if (source_device >= dst->pd->nr_chips) | ||
132 | goto out_drop; | ||
133 | ds = dst->ds[source_device]; | ||
124 | if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL) | 134 | if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL) |
125 | goto out_drop; | 135 | goto out_drop; |
126 | 136 | ||
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c index a6d959da6784..1c3e30c38b86 100644 --- a/net/dsa/tag_trailer.c +++ b/net/dsa/tag_trailer.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * net/dsa/tag_trailer.c - Trailer tag format handling | 2 | * net/dsa/tag_trailer.c - Trailer tag format handling |
3 | * Copyright (c) 2008 Marvell Semiconductor | 3 | * Copyright (c) 2008-2009 Marvell Semiconductor |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -59,7 +59,7 @@ int trailer_xmit(struct sk_buff *skb, struct net_device *dev) | |||
59 | 59 | ||
60 | nskb->protocol = htons(ETH_P_TRAILER); | 60 | nskb->protocol = htons(ETH_P_TRAILER); |
61 | 61 | ||
62 | nskb->dev = p->parent->master_netdev; | 62 | nskb->dev = p->parent->dst->master_netdev; |
63 | dev_queue_xmit(nskb); | 63 | dev_queue_xmit(nskb); |
64 | 64 | ||
65 | return NETDEV_TX_OK; | 65 | return NETDEV_TX_OK; |
@@ -68,12 +68,14 @@ int trailer_xmit(struct sk_buff *skb, struct net_device *dev) | |||
68 | static int trailer_rcv(struct sk_buff *skb, struct net_device *dev, | 68 | static int trailer_rcv(struct sk_buff *skb, struct net_device *dev, |
69 | struct packet_type *pt, struct net_device *orig_dev) | 69 | struct packet_type *pt, struct net_device *orig_dev) |
70 | { | 70 | { |
71 | struct dsa_switch *ds = dev->dsa_ptr; | 71 | struct dsa_switch_tree *dst = dev->dsa_ptr; |
72 | struct dsa_switch *ds; | ||
72 | u8 *trailer; | 73 | u8 *trailer; |
73 | int source_port; | 74 | int source_port; |
74 | 75 | ||
75 | if (unlikely(ds == NULL)) | 76 | if (unlikely(dst == NULL)) |
76 | goto out_drop; | 77 | goto out_drop; |
78 | ds = dst->ds[0]; | ||
77 | 79 | ||
78 | skb = skb_unshare(skb, GFP_ATOMIC); | 80 | skb = skb_unshare(skb, GFP_ATOMIC); |
79 | if (skb == NULL) | 81 | if (skb == NULL) |