diff options
author | Mugunthan V N <mugunthanvnm@ti.com> | 2013-02-05 03:26:47 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-02-06 15:46:40 -0500 |
commit | e11b220f336c654db876027d40953acef90b0cae (patch) | |
tree | 1621d2e2acd1cd6432e36c34ef5bffb5476727c2 | |
parent | ca99ca14c95ae49fb4c9cd3abf5f84d11a7e8a61 (diff) |
drivers: net: cpsw: Add helper functions for VLAN ALE implementation
Add helper functions for VLAN ALE implementations for Add, Delete
Dump VLAN related ALE entries
Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/cpsw_ale.c | 107 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/cpsw_ale.h | 20 |
3 files changed, 113 insertions, 22 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 9e63bff124fe..534bf7bc34db 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c | |||
@@ -345,7 +345,7 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev) | |||
345 | /* program multicast address list into ALE register */ | 345 | /* program multicast address list into ALE register */ |
346 | netdev_for_each_mc_addr(ha, ndev) { | 346 | netdev_for_each_mc_addr(ha, ndev) { |
347 | cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr, | 347 | cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr, |
348 | ALE_ALL_PORTS << priv->host_port, 0, 0); | 348 | ALE_ALL_PORTS << priv->host_port, 0, 0, 0); |
349 | } | 349 | } |
350 | } | 350 | } |
351 | } | 351 | } |
@@ -592,7 +592,7 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) | |||
592 | slave_port = cpsw_get_slave_port(priv, slave->slave_num); | 592 | slave_port = cpsw_get_slave_port(priv, slave->slave_num); |
593 | 593 | ||
594 | cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, | 594 | cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, |
595 | 1 << slave_port, 0, ALE_MCAST_FWD_2); | 595 | 1 << slave_port, 0, 0, ALE_MCAST_FWD_2); |
596 | 596 | ||
597 | slave->phy = phy_connect(priv->ndev, slave->data->phy_id, | 597 | slave->phy = phy_connect(priv->ndev, slave->data->phy_id, |
598 | &cpsw_adjust_link, slave->data->phy_if); | 598 | &cpsw_adjust_link, slave->data->phy_if); |
@@ -624,9 +624,9 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) | |||
624 | cpsw_ale_control_set(priv->ale, priv->host_port, | 624 | cpsw_ale_control_set(priv->ale, priv->host_port, |
625 | ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); | 625 | ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); |
626 | 626 | ||
627 | cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port, 0); | 627 | cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port, 0, 0); |
628 | cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, | 628 | cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, |
629 | 1 << priv->host_port, 0, ALE_MCAST_FWD_2); | 629 | 1 << priv->host_port, 0, 0, ALE_MCAST_FWD_2); |
630 | } | 630 | } |
631 | 631 | ||
632 | static int cpsw_ndo_open(struct net_device *ndev) | 632 | static int cpsw_ndo_open(struct net_device *ndev) |
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 0e9ccc2cf91f..7fa60d6092ed 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c | |||
@@ -148,7 +148,7 @@ static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry) | |||
148 | return idx; | 148 | return idx; |
149 | } | 149 | } |
150 | 150 | ||
151 | static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr) | 151 | int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid) |
152 | { | 152 | { |
153 | u32 ale_entry[ALE_ENTRY_WORDS]; | 153 | u32 ale_entry[ALE_ENTRY_WORDS]; |
154 | int type, idx; | 154 | int type, idx; |
@@ -160,6 +160,8 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr) | |||
160 | type = cpsw_ale_get_entry_type(ale_entry); | 160 | type = cpsw_ale_get_entry_type(ale_entry); |
161 | if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR) | 161 | if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR) |
162 | continue; | 162 | continue; |
163 | if (cpsw_ale_get_vlan_id(ale_entry) != vid) | ||
164 | continue; | ||
163 | cpsw_ale_get_addr(ale_entry, entry_addr); | 165 | cpsw_ale_get_addr(ale_entry, entry_addr); |
164 | if (memcmp(entry_addr, addr, 6) == 0) | 166 | if (memcmp(entry_addr, addr, 6) == 0) |
165 | return idx; | 167 | return idx; |
@@ -167,6 +169,22 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr) | |||
167 | return -ENOENT; | 169 | return -ENOENT; |
168 | } | 170 | } |
169 | 171 | ||
172 | int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid) | ||
173 | { | ||
174 | u32 ale_entry[ALE_ENTRY_WORDS]; | ||
175 | int type, idx; | ||
176 | |||
177 | for (idx = 0; idx < ale->params.ale_entries; idx++) { | ||
178 | cpsw_ale_read(ale, idx, ale_entry); | ||
179 | type = cpsw_ale_get_entry_type(ale_entry); | ||
180 | if (type != ALE_TYPE_VLAN) | ||
181 | continue; | ||
182 | if (cpsw_ale_get_vlan_id(ale_entry) == vid) | ||
183 | return idx; | ||
184 | } | ||
185 | return -ENOENT; | ||
186 | } | ||
187 | |||
170 | static int cpsw_ale_match_free(struct cpsw_ale *ale) | 188 | static int cpsw_ale_match_free(struct cpsw_ale *ale) |
171 | { | 189 | { |
172 | u32 ale_entry[ALE_ENTRY_WORDS]; | 190 | u32 ale_entry[ALE_ENTRY_WORDS]; |
@@ -274,19 +292,32 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask) | |||
274 | return 0; | 292 | return 0; |
275 | } | 293 | } |
276 | 294 | ||
277 | int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags) | 295 | static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry, |
296 | int flags, u16 vid) | ||
297 | { | ||
298 | if (flags & ALE_VLAN) { | ||
299 | cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR); | ||
300 | cpsw_ale_set_vlan_id(ale_entry, vid); | ||
301 | } else { | ||
302 | cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, | ||
307 | int flags, u16 vid) | ||
278 | { | 308 | { |
279 | u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; | 309 | u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; |
280 | int idx; | 310 | int idx; |
281 | 311 | ||
282 | cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); | 312 | cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid); |
313 | |||
283 | cpsw_ale_set_addr(ale_entry, addr); | 314 | cpsw_ale_set_addr(ale_entry, addr); |
284 | cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT); | 315 | cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT); |
285 | cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0); | 316 | cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0); |
286 | cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); | 317 | cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); |
287 | cpsw_ale_set_port_num(ale_entry, port); | 318 | cpsw_ale_set_port_num(ale_entry, port); |
288 | 319 | ||
289 | idx = cpsw_ale_match_addr(ale, addr); | 320 | idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); |
290 | if (idx < 0) | 321 | if (idx < 0) |
291 | idx = cpsw_ale_match_free(ale); | 322 | idx = cpsw_ale_match_free(ale); |
292 | if (idx < 0) | 323 | if (idx < 0) |
@@ -298,12 +329,13 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags) | |||
298 | return 0; | 329 | return 0; |
299 | } | 330 | } |
300 | 331 | ||
301 | int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port) | 332 | int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, |
333 | int flags, u16 vid) | ||
302 | { | 334 | { |
303 | u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; | 335 | u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; |
304 | int idx; | 336 | int idx; |
305 | 337 | ||
306 | idx = cpsw_ale_match_addr(ale, addr); | 338 | idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); |
307 | if (idx < 0) | 339 | if (idx < 0) |
308 | return -ENOENT; | 340 | return -ENOENT; |
309 | 341 | ||
@@ -313,18 +345,19 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port) | |||
313 | } | 345 | } |
314 | 346 | ||
315 | int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, | 347 | int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, |
316 | int super, int mcast_state) | 348 | int flags, u16 vid, int mcast_state) |
317 | { | 349 | { |
318 | u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; | 350 | u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; |
319 | int idx, mask; | 351 | int idx, mask; |
320 | 352 | ||
321 | idx = cpsw_ale_match_addr(ale, addr); | 353 | idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); |
322 | if (idx >= 0) | 354 | if (idx >= 0) |
323 | cpsw_ale_read(ale, idx, ale_entry); | 355 | cpsw_ale_read(ale, idx, ale_entry); |
324 | 356 | ||
325 | cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); | 357 | cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid); |
358 | |||
326 | cpsw_ale_set_addr(ale_entry, addr); | 359 | cpsw_ale_set_addr(ale_entry, addr); |
327 | cpsw_ale_set_super(ale_entry, super); | 360 | cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); |
328 | cpsw_ale_set_mcast_state(ale_entry, mcast_state); | 361 | cpsw_ale_set_mcast_state(ale_entry, mcast_state); |
329 | 362 | ||
330 | mask = cpsw_ale_get_port_mask(ale_entry); | 363 | mask = cpsw_ale_get_port_mask(ale_entry); |
@@ -342,12 +375,13 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, | |||
342 | return 0; | 375 | return 0; |
343 | } | 376 | } |
344 | 377 | ||
345 | int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask) | 378 | int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, |
379 | int flags, u16 vid) | ||
346 | { | 380 | { |
347 | u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; | 381 | u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; |
348 | int idx; | 382 | int idx; |
349 | 383 | ||
350 | idx = cpsw_ale_match_addr(ale, addr); | 384 | idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); |
351 | if (idx < 0) | 385 | if (idx < 0) |
352 | return -EINVAL; | 386 | return -EINVAL; |
353 | 387 | ||
@@ -362,6 +396,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask) | |||
362 | return 0; | 396 | return 0; |
363 | } | 397 | } |
364 | 398 | ||
399 | int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, | ||
400 | int reg_mcast, int unreg_mcast) | ||
401 | { | ||
402 | u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; | ||
403 | int idx; | ||
404 | |||
405 | idx = cpsw_ale_match_vlan(ale, vid); | ||
406 | if (idx >= 0) | ||
407 | cpsw_ale_read(ale, idx, ale_entry); | ||
408 | |||
409 | cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN); | ||
410 | cpsw_ale_set_vlan_id(ale_entry, vid); | ||
411 | |||
412 | cpsw_ale_set_vlan_untag_force(ale_entry, untag); | ||
413 | cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast); | ||
414 | cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast); | ||
415 | cpsw_ale_set_vlan_member_list(ale_entry, port); | ||
416 | |||
417 | if (idx < 0) | ||
418 | idx = cpsw_ale_match_free(ale); | ||
419 | if (idx < 0) | ||
420 | idx = cpsw_ale_find_ageable(ale); | ||
421 | if (idx < 0) | ||
422 | return -ENOMEM; | ||
423 | |||
424 | cpsw_ale_write(ale, idx, ale_entry); | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) | ||
429 | { | ||
430 | u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; | ||
431 | int idx; | ||
432 | |||
433 | idx = cpsw_ale_match_vlan(ale, vid); | ||
434 | if (idx < 0) | ||
435 | return -ENOENT; | ||
436 | |||
437 | cpsw_ale_read(ale, idx, ale_entry); | ||
438 | |||
439 | if (port_mask) | ||
440 | cpsw_ale_set_vlan_member_list(ale_entry, port_mask); | ||
441 | else | ||
442 | cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); | ||
443 | |||
444 | cpsw_ale_write(ale, idx, ale_entry); | ||
445 | return 0; | ||
446 | } | ||
447 | |||
365 | struct ale_control_info { | 448 | struct ale_control_info { |
366 | const char *name; | 449 | const char *name; |
367 | int offset, port_offset; | 450 | int offset, port_offset; |
diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h index 2bd09cbce522..a002417f952b 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.h +++ b/drivers/net/ethernet/ti/cpsw_ale.h | |||
@@ -64,8 +64,10 @@ enum cpsw_ale_port_state { | |||
64 | }; | 64 | }; |
65 | 65 | ||
66 | /* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */ | 66 | /* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */ |
67 | #define ALE_SECURE 1 | 67 | #define ALE_SECURE BIT(0) |
68 | #define ALE_BLOCKED 2 | 68 | #define ALE_BLOCKED BIT(1) |
69 | #define ALE_SUPER BIT(2) | ||
70 | #define ALE_VLAN BIT(3) | ||
69 | 71 | ||
70 | #define ALE_MCAST_FWD 0 | 72 | #define ALE_MCAST_FWD 0 |
71 | #define ALE_MCAST_BLOCK_LEARN_FWD 1 | 73 | #define ALE_MCAST_BLOCK_LEARN_FWD 1 |
@@ -81,11 +83,17 @@ void cpsw_ale_stop(struct cpsw_ale *ale); | |||
81 | int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout); | 83 | int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout); |
82 | int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask); | 84 | int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask); |
83 | int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask); | 85 | int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask); |
84 | int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags); | 86 | int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, |
85 | int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port); | 87 | int flags, u16 vid); |
88 | int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, | ||
89 | int flags, u16 vid); | ||
86 | int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, | 90 | int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, |
87 | int super, int mcast_state); | 91 | int flags, u16 vid, int mcast_state); |
88 | int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask); | 92 | int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, |
93 | int flags, u16 vid); | ||
94 | int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, | ||
95 | int reg_mcast, int unreg_mcast); | ||
96 | int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port); | ||
89 | 97 | ||
90 | int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control); | 98 | int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control); |
91 | int cpsw_ale_control_set(struct cpsw_ale *ale, int port, | 99 | int cpsw_ale_control_set(struct cpsw_ale *ale, int port, |