1 /* 2 * Texas Instruments 3-Port Ethernet Switch Address Lookup Engine 3 * 4 * Copyright (C) 2012 Texas Instruments 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation version 2. 9 * 10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 11 * kind, whether express or implied; without even the implied warranty 12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15 #include <linux/kernel.h> 16 #include <linux/platform_device.h> 17 #include <linux/seq_file.h> 18 #include <linux/slab.h> 19 #include <linux/err.h> 20 #include <linux/io.h> 21 #include <linux/stat.h> 22 #include <linux/sysfs.h> 23 #include <linux/etherdevice.h> 24 25 #include "cpsw_ale.h" 26 27 #define BITMASK(bits) (BIT(bits) - 1) 28 29 #define ALE_VERSION_MAJOR(rev) ((rev >> 8) & 0xff) 30 #define ALE_VERSION_MINOR(rev) (rev & 0xff) 31 32 /* ALE Registers */ 33 #define ALE_IDVER 0x00 34 #define ALE_CONTROL 0x08 35 #define ALE_PRESCALE 0x10 36 #define ALE_UNKNOWNVLAN 0x18 37 #define ALE_TABLE_CONTROL 0x20 38 #define ALE_TABLE 0x34 39 #define ALE_PORTCTL 0x40 40 41 #define ALE_TABLE_WRITE BIT(31) 42 43 #define ALE_TYPE_FREE 0 44 #define ALE_TYPE_ADDR 1 45 #define ALE_TYPE_VLAN 2 46 #define ALE_TYPE_VLAN_ADDR 3 47 48 #define ALE_UCAST_PERSISTANT 0 49 #define ALE_UCAST_UNTOUCHED 1 50 #define ALE_UCAST_OUI 2 51 #define ALE_UCAST_TOUCHED 3 52 53 static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) 54 { 55 int idx; 56 57 idx = start / 32; 58 start -= idx * 32; 59 idx = 2 - idx; /* flip */ 60 return (ale_entry[idx] >> start) & BITMASK(bits); 61 } 62 63 static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits, 64 u32 value) 65 { 66 int idx; 67 68 value &= BITMASK(bits); 69 idx = start / 32; 70 start -= idx * 32; 71 idx = 2 - idx; /* flip */ 72 ale_entry[idx] &= ~(BITMASK(bits) << start); 73 ale_entry[idx] |= (value << start); 74 } 75 76 #define DEFINE_ALE_FIELD(name, start, bits) \ 77 static inline int cpsw_ale_get_##name(u32 *ale_entry) \ 78 { \ 79 return cpsw_ale_get_field(ale_entry, start, bits); \ 80 } \ 81 static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value) \ 82 { \ 83 cpsw_ale_set_field(ale_entry, start, bits, value); \ 84 } 85 86 DEFINE_ALE_FIELD(entry_type, 60, 2) 87 DEFINE_ALE_FIELD(vlan_id, 48, 12) 88 DEFINE_ALE_FIELD(mcast_state, 62, 2) 89 DEFINE_ALE_FIELD(port_mask, 66, 3) 90 DEFINE_ALE_FIELD(super, 65, 1) 91 DEFINE_ALE_FIELD(ucast_type, 62, 2) 92 DEFINE_ALE_FIELD(port_num, 66, 2) 93 DEFINE_ALE_FIELD(blocked, 65, 1) 94 DEFINE_ALE_FIELD(secure, 64, 1) 95 DEFINE_ALE_FIELD(vlan_untag_force, 24, 3) 96 DEFINE_ALE_FIELD(vlan_reg_mcast, 16, 3) 97 DEFINE_ALE_FIELD(vlan_unreg_mcast, 8, 3) 98 DEFINE_ALE_FIELD(vlan_member_list, 0, 3) 99 DEFINE_ALE_FIELD(mcast, 40, 1) 100 101 /* The MAC address field in the ALE entry cannot be macroized as above */ 102 static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) 103 { 104 int i; 105 106 for (i = 0; i < 6; i++) 107 addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8); 108 } 109 110 static inline void cpsw_ale_set_addr(u32 *ale_entry, u8 *addr) 111 { 112 int i; 113 114 for (i = 0; i < 6; i++) 115 cpsw_ale_set_field(ale_entry, 40 - 8*i, 8, addr[i]); 116 } 117 118 static int cpsw_ale_read(struct cpsw_ale *ale, int idx, u32 *ale_entry) 119 { 120 int i; 121 122 WARN_ON(idx > ale->params.ale_entries); 123 124 __raw_writel(idx, ale->params.ale_regs + ALE_TABLE_CONTROL); 125 126 for (i = 0; i < ALE_ENTRY_WORDS; i++) 127 ale_entry[i] = __raw_readl(ale->params.ale_regs + 128 ALE_TABLE + 4 * i); 129 130 return idx; 131 } 132 133 static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry) 134 { 135 int i; 136 137 WARN_ON(idx > ale->params.ale_entries); 138 139 for (i = 0; i < ALE_ENTRY_WORDS; i++) 140 __raw_writel(ale_entry[i], ale->params.ale_regs + 141 ALE_TABLE + 4 * i); 142 143 __raw_writel(idx | ALE_TABLE_WRITE, ale->params.ale_regs + 144 ALE_TABLE_CONTROL); 145 146 return idx; 147 } 148 149 int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid) 150 { 151 u32 ale_entry[ALE_ENTRY_WORDS]; 152 int type, idx; 153 154 for (idx = 0; idx < ale->params.ale_entries; idx++) { 155 u8 entry_addr[6]; 156 157 cpsw_ale_read(ale, idx, ale_entry); 158 type = cpsw_ale_get_entry_type(ale_entry); 159 if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR) 160 continue; 161 if (cpsw_ale_get_vlan_id(ale_entry) != vid) 162 continue; 163 cpsw_ale_get_addr(ale_entry, entry_addr); 164 if (ether_addr_equal(entry_addr, addr)) 165 return idx; 166 } 167 return -ENOENT; 168 } 169 170 int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid) 171 { 172 u32 ale_entry[ALE_ENTRY_WORDS]; 173 int type, idx; 174 175 for (idx = 0; idx < ale->params.ale_entries; idx++) { 176 cpsw_ale_read(ale, idx, ale_entry); 177 type = cpsw_ale_get_entry_type(ale_entry); 178 if (type != ALE_TYPE_VLAN) 179 continue; 180 if (cpsw_ale_get_vlan_id(ale_entry) == vid) 181 return idx; 182 } 183 return -ENOENT; 184 } 185 186 static int cpsw_ale_match_free(struct cpsw_ale *ale) 187 { 188 u32 ale_entry[ALE_ENTRY_WORDS]; 189 int type, idx; 190 191 for (idx = 0; idx < ale->params.ale_entries; idx++) { 192 cpsw_ale_read(ale, idx, ale_entry); 193 type = cpsw_ale_get_entry_type(ale_entry); 194 if (type == ALE_TYPE_FREE) 195 return idx; 196 } 197 return -ENOENT; 198 } 199 200 static int cpsw_ale_find_ageable(struct cpsw_ale *ale) 201 { 202 u32 ale_entry[ALE_ENTRY_WORDS]; 203 int type, idx; 204 205 for (idx = 0; idx < ale->params.ale_entries; idx++) { 206 cpsw_ale_read(ale, idx, ale_entry); 207 type = cpsw_ale_get_entry_type(ale_entry); 208 if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR) 209 continue; 210 if (cpsw_ale_get_mcast(ale_entry)) 211 continue; 212 type = cpsw_ale_get_ucast_type(ale_entry); 213 if (type != ALE_UCAST_PERSISTANT && 214 type != ALE_UCAST_OUI) 215 return idx; 216 } 217 return -ENOENT; 218 } 219 220 static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry, 221 int port_mask) 222 { 223 int mask; 224 225 mask = cpsw_ale_get_port_mask(ale_entry); 226 if ((mask & port_mask) == 0) 227 return; /* ports dont intersect, not interested */ 228 mask &= ~port_mask; 229 230 /* free if only remaining port is host port */ 231 if (mask) 232 cpsw_ale_set_port_mask(ale_entry, mask); 233 else 234 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); 235 } 236 237 int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid) 238 { 239 u32 ale_entry[ALE_ENTRY_WORDS]; 240 int ret, idx; 241 242 for (idx = 0; idx < ale->params.ale_entries; idx++) { 243 cpsw_ale_read(ale, idx, ale_entry); 244 ret = cpsw_ale_get_entry_type(ale_entry); 245 if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR) 246 continue; 247 248 /* if vid passed is -1 then remove all multicast entry from 249 * the table irrespective of vlan id, if a valid vlan id is 250 * passed then remove only multicast added to that vlan id. 251 * if vlan id doesn't match then move on to next entry. 252 */ 253 if (vid != -1 && cpsw_ale_get_vlan_id(ale_entry) != vid) 254 continue; 255 256 if (cpsw_ale_get_mcast(ale_entry)) { 257 u8 addr[6]; 258 259 cpsw_ale_get_addr(ale_entry, addr); 260 if (!is_broadcast_ether_addr(addr)) 261 cpsw_ale_flush_mcast(ale, ale_entry, port_mask); 262 } 263 264 cpsw_ale_write(ale, idx, ale_entry); 265 } 266 return 0; 267 } 268 269 static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry, 270 int port_mask) 271 { 272 int port; 273 274 port = cpsw_ale_get_port_num(ale_entry); 275 if ((BIT(port) & port_mask) == 0) 276 return; /* ports dont intersect, not interested */ 277 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); 278 } 279 280 int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask) 281 { 282 u32 ale_entry[ALE_ENTRY_WORDS]; 283 int ret, idx; 284 285 for (idx = 0; idx < ale->params.ale_entries; idx++) { 286 cpsw_ale_read(ale, idx, ale_entry); 287 ret = cpsw_ale_get_entry_type(ale_entry); 288 if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR) 289 continue; 290 291 if (cpsw_ale_get_mcast(ale_entry)) 292 cpsw_ale_flush_mcast(ale, ale_entry, port_mask); 293 else 294 cpsw_ale_flush_ucast(ale, ale_entry, port_mask); 295 296 cpsw_ale_write(ale, idx, ale_entry); 297 } 298 return 0; 299 } 300 301 static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry, 302 int flags, u16 vid) 303 { 304 if (flags & ALE_VLAN) { 305 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR); 306 cpsw_ale_set_vlan_id(ale_entry, vid); 307 } else { 308 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); 309 } 310 } 311 312 int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, 313 int flags, u16 vid) 314 { 315 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 316 int idx; 317 318 cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid); 319 320 cpsw_ale_set_addr(ale_entry, addr); 321 cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT); 322 cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0); 323 cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); 324 cpsw_ale_set_port_num(ale_entry, port); 325 326 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); 327 if (idx < 0) 328 idx = cpsw_ale_match_free(ale); 329 if (idx < 0) 330 idx = cpsw_ale_find_ageable(ale); 331 if (idx < 0) 332 return -ENOMEM; 333 334 cpsw_ale_write(ale, idx, ale_entry); 335 return 0; 336 } 337 338 int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, 339 int flags, u16 vid) 340 { 341 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 342 int idx; 343 344 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); 345 if (idx < 0) 346 return -ENOENT; 347 348 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); 349 cpsw_ale_write(ale, idx, ale_entry); 350 return 0; 351 } 352 353 int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, 354 int flags, u16 vid, int mcast_state) 355 { 356 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 357 int idx, mask; 358 359 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); 360 if (idx >= 0) 361 cpsw_ale_read(ale, idx, ale_entry); 362 363 cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid); 364 365 cpsw_ale_set_addr(ale_entry, addr); 366 cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); 367 cpsw_ale_set_mcast_state(ale_entry, mcast_state); 368 369 mask = cpsw_ale_get_port_mask(ale_entry); 370 port_mask |= mask; 371 cpsw_ale_set_port_mask(ale_entry, port_mask); 372 373 if (idx < 0) 374 idx = cpsw_ale_match_free(ale); 375 if (idx < 0) 376 idx = cpsw_ale_find_ageable(ale); 377 if (idx < 0) 378 return -ENOMEM; 379 380 cpsw_ale_write(ale, idx, ale_entry); 381 return 0; 382 } 383 384 int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, 385 int flags, u16 vid) 386 { 387 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 388 int idx; 389 390 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); 391 if (idx < 0) 392 return -EINVAL; 393 394 cpsw_ale_read(ale, idx, ale_entry); 395 396 if (port_mask) 397 cpsw_ale_set_port_mask(ale_entry, port_mask); 398 else 399 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); 400 401 cpsw_ale_write(ale, idx, ale_entry); 402 return 0; 403 } 404 405 int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, 406 int reg_mcast, int unreg_mcast) 407 { 408 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 409 int idx; 410 411 idx = cpsw_ale_match_vlan(ale, vid); 412 if (idx >= 0) 413 cpsw_ale_read(ale, idx, ale_entry); 414 415 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN); 416 cpsw_ale_set_vlan_id(ale_entry, vid); 417 418 cpsw_ale_set_vlan_untag_force(ale_entry, untag); 419 cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast); 420 cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast); 421 cpsw_ale_set_vlan_member_list(ale_entry, port); 422 423 if (idx < 0) 424 idx = cpsw_ale_match_free(ale); 425 if (idx < 0) 426 idx = cpsw_ale_find_ageable(ale); 427 if (idx < 0) 428 return -ENOMEM; 429 430 cpsw_ale_write(ale, idx, ale_entry); 431 return 0; 432 } 433 434 int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) 435 { 436 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 437 int idx; 438 439 idx = cpsw_ale_match_vlan(ale, vid); 440 if (idx < 0) 441 return -ENOENT; 442 443 cpsw_ale_read(ale, idx, ale_entry); 444 445 if (port_mask) 446 cpsw_ale_set_vlan_member_list(ale_entry, port_mask); 447 else 448 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); 449 450 cpsw_ale_write(ale, idx, ale_entry); 451 return 0; 452 } 453 454 void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti) 455 { 456 u32 ale_entry[ALE_ENTRY_WORDS]; 457 int type, idx; 458 int unreg_mcast = 0; 459 460 /* Only bother doing the work if the setting is actually changing */ 461 if (ale->allmulti == allmulti) 462 return; 463 464 /* Remember the new setting to check against next time */ 465 ale->allmulti = allmulti; 466 467 for (idx = 0; idx < ale->params.ale_entries; idx++) { 468 cpsw_ale_read(ale, idx, ale_entry); 469 type = cpsw_ale_get_entry_type(ale_entry); 470 if (type != ALE_TYPE_VLAN) 471 continue; 472 473 unreg_mcast = cpsw_ale_get_vlan_unreg_mcast(ale_entry); 474 if (allmulti) 475 unreg_mcast |= 1; 476 else 477 unreg_mcast &= ~1; 478 cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast); 479 cpsw_ale_write(ale, idx, ale_entry); 480 } 481 } 482 483 struct ale_control_info { 484 const char *name; 485 int offset, port_offset; 486 int shift, port_shift; 487 int bits; 488 }; 489 490 static const struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = { 491 [ALE_ENABLE] = { 492 .name = "enable", 493 .offset = ALE_CONTROL, 494 .port_offset = 0, 495 .shift = 31, 496 .port_shift = 0, 497 .bits = 1, 498 }, 499 [ALE_CLEAR] = { 500 .name = "clear", 501 .offset = ALE_CONTROL, 502 .port_offset = 0, 503 .shift = 30, 504 .port_shift = 0, 505 .bits = 1, 506 }, 507 [ALE_AGEOUT] = { 508 .name = "ageout", 509 .offset = ALE_CONTROL, 510 .port_offset = 0, 511 .shift = 29, 512 .port_shift = 0, 513 .bits = 1, 514 }, 515 [ALE_P0_UNI_FLOOD] = { 516 .name = "port0_unicast_flood", 517 .offset = ALE_CONTROL, 518 .port_offset = 0, 519 .shift = 8, 520 .port_shift = 0, 521 .bits = 1, 522 }, 523 [ALE_VLAN_NOLEARN] = { 524 .name = "vlan_nolearn", 525 .offset = ALE_CONTROL, 526 .port_offset = 0, 527 .shift = 7, 528 .port_shift = 0, 529 .bits = 1, 530 }, 531 [ALE_NO_PORT_VLAN] = { 532 .name = "no_port_vlan", 533 .offset = ALE_CONTROL, 534 .port_offset = 0, 535 .shift = 6, 536 .port_shift = 0, 537 .bits = 1, 538 }, 539 [ALE_OUI_DENY] = { 540 .name = "oui_deny", 541 .offset = ALE_CONTROL, 542 .port_offset = 0, 543 .shift = 5, 544 .port_shift = 0, 545 .bits = 1, 546 }, 547 [ALE_BYPASS] = { 548 .name = "bypass", 549 .offset = ALE_CONTROL, 550 .port_offset = 0, 551 .shift = 4, 552 .port_shift = 0, 553 .bits = 1, 554 }, 555 [ALE_RATE_LIMIT_TX] = { 556 .name = "rate_limit_tx", 557 .offset = ALE_CONTROL, 558 .port_offset = 0, 559 .shift = 3, 560 .port_shift = 0, 561 .bits = 1, 562 }, 563 [ALE_VLAN_AWARE] = { 564 .name = "vlan_aware", 565 .offset = ALE_CONTROL, 566 .port_offset = 0, 567 .shift = 2, 568 .port_shift = 0, 569 .bits = 1, 570 }, 571 [ALE_AUTH_ENABLE] = { 572 .name = "auth_enable", 573 .offset = ALE_CONTROL, 574 .port_offset = 0, 575 .shift = 1, 576 .port_shift = 0, 577 .bits = 1, 578 }, 579 [ALE_RATE_LIMIT] = { 580 .name = "rate_limit", 581 .offset = ALE_CONTROL, 582 .port_offset = 0, 583 .shift = 0, 584 .port_shift = 0, 585 .bits = 1, 586 }, 587 [ALE_PORT_STATE] = { 588 .name = "port_state", 589 .offset = ALE_PORTCTL, 590 .port_offset = 4, 591 .shift = 0, 592 .port_shift = 0, 593 .bits = 2, 594 }, 595 [ALE_PORT_DROP_UNTAGGED] = { 596 .name = "drop_untagged", 597 .offset = ALE_PORTCTL, 598 .port_offset = 4, 599 .shift = 2, 600 .port_shift = 0, 601 .bits = 1, 602 }, 603 [ALE_PORT_DROP_UNKNOWN_VLAN] = { 604 .name = "drop_unknown", 605 .offset = ALE_PORTCTL, 606 .port_offset = 4, 607 .shift = 3, 608 .port_shift = 0, 609 .bits = 1, 610 }, 611 [ALE_PORT_NOLEARN] = { 612 .name = "nolearn", 613 .offset = ALE_PORTCTL, 614 .port_offset = 4, 615 .shift = 4, 616 .port_shift = 0, 617 .bits = 1, 618 }, 619 [ALE_PORT_NO_SA_UPDATE] = { 620 .name = "no_source_update", 621 .offset = ALE_PORTCTL, 622 .port_offset = 4, 623 .shift = 5, 624 .port_shift = 0, 625 .bits = 1, 626 }, 627 [ALE_PORT_MCAST_LIMIT] = { 628 .name = "mcast_limit", 629 .offset = ALE_PORTCTL, 630 .port_offset = 4, 631 .shift = 16, 632 .port_shift = 0, 633 .bits = 8, 634 }, 635 [ALE_PORT_BCAST_LIMIT] = { 636 .name = "bcast_limit", 637 .offset = ALE_PORTCTL, 638 .port_offset = 4, 639 .shift = 24, 640 .port_shift = 0, 641 .bits = 8, 642 }, 643 [ALE_PORT_UNKNOWN_VLAN_MEMBER] = { 644 .name = "unknown_vlan_member", 645 .offset = ALE_UNKNOWNVLAN, 646 .port_offset = 0, 647 .shift = 0, 648 .port_shift = 0, 649 .bits = 6, 650 }, 651 [ALE_PORT_UNKNOWN_MCAST_FLOOD] = { 652 .name = "unknown_mcast_flood", 653 .offset = ALE_UNKNOWNVLAN, 654 .port_offset = 0, 655 .shift = 8, 656 .port_shift = 0, 657 .bits = 6, 658 }, 659 [ALE_PORT_UNKNOWN_REG_MCAST_FLOOD] = { 660 .name = "unknown_reg_flood", 661 .offset = ALE_UNKNOWNVLAN, 662 .port_offset = 0, 663 .shift = 16, 664 .port_shift = 0, 665 .bits = 6, 666 }, 667 [ALE_PORT_UNTAGGED_EGRESS] = { 668 .name = "untagged_egress", 669 .offset = ALE_UNKNOWNVLAN, 670 .port_offset = 0, 671 .shift = 24, 672 .port_shift = 0, 673 .bits = 6, 674 }, 675 }; 676 677 int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control, 678 int value) 679 { 680 const struct ale_control_info *info; 681 int offset, shift; 682 u32 tmp, mask; 683 684 if (control < 0 || control >= ARRAY_SIZE(ale_controls)) 685 return -EINVAL; 686 687 info = &ale_controls[control]; 688 if (info->port_offset == 0 && info->port_shift == 0) 689 port = 0; /* global, port is a dont care */ 690 691 if (port < 0 || port > ale->params.ale_ports) 692 return -EINVAL; 693 694 mask = BITMASK(info->bits); 695 if (value & ~mask) 696 return -EINVAL; 697 698 offset = info->offset + (port * info->port_offset); 699 shift = info->shift + (port * info->port_shift); 700 701 tmp = __raw_readl(ale->params.ale_regs + offset); 702 tmp = (tmp & ~(mask << shift)) | (value << shift); 703 __raw_writel(tmp, ale->params.ale_regs + offset); 704 705 return 0; 706 } 707 708 int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) 709 { 710 const struct ale_control_info *info; 711 int offset, shift; 712 u32 tmp; 713 714 if (control < 0 || control >= ARRAY_SIZE(ale_controls)) 715 return -EINVAL; 716 717 info = &ale_controls[control]; 718 if (info->port_offset == 0 && info->port_shift == 0) 719 port = 0; /* global, port is a dont care */ 720 721 if (port < 0 || port > ale->params.ale_ports) 722 return -EINVAL; 723 724 offset = info->offset + (port * info->port_offset); 725 shift = info->shift + (port * info->port_shift); 726 727 tmp = __raw_readl(ale->params.ale_regs + offset) >> shift; 728 return tmp & BITMASK(info->bits); 729 } 730 731 static void cpsw_ale_timer(unsigned long arg) 732 { 733 struct cpsw_ale *ale = (struct cpsw_ale *)arg; 734 735 cpsw_ale_control_set(ale, 0, ALE_AGEOUT, 1); 736 737 if (ale->ageout) { 738 ale->timer.expires = jiffies + ale->ageout; 739 add_timer(&ale->timer); 740 } 741 } 742 743 int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout) 744 { 745 del_timer_sync(&ale->timer); 746 ale->ageout = ageout * HZ; 747 if (ale->ageout) { 748 ale->timer.expires = jiffies + ale->ageout; 749 add_timer(&ale->timer); 750 } 751 return 0; 752 } 753 754 void cpsw_ale_start(struct cpsw_ale *ale) 755 { 756 u32 rev; 757 758 rev = __raw_readl(ale->params.ale_regs + ALE_IDVER); 759 dev_dbg(ale->params.dev, "initialized cpsw ale revision %d.%d\n", 760 ALE_VERSION_MAJOR(rev), ALE_VERSION_MINOR(rev)); 761 cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1); 762 cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); 763 764 init_timer(&ale->timer); 765 ale->timer.data = (unsigned long)ale; 766 ale->timer.function = cpsw_ale_timer; 767 if (ale->ageout) { 768 ale->timer.expires = jiffies + ale->ageout; 769 add_timer(&ale->timer); 770 } 771 } 772 773 void cpsw_ale_stop(struct cpsw_ale *ale) 774 { 775 del_timer_sync(&ale->timer); 776 } 777 778 struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) 779 { 780 struct cpsw_ale *ale; 781 782 ale = kzalloc(sizeof(*ale), GFP_KERNEL); 783 if (!ale) 784 return NULL; 785 786 ale->params = *params; 787 ale->ageout = ale->params.ale_ageout * HZ; 788 789 return ale; 790 } 791 792 int cpsw_ale_destroy(struct cpsw_ale *ale) 793 { 794 if (!ale) 795 return -EINVAL; 796 cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0); 797 kfree(ale); 798 return 0; 799 } 800 801 void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) 802 { 803 int i; 804 805 for (i = 0; i < ale->params.ale_entries; i++) { 806 cpsw_ale_read(ale, i, data); 807 data += ALE_ENTRY_WORDS; 808 } 809 } 810