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 struct ale_control_info { 447 const char *name; 448 int offset, port_offset; 449 int shift, port_shift; 450 int bits; 451 }; 452 453 static const struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = { 454 [ALE_ENABLE] = { 455 .name = "enable", 456 .offset = ALE_CONTROL, 457 .port_offset = 0, 458 .shift = 31, 459 .port_shift = 0, 460 .bits = 1, 461 }, 462 [ALE_CLEAR] = { 463 .name = "clear", 464 .offset = ALE_CONTROL, 465 .port_offset = 0, 466 .shift = 30, 467 .port_shift = 0, 468 .bits = 1, 469 }, 470 [ALE_AGEOUT] = { 471 .name = "ageout", 472 .offset = ALE_CONTROL, 473 .port_offset = 0, 474 .shift = 29, 475 .port_shift = 0, 476 .bits = 1, 477 }, 478 [ALE_P0_UNI_FLOOD] = { 479 .name = "port0_unicast_flood", 480 .offset = ALE_CONTROL, 481 .port_offset = 0, 482 .shift = 8, 483 .port_shift = 0, 484 .bits = 1, 485 }, 486 [ALE_VLAN_NOLEARN] = { 487 .name = "vlan_nolearn", 488 .offset = ALE_CONTROL, 489 .port_offset = 0, 490 .shift = 7, 491 .port_shift = 0, 492 .bits = 1, 493 }, 494 [ALE_NO_PORT_VLAN] = { 495 .name = "no_port_vlan", 496 .offset = ALE_CONTROL, 497 .port_offset = 0, 498 .shift = 6, 499 .port_shift = 0, 500 .bits = 1, 501 }, 502 [ALE_OUI_DENY] = { 503 .name = "oui_deny", 504 .offset = ALE_CONTROL, 505 .port_offset = 0, 506 .shift = 5, 507 .port_shift = 0, 508 .bits = 1, 509 }, 510 [ALE_BYPASS] = { 511 .name = "bypass", 512 .offset = ALE_CONTROL, 513 .port_offset = 0, 514 .shift = 4, 515 .port_shift = 0, 516 .bits = 1, 517 }, 518 [ALE_RATE_LIMIT_TX] = { 519 .name = "rate_limit_tx", 520 .offset = ALE_CONTROL, 521 .port_offset = 0, 522 .shift = 3, 523 .port_shift = 0, 524 .bits = 1, 525 }, 526 [ALE_VLAN_AWARE] = { 527 .name = "vlan_aware", 528 .offset = ALE_CONTROL, 529 .port_offset = 0, 530 .shift = 2, 531 .port_shift = 0, 532 .bits = 1, 533 }, 534 [ALE_AUTH_ENABLE] = { 535 .name = "auth_enable", 536 .offset = ALE_CONTROL, 537 .port_offset = 0, 538 .shift = 1, 539 .port_shift = 0, 540 .bits = 1, 541 }, 542 [ALE_RATE_LIMIT] = { 543 .name = "rate_limit", 544 .offset = ALE_CONTROL, 545 .port_offset = 0, 546 .shift = 0, 547 .port_shift = 0, 548 .bits = 1, 549 }, 550 [ALE_PORT_STATE] = { 551 .name = "port_state", 552 .offset = ALE_PORTCTL, 553 .port_offset = 4, 554 .shift = 0, 555 .port_shift = 0, 556 .bits = 2, 557 }, 558 [ALE_PORT_DROP_UNTAGGED] = { 559 .name = "drop_untagged", 560 .offset = ALE_PORTCTL, 561 .port_offset = 4, 562 .shift = 2, 563 .port_shift = 0, 564 .bits = 1, 565 }, 566 [ALE_PORT_DROP_UNKNOWN_VLAN] = { 567 .name = "drop_unknown", 568 .offset = ALE_PORTCTL, 569 .port_offset = 4, 570 .shift = 3, 571 .port_shift = 0, 572 .bits = 1, 573 }, 574 [ALE_PORT_NOLEARN] = { 575 .name = "nolearn", 576 .offset = ALE_PORTCTL, 577 .port_offset = 4, 578 .shift = 4, 579 .port_shift = 0, 580 .bits = 1, 581 }, 582 [ALE_PORT_NO_SA_UPDATE] = { 583 .name = "no_source_update", 584 .offset = ALE_PORTCTL, 585 .port_offset = 4, 586 .shift = 5, 587 .port_shift = 0, 588 .bits = 1, 589 }, 590 [ALE_PORT_MCAST_LIMIT] = { 591 .name = "mcast_limit", 592 .offset = ALE_PORTCTL, 593 .port_offset = 4, 594 .shift = 16, 595 .port_shift = 0, 596 .bits = 8, 597 }, 598 [ALE_PORT_BCAST_LIMIT] = { 599 .name = "bcast_limit", 600 .offset = ALE_PORTCTL, 601 .port_offset = 4, 602 .shift = 24, 603 .port_shift = 0, 604 .bits = 8, 605 }, 606 [ALE_PORT_UNKNOWN_VLAN_MEMBER] = { 607 .name = "unknown_vlan_member", 608 .offset = ALE_UNKNOWNVLAN, 609 .port_offset = 0, 610 .shift = 0, 611 .port_shift = 0, 612 .bits = 6, 613 }, 614 [ALE_PORT_UNKNOWN_MCAST_FLOOD] = { 615 .name = "unknown_mcast_flood", 616 .offset = ALE_UNKNOWNVLAN, 617 .port_offset = 0, 618 .shift = 8, 619 .port_shift = 0, 620 .bits = 6, 621 }, 622 [ALE_PORT_UNKNOWN_REG_MCAST_FLOOD] = { 623 .name = "unknown_reg_flood", 624 .offset = ALE_UNKNOWNVLAN, 625 .port_offset = 0, 626 .shift = 16, 627 .port_shift = 0, 628 .bits = 6, 629 }, 630 [ALE_PORT_UNTAGGED_EGRESS] = { 631 .name = "untagged_egress", 632 .offset = ALE_UNKNOWNVLAN, 633 .port_offset = 0, 634 .shift = 24, 635 .port_shift = 0, 636 .bits = 6, 637 }, 638 }; 639 640 int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control, 641 int value) 642 { 643 const struct ale_control_info *info; 644 int offset, shift; 645 u32 tmp, mask; 646 647 if (control < 0 || control >= ARRAY_SIZE(ale_controls)) 648 return -EINVAL; 649 650 info = &ale_controls[control]; 651 if (info->port_offset == 0 && info->port_shift == 0) 652 port = 0; /* global, port is a dont care */ 653 654 if (port < 0 || port > ale->params.ale_ports) 655 return -EINVAL; 656 657 mask = BITMASK(info->bits); 658 if (value & ~mask) 659 return -EINVAL; 660 661 offset = info->offset + (port * info->port_offset); 662 shift = info->shift + (port * info->port_shift); 663 664 tmp = __raw_readl(ale->params.ale_regs + offset); 665 tmp = (tmp & ~(mask << shift)) | (value << shift); 666 __raw_writel(tmp, ale->params.ale_regs + offset); 667 668 return 0; 669 } 670 671 int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) 672 { 673 const struct ale_control_info *info; 674 int offset, shift; 675 u32 tmp; 676 677 if (control < 0 || control >= ARRAY_SIZE(ale_controls)) 678 return -EINVAL; 679 680 info = &ale_controls[control]; 681 if (info->port_offset == 0 && info->port_shift == 0) 682 port = 0; /* global, port is a dont care */ 683 684 if (port < 0 || port > ale->params.ale_ports) 685 return -EINVAL; 686 687 offset = info->offset + (port * info->port_offset); 688 shift = info->shift + (port * info->port_shift); 689 690 tmp = __raw_readl(ale->params.ale_regs + offset) >> shift; 691 return tmp & BITMASK(info->bits); 692 } 693 694 static void cpsw_ale_timer(unsigned long arg) 695 { 696 struct cpsw_ale *ale = (struct cpsw_ale *)arg; 697 698 cpsw_ale_control_set(ale, 0, ALE_AGEOUT, 1); 699 700 if (ale->ageout) { 701 ale->timer.expires = jiffies + ale->ageout; 702 add_timer(&ale->timer); 703 } 704 } 705 706 int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout) 707 { 708 del_timer_sync(&ale->timer); 709 ale->ageout = ageout * HZ; 710 if (ale->ageout) { 711 ale->timer.expires = jiffies + ale->ageout; 712 add_timer(&ale->timer); 713 } 714 return 0; 715 } 716 717 void cpsw_ale_start(struct cpsw_ale *ale) 718 { 719 u32 rev; 720 721 rev = __raw_readl(ale->params.ale_regs + ALE_IDVER); 722 dev_dbg(ale->params.dev, "initialized cpsw ale revision %d.%d\n", 723 ALE_VERSION_MAJOR(rev), ALE_VERSION_MINOR(rev)); 724 cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1); 725 cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); 726 727 init_timer(&ale->timer); 728 ale->timer.data = (unsigned long)ale; 729 ale->timer.function = cpsw_ale_timer; 730 if (ale->ageout) { 731 ale->timer.expires = jiffies + ale->ageout; 732 add_timer(&ale->timer); 733 } 734 } 735 736 void cpsw_ale_stop(struct cpsw_ale *ale) 737 { 738 del_timer_sync(&ale->timer); 739 } 740 741 struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) 742 { 743 struct cpsw_ale *ale; 744 745 ale = kzalloc(sizeof(*ale), GFP_KERNEL); 746 if (!ale) 747 return NULL; 748 749 ale->params = *params; 750 ale->ageout = ale->params.ale_ageout * HZ; 751 752 return ale; 753 } 754 755 int cpsw_ale_destroy(struct cpsw_ale *ale) 756 { 757 if (!ale) 758 return -EINVAL; 759 cpsw_ale_stop(ale); 760 cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0); 761 kfree(ale); 762 return 0; 763 } 764 765 void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) 766 { 767 int i; 768 769 for (i = 0; i < ale->params.ale_entries; i++) { 770 cpsw_ale_read(ale, i, data); 771 data += ALE_ENTRY_WORDS; 772 } 773 } 774