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) 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 (cpsw_ale_get_mcast(ale_entry)) { 249 u8 addr[6]; 250 251 cpsw_ale_get_addr(ale_entry, addr); 252 if (!is_broadcast_ether_addr(addr)) 253 cpsw_ale_flush_mcast(ale, ale_entry, port_mask); 254 } 255 256 cpsw_ale_write(ale, idx, ale_entry); 257 } 258 return 0; 259 } 260 261 static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry, 262 int port_mask) 263 { 264 int port; 265 266 port = cpsw_ale_get_port_num(ale_entry); 267 if ((BIT(port) & port_mask) == 0) 268 return; /* ports dont intersect, not interested */ 269 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); 270 } 271 272 int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask) 273 { 274 u32 ale_entry[ALE_ENTRY_WORDS]; 275 int ret, idx; 276 277 for (idx = 0; idx < ale->params.ale_entries; idx++) { 278 cpsw_ale_read(ale, idx, ale_entry); 279 ret = cpsw_ale_get_entry_type(ale_entry); 280 if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR) 281 continue; 282 283 if (cpsw_ale_get_mcast(ale_entry)) 284 cpsw_ale_flush_mcast(ale, ale_entry, port_mask); 285 else 286 cpsw_ale_flush_ucast(ale, ale_entry, port_mask); 287 288 cpsw_ale_write(ale, idx, ale_entry); 289 } 290 return 0; 291 } 292 293 static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry, 294 int flags, u16 vid) 295 { 296 if (flags & ALE_VLAN) { 297 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR); 298 cpsw_ale_set_vlan_id(ale_entry, vid); 299 } else { 300 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); 301 } 302 } 303 304 int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, 305 int flags, u16 vid) 306 { 307 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 308 int idx; 309 310 cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid); 311 312 cpsw_ale_set_addr(ale_entry, addr); 313 cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT); 314 cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0); 315 cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); 316 cpsw_ale_set_port_num(ale_entry, port); 317 318 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); 319 if (idx < 0) 320 idx = cpsw_ale_match_free(ale); 321 if (idx < 0) 322 idx = cpsw_ale_find_ageable(ale); 323 if (idx < 0) 324 return -ENOMEM; 325 326 cpsw_ale_write(ale, idx, ale_entry); 327 return 0; 328 } 329 330 int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, 331 int flags, u16 vid) 332 { 333 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 334 int idx; 335 336 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); 337 if (idx < 0) 338 return -ENOENT; 339 340 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); 341 cpsw_ale_write(ale, idx, ale_entry); 342 return 0; 343 } 344 345 int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, 346 int flags, u16 vid, int mcast_state) 347 { 348 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 349 int idx, mask; 350 351 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); 352 if (idx >= 0) 353 cpsw_ale_read(ale, idx, ale_entry); 354 355 cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid); 356 357 cpsw_ale_set_addr(ale_entry, addr); 358 cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); 359 cpsw_ale_set_mcast_state(ale_entry, mcast_state); 360 361 mask = cpsw_ale_get_port_mask(ale_entry); 362 port_mask |= mask; 363 cpsw_ale_set_port_mask(ale_entry, port_mask); 364 365 if (idx < 0) 366 idx = cpsw_ale_match_free(ale); 367 if (idx < 0) 368 idx = cpsw_ale_find_ageable(ale); 369 if (idx < 0) 370 return -ENOMEM; 371 372 cpsw_ale_write(ale, idx, ale_entry); 373 return 0; 374 } 375 376 int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, 377 int flags, u16 vid) 378 { 379 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 380 int idx; 381 382 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); 383 if (idx < 0) 384 return -EINVAL; 385 386 cpsw_ale_read(ale, idx, ale_entry); 387 388 if (port_mask) 389 cpsw_ale_set_port_mask(ale_entry, port_mask); 390 else 391 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); 392 393 cpsw_ale_write(ale, idx, ale_entry); 394 return 0; 395 } 396 397 int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, 398 int reg_mcast, int unreg_mcast) 399 { 400 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 401 int idx; 402 403 idx = cpsw_ale_match_vlan(ale, vid); 404 if (idx >= 0) 405 cpsw_ale_read(ale, idx, ale_entry); 406 407 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN); 408 cpsw_ale_set_vlan_id(ale_entry, vid); 409 410 cpsw_ale_set_vlan_untag_force(ale_entry, untag); 411 cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast); 412 cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast); 413 cpsw_ale_set_vlan_member_list(ale_entry, port); 414 415 if (idx < 0) 416 idx = cpsw_ale_match_free(ale); 417 if (idx < 0) 418 idx = cpsw_ale_find_ageable(ale); 419 if (idx < 0) 420 return -ENOMEM; 421 422 cpsw_ale_write(ale, idx, ale_entry); 423 return 0; 424 } 425 426 int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) 427 { 428 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 429 int idx; 430 431 idx = cpsw_ale_match_vlan(ale, vid); 432 if (idx < 0) 433 return -ENOENT; 434 435 cpsw_ale_read(ale, idx, ale_entry); 436 437 if (port_mask) 438 cpsw_ale_set_vlan_member_list(ale_entry, port_mask); 439 else 440 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); 441 442 cpsw_ale_write(ale, idx, ale_entry); 443 return 0; 444 } 445 446 void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti) 447 { 448 u32 ale_entry[ALE_ENTRY_WORDS]; 449 int type, idx; 450 int unreg_mcast = 0; 451 452 /* Only bother doing the work if the setting is actually changing */ 453 if (ale->allmulti == allmulti) 454 return; 455 456 /* Remember the new setting to check against next time */ 457 ale->allmulti = allmulti; 458 459 for (idx = 0; idx < ale->params.ale_entries; idx++) { 460 cpsw_ale_read(ale, idx, ale_entry); 461 type = cpsw_ale_get_entry_type(ale_entry); 462 if (type != ALE_TYPE_VLAN) 463 continue; 464 465 unreg_mcast = cpsw_ale_get_vlan_unreg_mcast(ale_entry); 466 if (allmulti) 467 unreg_mcast |= 1; 468 else 469 unreg_mcast &= ~1; 470 cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast); 471 cpsw_ale_write(ale, idx, ale_entry); 472 } 473 } 474 475 struct ale_control_info { 476 const char *name; 477 int offset, port_offset; 478 int shift, port_shift; 479 int bits; 480 }; 481 482 static const struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = { 483 [ALE_ENABLE] = { 484 .name = "enable", 485 .offset = ALE_CONTROL, 486 .port_offset = 0, 487 .shift = 31, 488 .port_shift = 0, 489 .bits = 1, 490 }, 491 [ALE_CLEAR] = { 492 .name = "clear", 493 .offset = ALE_CONTROL, 494 .port_offset = 0, 495 .shift = 30, 496 .port_shift = 0, 497 .bits = 1, 498 }, 499 [ALE_AGEOUT] = { 500 .name = "ageout", 501 .offset = ALE_CONTROL, 502 .port_offset = 0, 503 .shift = 29, 504 .port_shift = 0, 505 .bits = 1, 506 }, 507 [ALE_P0_UNI_FLOOD] = { 508 .name = "port0_unicast_flood", 509 .offset = ALE_CONTROL, 510 .port_offset = 0, 511 .shift = 8, 512 .port_shift = 0, 513 .bits = 1, 514 }, 515 [ALE_VLAN_NOLEARN] = { 516 .name = "vlan_nolearn", 517 .offset = ALE_CONTROL, 518 .port_offset = 0, 519 .shift = 7, 520 .port_shift = 0, 521 .bits = 1, 522 }, 523 [ALE_NO_PORT_VLAN] = { 524 .name = "no_port_vlan", 525 .offset = ALE_CONTROL, 526 .port_offset = 0, 527 .shift = 6, 528 .port_shift = 0, 529 .bits = 1, 530 }, 531 [ALE_OUI_DENY] = { 532 .name = "oui_deny", 533 .offset = ALE_CONTROL, 534 .port_offset = 0, 535 .shift = 5, 536 .port_shift = 0, 537 .bits = 1, 538 }, 539 [ALE_BYPASS] = { 540 .name = "bypass", 541 .offset = ALE_CONTROL, 542 .port_offset = 0, 543 .shift = 4, 544 .port_shift = 0, 545 .bits = 1, 546 }, 547 [ALE_RATE_LIMIT_TX] = { 548 .name = "rate_limit_tx", 549 .offset = ALE_CONTROL, 550 .port_offset = 0, 551 .shift = 3, 552 .port_shift = 0, 553 .bits = 1, 554 }, 555 [ALE_VLAN_AWARE] = { 556 .name = "vlan_aware", 557 .offset = ALE_CONTROL, 558 .port_offset = 0, 559 .shift = 2, 560 .port_shift = 0, 561 .bits = 1, 562 }, 563 [ALE_AUTH_ENABLE] = { 564 .name = "auth_enable", 565 .offset = ALE_CONTROL, 566 .port_offset = 0, 567 .shift = 1, 568 .port_shift = 0, 569 .bits = 1, 570 }, 571 [ALE_RATE_LIMIT] = { 572 .name = "rate_limit", 573 .offset = ALE_CONTROL, 574 .port_offset = 0, 575 .shift = 0, 576 .port_shift = 0, 577 .bits = 1, 578 }, 579 [ALE_PORT_STATE] = { 580 .name = "port_state", 581 .offset = ALE_PORTCTL, 582 .port_offset = 4, 583 .shift = 0, 584 .port_shift = 0, 585 .bits = 2, 586 }, 587 [ALE_PORT_DROP_UNTAGGED] = { 588 .name = "drop_untagged", 589 .offset = ALE_PORTCTL, 590 .port_offset = 4, 591 .shift = 2, 592 .port_shift = 0, 593 .bits = 1, 594 }, 595 [ALE_PORT_DROP_UNKNOWN_VLAN] = { 596 .name = "drop_unknown", 597 .offset = ALE_PORTCTL, 598 .port_offset = 4, 599 .shift = 3, 600 .port_shift = 0, 601 .bits = 1, 602 }, 603 [ALE_PORT_NOLEARN] = { 604 .name = "nolearn", 605 .offset = ALE_PORTCTL, 606 .port_offset = 4, 607 .shift = 4, 608 .port_shift = 0, 609 .bits = 1, 610 }, 611 [ALE_PORT_NO_SA_UPDATE] = { 612 .name = "no_source_update", 613 .offset = ALE_PORTCTL, 614 .port_offset = 4, 615 .shift = 5, 616 .port_shift = 0, 617 .bits = 1, 618 }, 619 [ALE_PORT_MCAST_LIMIT] = { 620 .name = "mcast_limit", 621 .offset = ALE_PORTCTL, 622 .port_offset = 4, 623 .shift = 16, 624 .port_shift = 0, 625 .bits = 8, 626 }, 627 [ALE_PORT_BCAST_LIMIT] = { 628 .name = "bcast_limit", 629 .offset = ALE_PORTCTL, 630 .port_offset = 4, 631 .shift = 24, 632 .port_shift = 0, 633 .bits = 8, 634 }, 635 [ALE_PORT_UNKNOWN_VLAN_MEMBER] = { 636 .name = "unknown_vlan_member", 637 .offset = ALE_UNKNOWNVLAN, 638 .port_offset = 0, 639 .shift = 0, 640 .port_shift = 0, 641 .bits = 6, 642 }, 643 [ALE_PORT_UNKNOWN_MCAST_FLOOD] = { 644 .name = "unknown_mcast_flood", 645 .offset = ALE_UNKNOWNVLAN, 646 .port_offset = 0, 647 .shift = 8, 648 .port_shift = 0, 649 .bits = 6, 650 }, 651 [ALE_PORT_UNKNOWN_REG_MCAST_FLOOD] = { 652 .name = "unknown_reg_flood", 653 .offset = ALE_UNKNOWNVLAN, 654 .port_offset = 0, 655 .shift = 16, 656 .port_shift = 0, 657 .bits = 6, 658 }, 659 [ALE_PORT_UNTAGGED_EGRESS] = { 660 .name = "untagged_egress", 661 .offset = ALE_UNKNOWNVLAN, 662 .port_offset = 0, 663 .shift = 24, 664 .port_shift = 0, 665 .bits = 6, 666 }, 667 }; 668 669 int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control, 670 int value) 671 { 672 const struct ale_control_info *info; 673 int offset, shift; 674 u32 tmp, mask; 675 676 if (control < 0 || control >= ARRAY_SIZE(ale_controls)) 677 return -EINVAL; 678 679 info = &ale_controls[control]; 680 if (info->port_offset == 0 && info->port_shift == 0) 681 port = 0; /* global, port is a dont care */ 682 683 if (port < 0 || port > ale->params.ale_ports) 684 return -EINVAL; 685 686 mask = BITMASK(info->bits); 687 if (value & ~mask) 688 return -EINVAL; 689 690 offset = info->offset + (port * info->port_offset); 691 shift = info->shift + (port * info->port_shift); 692 693 tmp = __raw_readl(ale->params.ale_regs + offset); 694 tmp = (tmp & ~(mask << shift)) | (value << shift); 695 __raw_writel(tmp, ale->params.ale_regs + offset); 696 697 return 0; 698 } 699 700 int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) 701 { 702 const struct ale_control_info *info; 703 int offset, shift; 704 u32 tmp; 705 706 if (control < 0 || control >= ARRAY_SIZE(ale_controls)) 707 return -EINVAL; 708 709 info = &ale_controls[control]; 710 if (info->port_offset == 0 && info->port_shift == 0) 711 port = 0; /* global, port is a dont care */ 712 713 if (port < 0 || port > ale->params.ale_ports) 714 return -EINVAL; 715 716 offset = info->offset + (port * info->port_offset); 717 shift = info->shift + (port * info->port_shift); 718 719 tmp = __raw_readl(ale->params.ale_regs + offset) >> shift; 720 return tmp & BITMASK(info->bits); 721 } 722 723 static void cpsw_ale_timer(unsigned long arg) 724 { 725 struct cpsw_ale *ale = (struct cpsw_ale *)arg; 726 727 cpsw_ale_control_set(ale, 0, ALE_AGEOUT, 1); 728 729 if (ale->ageout) { 730 ale->timer.expires = jiffies + ale->ageout; 731 add_timer(&ale->timer); 732 } 733 } 734 735 int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout) 736 { 737 del_timer_sync(&ale->timer); 738 ale->ageout = ageout * HZ; 739 if (ale->ageout) { 740 ale->timer.expires = jiffies + ale->ageout; 741 add_timer(&ale->timer); 742 } 743 return 0; 744 } 745 746 void cpsw_ale_start(struct cpsw_ale *ale) 747 { 748 u32 rev; 749 750 rev = __raw_readl(ale->params.ale_regs + ALE_IDVER); 751 dev_dbg(ale->params.dev, "initialized cpsw ale revision %d.%d\n", 752 ALE_VERSION_MAJOR(rev), ALE_VERSION_MINOR(rev)); 753 cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1); 754 cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); 755 756 init_timer(&ale->timer); 757 ale->timer.data = (unsigned long)ale; 758 ale->timer.function = cpsw_ale_timer; 759 if (ale->ageout) { 760 ale->timer.expires = jiffies + ale->ageout; 761 add_timer(&ale->timer); 762 } 763 } 764 765 void cpsw_ale_stop(struct cpsw_ale *ale) 766 { 767 del_timer_sync(&ale->timer); 768 } 769 770 struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) 771 { 772 struct cpsw_ale *ale; 773 774 ale = kzalloc(sizeof(*ale), GFP_KERNEL); 775 if (!ale) 776 return NULL; 777 778 ale->params = *params; 779 ale->ageout = ale->params.ale_ageout * HZ; 780 781 return ale; 782 } 783 784 int cpsw_ale_destroy(struct cpsw_ale *ale) 785 { 786 if (!ale) 787 return -EINVAL; 788 cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0); 789 kfree(ale); 790 return 0; 791 } 792 793 void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) 794 { 795 int i; 796 797 for (i = 0; i < ale->params.ale_entries; i++) { 798 cpsw_ale_read(ale, i, data); 799 data += ALE_ENTRY_WORDS; 800 } 801 } 802