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 #define ALE_ENTRY_BITS 68 29 #define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) 30 31 #define ALE_VERSION_MAJOR(rev) ((rev >> 8) & 0xff) 32 #define ALE_VERSION_MINOR(rev) (rev & 0xff) 33 34 /* ALE Registers */ 35 #define ALE_IDVER 0x00 36 #define ALE_CONTROL 0x08 37 #define ALE_PRESCALE 0x10 38 #define ALE_UNKNOWNVLAN 0x18 39 #define ALE_TABLE_CONTROL 0x20 40 #define ALE_TABLE 0x34 41 #define ALE_PORTCTL 0x40 42 43 #define ALE_TABLE_WRITE BIT(31) 44 45 #define ALE_TYPE_FREE 0 46 #define ALE_TYPE_ADDR 1 47 #define ALE_TYPE_VLAN 2 48 #define ALE_TYPE_VLAN_ADDR 3 49 50 #define ALE_UCAST_PERSISTANT 0 51 #define ALE_UCAST_UNTOUCHED 1 52 #define ALE_UCAST_OUI 2 53 #define ALE_UCAST_TOUCHED 3 54 55 static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) 56 { 57 int idx; 58 59 idx = start / 32; 60 start -= idx * 32; 61 idx = 2 - idx; /* flip */ 62 return (ale_entry[idx] >> start) & BITMASK(bits); 63 } 64 65 static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits, 66 u32 value) 67 { 68 int idx; 69 70 value &= BITMASK(bits); 71 idx = start / 32; 72 start -= idx * 32; 73 idx = 2 - idx; /* flip */ 74 ale_entry[idx] &= ~(BITMASK(bits) << start); 75 ale_entry[idx] |= (value << start); 76 } 77 78 #define DEFINE_ALE_FIELD(name, start, bits) \ 79 static inline int cpsw_ale_get_##name(u32 *ale_entry) \ 80 { \ 81 return cpsw_ale_get_field(ale_entry, start, bits); \ 82 } \ 83 static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value) \ 84 { \ 85 cpsw_ale_set_field(ale_entry, start, bits, value); \ 86 } 87 88 DEFINE_ALE_FIELD(entry_type, 60, 2) 89 DEFINE_ALE_FIELD(vlan_id, 48, 12) 90 DEFINE_ALE_FIELD(mcast_state, 62, 2) 91 DEFINE_ALE_FIELD(port_mask, 66, 3) 92 DEFINE_ALE_FIELD(super, 65, 1) 93 DEFINE_ALE_FIELD(ucast_type, 62, 2) 94 DEFINE_ALE_FIELD(port_num, 66, 2) 95 DEFINE_ALE_FIELD(blocked, 65, 1) 96 DEFINE_ALE_FIELD(secure, 64, 1) 97 DEFINE_ALE_FIELD(vlan_untag_force, 24, 3) 98 DEFINE_ALE_FIELD(vlan_reg_mcast, 16, 3) 99 DEFINE_ALE_FIELD(vlan_unreg_mcast, 8, 3) 100 DEFINE_ALE_FIELD(vlan_member_list, 0, 3) 101 DEFINE_ALE_FIELD(mcast, 40, 1) 102 103 /* The MAC address field in the ALE entry cannot be macroized as above */ 104 static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) 105 { 106 int i; 107 108 for (i = 0; i < 6; i++) 109 addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8); 110 } 111 112 static inline void cpsw_ale_set_addr(u32 *ale_entry, u8 *addr) 113 { 114 int i; 115 116 for (i = 0; i < 6; i++) 117 cpsw_ale_set_field(ale_entry, 40 - 8*i, 8, addr[i]); 118 } 119 120 static int cpsw_ale_read(struct cpsw_ale *ale, int idx, u32 *ale_entry) 121 { 122 int i; 123 124 WARN_ON(idx > ale->params.ale_entries); 125 126 __raw_writel(idx, ale->params.ale_regs + ALE_TABLE_CONTROL); 127 128 for (i = 0; i < ALE_ENTRY_WORDS; i++) 129 ale_entry[i] = __raw_readl(ale->params.ale_regs + 130 ALE_TABLE + 4 * i); 131 132 return idx; 133 } 134 135 static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry) 136 { 137 int i; 138 139 WARN_ON(idx > ale->params.ale_entries); 140 141 for (i = 0; i < ALE_ENTRY_WORDS; i++) 142 __raw_writel(ale_entry[i], ale->params.ale_regs + 143 ALE_TABLE + 4 * i); 144 145 __raw_writel(idx | ALE_TABLE_WRITE, ale->params.ale_regs + 146 ALE_TABLE_CONTROL); 147 148 return idx; 149 } 150 151 int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid) 152 { 153 u32 ale_entry[ALE_ENTRY_WORDS]; 154 int type, idx; 155 156 for (idx = 0; idx < ale->params.ale_entries; idx++) { 157 u8 entry_addr[6]; 158 159 cpsw_ale_read(ale, idx, ale_entry); 160 type = cpsw_ale_get_entry_type(ale_entry); 161 if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR) 162 continue; 163 if (cpsw_ale_get_vlan_id(ale_entry) != vid) 164 continue; 165 cpsw_ale_get_addr(ale_entry, entry_addr); 166 if (memcmp(entry_addr, addr, 6) == 0) 167 return idx; 168 } 169 return -ENOENT; 170 } 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 188 static int cpsw_ale_match_free(struct cpsw_ale *ale) 189 { 190 u32 ale_entry[ALE_ENTRY_WORDS]; 191 int type, idx; 192 193 for (idx = 0; idx < ale->params.ale_entries; idx++) { 194 cpsw_ale_read(ale, idx, ale_entry); 195 type = cpsw_ale_get_entry_type(ale_entry); 196 if (type == ALE_TYPE_FREE) 197 return idx; 198 } 199 return -ENOENT; 200 } 201 202 static int cpsw_ale_find_ageable(struct cpsw_ale *ale) 203 { 204 u32 ale_entry[ALE_ENTRY_WORDS]; 205 int type, idx; 206 207 for (idx = 0; idx < ale->params.ale_entries; idx++) { 208 cpsw_ale_read(ale, idx, ale_entry); 209 type = cpsw_ale_get_entry_type(ale_entry); 210 if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR) 211 continue; 212 if (cpsw_ale_get_mcast(ale_entry)) 213 continue; 214 type = cpsw_ale_get_ucast_type(ale_entry); 215 if (type != ALE_UCAST_PERSISTANT && 216 type != ALE_UCAST_OUI) 217 return idx; 218 } 219 return -ENOENT; 220 } 221 222 static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry, 223 int port_mask) 224 { 225 int mask; 226 227 mask = cpsw_ale_get_port_mask(ale_entry); 228 if ((mask & port_mask) == 0) 229 return; /* ports dont intersect, not interested */ 230 mask &= ~port_mask; 231 232 /* free if only remaining port is host port */ 233 if (mask) 234 cpsw_ale_set_port_mask(ale_entry, mask); 235 else 236 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); 237 } 238 239 int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask) 240 { 241 u32 ale_entry[ALE_ENTRY_WORDS]; 242 int ret, idx; 243 244 for (idx = 0; idx < ale->params.ale_entries; idx++) { 245 cpsw_ale_read(ale, idx, ale_entry); 246 ret = cpsw_ale_get_entry_type(ale_entry); 247 if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR) 248 continue; 249 250 if (cpsw_ale_get_mcast(ale_entry)) { 251 u8 addr[6]; 252 253 cpsw_ale_get_addr(ale_entry, addr); 254 if (!is_broadcast_ether_addr(addr)) 255 cpsw_ale_flush_mcast(ale, ale_entry, port_mask); 256 } 257 258 cpsw_ale_write(ale, idx, ale_entry); 259 } 260 return 0; 261 } 262 263 static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry, 264 int port_mask) 265 { 266 int port; 267 268 port = cpsw_ale_get_port_num(ale_entry); 269 if ((BIT(port) & port_mask) == 0) 270 return; /* ports dont intersect, not interested */ 271 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); 272 } 273 274 int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask) 275 { 276 u32 ale_entry[ALE_ENTRY_WORDS]; 277 int ret, idx; 278 279 for (idx = 0; idx < ale->params.ale_entries; idx++) { 280 cpsw_ale_read(ale, idx, ale_entry); 281 ret = cpsw_ale_get_entry_type(ale_entry); 282 if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR) 283 continue; 284 285 if (cpsw_ale_get_mcast(ale_entry)) 286 cpsw_ale_flush_mcast(ale, ale_entry, port_mask); 287 else 288 cpsw_ale_flush_ucast(ale, ale_entry, port_mask); 289 290 cpsw_ale_write(ale, idx, ale_entry); 291 } 292 return 0; 293 } 294 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) 308 { 309 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 310 int idx; 311 312 cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid); 313 314 cpsw_ale_set_addr(ale_entry, addr); 315 cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT); 316 cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0); 317 cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); 318 cpsw_ale_set_port_num(ale_entry, port); 319 320 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); 321 if (idx < 0) 322 idx = cpsw_ale_match_free(ale); 323 if (idx < 0) 324 idx = cpsw_ale_find_ageable(ale); 325 if (idx < 0) 326 return -ENOMEM; 327 328 cpsw_ale_write(ale, idx, ale_entry); 329 return 0; 330 } 331 332 int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, 333 int flags, u16 vid) 334 { 335 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 336 int idx; 337 338 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); 339 if (idx < 0) 340 return -ENOENT; 341 342 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); 343 cpsw_ale_write(ale, idx, ale_entry); 344 return 0; 345 } 346 347 int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, 348 int flags, u16 vid, int mcast_state) 349 { 350 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 351 int idx, mask; 352 353 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); 354 if (idx >= 0) 355 cpsw_ale_read(ale, idx, ale_entry); 356 357 cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid); 358 359 cpsw_ale_set_addr(ale_entry, addr); 360 cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); 361 cpsw_ale_set_mcast_state(ale_entry, mcast_state); 362 363 mask = cpsw_ale_get_port_mask(ale_entry); 364 port_mask |= mask; 365 cpsw_ale_set_port_mask(ale_entry, port_mask); 366 367 if (idx < 0) 368 idx = cpsw_ale_match_free(ale); 369 if (idx < 0) 370 idx = cpsw_ale_find_ageable(ale); 371 if (idx < 0) 372 return -ENOMEM; 373 374 cpsw_ale_write(ale, idx, ale_entry); 375 return 0; 376 } 377 378 int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, 379 int flags, u16 vid) 380 { 381 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; 382 int idx; 383 384 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); 385 if (idx < 0) 386 return -EINVAL; 387 388 cpsw_ale_read(ale, idx, ale_entry); 389 390 if (port_mask) 391 cpsw_ale_set_port_mask(ale_entry, port_mask); 392 else 393 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); 394 395 cpsw_ale_write(ale, idx, ale_entry); 396 return 0; 397 } 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 448 struct ale_control_info { 449 const char *name; 450 int offset, port_offset; 451 int shift, port_shift; 452 int bits; 453 }; 454 455 static const struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = { 456 [ALE_ENABLE] = { 457 .name = "enable", 458 .offset = ALE_CONTROL, 459 .port_offset = 0, 460 .shift = 31, 461 .port_shift = 0, 462 .bits = 1, 463 }, 464 [ALE_CLEAR] = { 465 .name = "clear", 466 .offset = ALE_CONTROL, 467 .port_offset = 0, 468 .shift = 30, 469 .port_shift = 0, 470 .bits = 1, 471 }, 472 [ALE_AGEOUT] = { 473 .name = "ageout", 474 .offset = ALE_CONTROL, 475 .port_offset = 0, 476 .shift = 29, 477 .port_shift = 0, 478 .bits = 1, 479 }, 480 [ALE_VLAN_NOLEARN] = { 481 .name = "vlan_nolearn", 482 .offset = ALE_CONTROL, 483 .port_offset = 0, 484 .shift = 7, 485 .port_shift = 0, 486 .bits = 1, 487 }, 488 [ALE_NO_PORT_VLAN] = { 489 .name = "no_port_vlan", 490 .offset = ALE_CONTROL, 491 .port_offset = 0, 492 .shift = 6, 493 .port_shift = 0, 494 .bits = 1, 495 }, 496 [ALE_OUI_DENY] = { 497 .name = "oui_deny", 498 .offset = ALE_CONTROL, 499 .port_offset = 0, 500 .shift = 5, 501 .port_shift = 0, 502 .bits = 1, 503 }, 504 [ALE_BYPASS] = { 505 .name = "bypass", 506 .offset = ALE_CONTROL, 507 .port_offset = 0, 508 .shift = 4, 509 .port_shift = 0, 510 .bits = 1, 511 }, 512 [ALE_RATE_LIMIT_TX] = { 513 .name = "rate_limit_tx", 514 .offset = ALE_CONTROL, 515 .port_offset = 0, 516 .shift = 3, 517 .port_shift = 0, 518 .bits = 1, 519 }, 520 [ALE_VLAN_AWARE] = { 521 .name = "vlan_aware", 522 .offset = ALE_CONTROL, 523 .port_offset = 0, 524 .shift = 2, 525 .port_shift = 0, 526 .bits = 1, 527 }, 528 [ALE_AUTH_ENABLE] = { 529 .name = "auth_enable", 530 .offset = ALE_CONTROL, 531 .port_offset = 0, 532 .shift = 1, 533 .port_shift = 0, 534 .bits = 1, 535 }, 536 [ALE_RATE_LIMIT] = { 537 .name = "rate_limit", 538 .offset = ALE_CONTROL, 539 .port_offset = 0, 540 .shift = 0, 541 .port_shift = 0, 542 .bits = 1, 543 }, 544 [ALE_PORT_STATE] = { 545 .name = "port_state", 546 .offset = ALE_PORTCTL, 547 .port_offset = 4, 548 .shift = 0, 549 .port_shift = 0, 550 .bits = 2, 551 }, 552 [ALE_PORT_DROP_UNTAGGED] = { 553 .name = "drop_untagged", 554 .offset = ALE_PORTCTL, 555 .port_offset = 4, 556 .shift = 2, 557 .port_shift = 0, 558 .bits = 1, 559 }, 560 [ALE_PORT_DROP_UNKNOWN_VLAN] = { 561 .name = "drop_unknown", 562 .offset = ALE_PORTCTL, 563 .port_offset = 4, 564 .shift = 3, 565 .port_shift = 0, 566 .bits = 1, 567 }, 568 [ALE_PORT_NOLEARN] = { 569 .name = "nolearn", 570 .offset = ALE_PORTCTL, 571 .port_offset = 4, 572 .shift = 4, 573 .port_shift = 0, 574 .bits = 1, 575 }, 576 [ALE_PORT_MCAST_LIMIT] = { 577 .name = "mcast_limit", 578 .offset = ALE_PORTCTL, 579 .port_offset = 4, 580 .shift = 16, 581 .port_shift = 0, 582 .bits = 8, 583 }, 584 [ALE_PORT_BCAST_LIMIT] = { 585 .name = "bcast_limit", 586 .offset = ALE_PORTCTL, 587 .port_offset = 4, 588 .shift = 24, 589 .port_shift = 0, 590 .bits = 8, 591 }, 592 [ALE_PORT_UNKNOWN_VLAN_MEMBER] = { 593 .name = "unknown_vlan_member", 594 .offset = ALE_UNKNOWNVLAN, 595 .port_offset = 0, 596 .shift = 0, 597 .port_shift = 0, 598 .bits = 6, 599 }, 600 [ALE_PORT_UNKNOWN_MCAST_FLOOD] = { 601 .name = "unknown_mcast_flood", 602 .offset = ALE_UNKNOWNVLAN, 603 .port_offset = 0, 604 .shift = 8, 605 .port_shift = 0, 606 .bits = 6, 607 }, 608 [ALE_PORT_UNKNOWN_REG_MCAST_FLOOD] = { 609 .name = "unknown_reg_flood", 610 .offset = ALE_UNKNOWNVLAN, 611 .port_offset = 0, 612 .shift = 16, 613 .port_shift = 0, 614 .bits = 6, 615 }, 616 [ALE_PORT_UNTAGGED_EGRESS] = { 617 .name = "untagged_egress", 618 .offset = ALE_UNKNOWNVLAN, 619 .port_offset = 0, 620 .shift = 24, 621 .port_shift = 0, 622 .bits = 6, 623 }, 624 }; 625 626 int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control, 627 int value) 628 { 629 const struct ale_control_info *info; 630 int offset, shift; 631 u32 tmp, mask; 632 633 if (control < 0 || control >= ARRAY_SIZE(ale_controls)) 634 return -EINVAL; 635 636 info = &ale_controls[control]; 637 if (info->port_offset == 0 && info->port_shift == 0) 638 port = 0; /* global, port is a dont care */ 639 640 if (port < 0 || port > ale->params.ale_ports) 641 return -EINVAL; 642 643 mask = BITMASK(info->bits); 644 if (value & ~mask) 645 return -EINVAL; 646 647 offset = info->offset + (port * info->port_offset); 648 shift = info->shift + (port * info->port_shift); 649 650 tmp = __raw_readl(ale->params.ale_regs + offset); 651 tmp = (tmp & ~(mask << shift)) | (value << shift); 652 __raw_writel(tmp, ale->params.ale_regs + offset); 653 654 return 0; 655 } 656 657 int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) 658 { 659 const struct ale_control_info *info; 660 int offset, shift; 661 u32 tmp; 662 663 if (control < 0 || control >= ARRAY_SIZE(ale_controls)) 664 return -EINVAL; 665 666 info = &ale_controls[control]; 667 if (info->port_offset == 0 && info->port_shift == 0) 668 port = 0; /* global, port is a dont care */ 669 670 if (port < 0 || port > ale->params.ale_ports) 671 return -EINVAL; 672 673 offset = info->offset + (port * info->port_offset); 674 shift = info->shift + (port * info->port_shift); 675 676 tmp = __raw_readl(ale->params.ale_regs + offset) >> shift; 677 return tmp & BITMASK(info->bits); 678 } 679 680 static void cpsw_ale_timer(unsigned long arg) 681 { 682 struct cpsw_ale *ale = (struct cpsw_ale *)arg; 683 684 cpsw_ale_control_set(ale, 0, ALE_AGEOUT, 1); 685 686 if (ale->ageout) { 687 ale->timer.expires = jiffies + ale->ageout; 688 add_timer(&ale->timer); 689 } 690 } 691 692 int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout) 693 { 694 del_timer_sync(&ale->timer); 695 ale->ageout = ageout * HZ; 696 if (ale->ageout) { 697 ale->timer.expires = jiffies + ale->ageout; 698 add_timer(&ale->timer); 699 } 700 return 0; 701 } 702 703 void cpsw_ale_start(struct cpsw_ale *ale) 704 { 705 u32 rev; 706 707 rev = __raw_readl(ale->params.ale_regs + ALE_IDVER); 708 dev_dbg(ale->params.dev, "initialized cpsw ale revision %d.%d\n", 709 ALE_VERSION_MAJOR(rev), ALE_VERSION_MINOR(rev)); 710 cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1); 711 cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); 712 713 init_timer(&ale->timer); 714 ale->timer.data = (unsigned long)ale; 715 ale->timer.function = cpsw_ale_timer; 716 if (ale->ageout) { 717 ale->timer.expires = jiffies + ale->ageout; 718 add_timer(&ale->timer); 719 } 720 } 721 722 void cpsw_ale_stop(struct cpsw_ale *ale) 723 { 724 del_timer_sync(&ale->timer); 725 } 726 727 struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) 728 { 729 struct cpsw_ale *ale; 730 731 ale = kzalloc(sizeof(*ale), GFP_KERNEL); 732 if (!ale) 733 return NULL; 734 735 ale->params = *params; 736 ale->ageout = ale->params.ale_ageout * HZ; 737 738 return ale; 739 } 740 741 int cpsw_ale_destroy(struct cpsw_ale *ale) 742 { 743 if (!ale) 744 return -EINVAL; 745 cpsw_ale_stop(ale); 746 cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0); 747 kfree(ale); 748 return 0; 749 } 750