1/*- 2 * Copyright 2007-2009 Solarflare Communications Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD$"); 28 29#include "efsys.h" 30#include "efx.h" 31#include "efx_types.h" 32#include "efx_regs.h" 33#include "efx_impl.h" 34 35 36#if EFSYS_OPT_FILTER 37 38/* "Fudge factors" - difference between programmed value and actual depth. 39 * Due to pipelined implementation we need to program H/W with a value that 40 * is larger than the hop limit we want. 41 */ 42#define FILTER_CTL_SRCH_FUDGE_WILD 3 43#define FILTER_CTL_SRCH_FUDGE_FULL 1 44 45/* Hard maximum hop limit. Hardware will time-out beyond 200-something. 46 * We also need to avoid infinite loops in efx_filter_search() when the 47 * table is full. 48 */ 49#define FILTER_CTL_SRCH_MAX 200 50 51/* The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit 52 * key derived from the n-tuple. */ 53static uint16_t 54efx_filter_tbl_hash( 55 __in uint32_t key) 56{ 57 uint16_t tmp; 58 59 /* First 16 rounds */ 60 tmp = 0x1fff ^ (uint16_t)(key >> 16); 61 tmp = tmp ^ tmp >> 3 ^ tmp >> 6; 62 tmp = tmp ^ tmp >> 9; 63 64 /* Last 16 rounds */ 65 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff); 66 tmp = tmp ^ tmp >> 3 ^ tmp >> 6; 67 tmp = tmp ^ tmp >> 9; 68 69 return (tmp); 70} 71 72 73/* To allow for hash collisions, filter search continues at these 74 * increments from the first possible entry selected by the hash. */ 75static uint16_t 76efx_filter_tbl_increment( 77 __in uint32_t key) 78{ 79 return ((uint16_t)(key * 2 - 1)); 80} 81 82static __checkReturn boolean_t 83efx_filter_test_used( 84 __in efx_filter_tbl_t *eftp, 85 __in unsigned int index) 86{ 87 EFSYS_ASSERT3P(eftp->eft_bitmap, !=, NULL); 88 return ((eftp->eft_bitmap[index / 32] & (1 << (index % 32))) != 0); 89} 90 91static void 92efx_filter_set_used( 93 __in efx_filter_tbl_t *eftp, 94 __in unsigned int index) 95{ 96 EFSYS_ASSERT3P(eftp->eft_bitmap, !=, NULL); 97 eftp->eft_bitmap[index / 32] |= (1 << (index % 32)); 98 ++eftp->eft_used; 99} 100 101static void 102efx_filter_clear_used( 103 __in efx_filter_tbl_t *eftp, 104 __in unsigned int index) 105{ 106 EFSYS_ASSERT3P(eftp->eft_bitmap, !=, NULL); 107 eftp->eft_bitmap[index / 32] &= ~(1 << (index % 32)); 108 109 --eftp->eft_used; 110 EFSYS_ASSERT3U(eftp->eft_used, >=, 0); 111} 112 113 114static efx_filter_tbl_id_t 115efx_filter_tbl_id( 116 __in efx_filter_type_t type) 117{ 118 efx_filter_tbl_id_t tbl_id; 119 120 switch (type) 121 { 122 case EFX_FILTER_RX_TCP_FULL: 123 case EFX_FILTER_RX_TCP_WILD: 124 case EFX_FILTER_RX_UDP_FULL: 125 case EFX_FILTER_RX_UDP_WILD: 126 tbl_id = EFX_FILTER_TBL_RX_IP; 127 break; 128 129#if EFSYS_OPT_SIENA 130 case EFX_FILTER_RX_MAC_FULL: 131 case EFX_FILTER_RX_MAC_WILD: 132 tbl_id = EFX_FILTER_TBL_RX_MAC; 133 break; 134 135 case EFX_FILTER_TX_TCP_FULL: 136 case EFX_FILTER_TX_TCP_WILD: 137 case EFX_FILTER_TX_UDP_FULL: 138 case EFX_FILTER_TX_UDP_WILD: 139 tbl_id = EFX_FILTER_TBL_TX_IP; 140 break; 141 142 case EFX_FILTER_TX_MAC_FULL: 143 case EFX_FILTER_TX_MAC_WILD: 144 tbl_id = EFX_FILTER_TBL_RX_MAC; 145 break; 146#endif /* EFSYS_OPT_SIENA */ 147 148 default: 149 EFSYS_ASSERT(B_FALSE); 150 break; 151 } 152 return (tbl_id); 153} 154 155static void 156efx_filter_reset_search_depth( 157 __inout efx_filter_t *efp, 158 __in efx_filter_tbl_id_t tbl_id) 159{ 160 switch (tbl_id) 161 { 162 case EFX_FILTER_TBL_RX_IP: 163 efp->ef_depth[EFX_FILTER_RX_TCP_FULL] = 0; 164 efp->ef_depth[EFX_FILTER_RX_TCP_WILD] = 0; 165 efp->ef_depth[EFX_FILTER_RX_UDP_FULL] = 0; 166 efp->ef_depth[EFX_FILTER_RX_UDP_WILD] = 0; 167 break; 168 169#if EFSYS_OPT_SIENA 170 case EFX_FILTER_TBL_RX_MAC: 171 efp->ef_depth[EFX_FILTER_RX_MAC_FULL] = 0; 172 efp->ef_depth[EFX_FILTER_RX_MAC_WILD] = 0; 173 break; 174 175 case EFX_FILTER_TBL_TX_IP: 176 efp->ef_depth[EFX_FILTER_TX_TCP_FULL] = 0; 177 efp->ef_depth[EFX_FILTER_TX_TCP_WILD] = 0; 178 efp->ef_depth[EFX_FILTER_TX_UDP_FULL] = 0; 179 efp->ef_depth[EFX_FILTER_TX_UDP_WILD] = 0; 180 break; 181 182 case EFX_FILTER_TBL_TX_MAC: 183 efp->ef_depth[EFX_FILTER_TX_MAC_FULL] = 0; 184 efp->ef_depth[EFX_FILTER_TX_MAC_WILD] = 0; 185 break; 186#endif /* EFSYS_OPT_SIENA */ 187 188 default: 189 EFSYS_ASSERT(B_FALSE); 190 break; 191 } 192} 193 194static void 195efx_filter_push_rx_limits( 196 __in efx_nic_t *enp) 197{ 198 efx_filter_t *efp = &enp->en_filter; 199 efx_oword_t oword; 200 201 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); 202 203 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT, 204 efp->ef_depth[EFX_FILTER_RX_TCP_FULL] + 205 FILTER_CTL_SRCH_FUDGE_FULL); 206 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT, 207 efp->ef_depth[EFX_FILTER_RX_TCP_WILD] + 208 FILTER_CTL_SRCH_FUDGE_WILD); 209 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT, 210 efp->ef_depth[EFX_FILTER_RX_UDP_FULL] + 211 FILTER_CTL_SRCH_FUDGE_FULL); 212 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT, 213 efp->ef_depth[EFX_FILTER_RX_UDP_WILD] + 214 FILTER_CTL_SRCH_FUDGE_WILD); 215 216#if EFSYS_OPT_SIENA 217 if (efp->ef_tbl[EFX_FILTER_TBL_RX_MAC].eft_size) { 218 EFX_SET_OWORD_FIELD(oword, 219 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT, 220 efp->ef_depth[EFX_FILTER_RX_MAC_FULL] + 221 FILTER_CTL_SRCH_FUDGE_FULL); 222 EFX_SET_OWORD_FIELD(oword, 223 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT, 224 efp->ef_depth[EFX_FILTER_RX_MAC_WILD] + 225 FILTER_CTL_SRCH_FUDGE_WILD); 226 } 227#endif /* EFSYS_OPT_SIENA */ 228 229 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); 230} 231 232static void 233efx_filter_push_tx_limits( 234 __in efx_nic_t *enp) 235{ 236 efx_filter_t *efp = &enp->en_filter; 237 efx_oword_t oword; 238 239 if (efp->ef_tbl[EFX_FILTER_TBL_TX_IP].eft_size == 0) 240 return; 241 242 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword); 243 244 EFX_SET_OWORD_FIELD(oword, FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE, 245 efp->ef_depth[EFX_FILTER_TX_TCP_FULL] + 246 FILTER_CTL_SRCH_FUDGE_FULL); 247 EFX_SET_OWORD_FIELD(oword, FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE, 248 efp->ef_depth[EFX_FILTER_TX_TCP_WILD] + 249 FILTER_CTL_SRCH_FUDGE_WILD); 250 EFX_SET_OWORD_FIELD(oword, FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE, 251 efp->ef_depth[EFX_FILTER_TX_UDP_FULL] + 252 FILTER_CTL_SRCH_FUDGE_FULL); 253 EFX_SET_OWORD_FIELD(oword, FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE, 254 efp->ef_depth[EFX_FILTER_TX_UDP_WILD] + 255 FILTER_CTL_SRCH_FUDGE_WILD); 256 257 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword); 258} 259 260/* Build a filter entry and return its n-tuple key. */ 261static __checkReturn uint32_t 262efx_filter_build( 263 __out efx_oword_t *filter, 264 __in efx_filter_spec_t *spec) 265{ 266 uint32_t dword3; 267 uint32_t key; 268 uint8_t type = spec->efs_type; 269 uint8_t flags = spec->efs_flags; 270 271 switch (efx_filter_tbl_id(type)) { 272 case EFX_FILTER_TBL_RX_IP: { 273 boolean_t is_udp = (type == EFX_FILTER_RX_UDP_FULL || 274 type == EFX_FILTER_RX_UDP_WILD); 275 EFX_POPULATE_OWORD_7(*filter, 276 FRF_BZ_RSS_EN, (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0, 277 FRF_BZ_SCATTER_EN, (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0, 278 FRF_AZ_TCP_UDP, is_udp, 279 FRF_AZ_RXQ_ID, spec->efs_dmaq_id, 280 EFX_DWORD_2, spec->efs_dword[2], 281 EFX_DWORD_1, spec->efs_dword[1], 282 EFX_DWORD_0, spec->efs_dword[0]); 283 dword3 = is_udp; 284 break; 285 } 286 287#if EFSYS_OPT_SIENA 288 case EFX_FILTER_TBL_RX_MAC: { 289 boolean_t is_wild = (type == EFX_FILTER_RX_MAC_WILD); 290 EFX_POPULATE_OWORD_8(*filter, 291 FRF_CZ_RMFT_RSS_EN, (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0, 292 FRF_CZ_RMFT_SCATTER_EN, (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0, 293 FRF_CZ_RMFT_IP_OVERRIDE, (flags & EFX_FILTER_FLAG_RX_OVERRIDE_IP) ? 1 : 0, 294 FRF_CZ_RMFT_RXQ_ID, spec->efs_dmaq_id, 295 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild, 296 FRF_CZ_RMFT_DEST_MAC_DW1, spec->efs_dword[2], 297 FRF_CZ_RMFT_DEST_MAC_DW0, spec->efs_dword[1], 298 FRF_CZ_RMFT_VLAN_ID, spec->efs_dword[0]); 299 dword3 = is_wild; 300 break; 301 } 302#endif /* EFSYS_OPT_SIENA */ 303 304 case EFX_FILTER_TBL_TX_IP: { 305 boolean_t is_udp = (type == EFX_FILTER_TX_UDP_FULL || 306 type == EFX_FILTER_TX_UDP_WILD); 307 EFX_POPULATE_OWORD_5(*filter, 308 FRF_CZ_TIFT_TCP_UDP, is_udp, 309 FRF_CZ_TIFT_TXQ_ID, spec->efs_dmaq_id, 310 EFX_DWORD_2, spec->efs_dword[2], 311 EFX_DWORD_1, spec->efs_dword[1], 312 EFX_DWORD_0, spec->efs_dword[0]); 313 dword3 = is_udp | spec->efs_dmaq_id << 1; 314 break; 315 } 316 317#if EFSYS_OPT_SIENA 318 case EFX_FILTER_TBL_TX_MAC: { 319 boolean_t is_wild = (type == EFX_FILTER_TX_MAC_WILD); 320 EFX_POPULATE_OWORD_5(*filter, 321 FRF_CZ_TMFT_TXQ_ID, spec->efs_dmaq_id, 322 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild, 323 FRF_CZ_TMFT_SRC_MAC_DW1, spec->efs_dword[2], 324 FRF_CZ_TMFT_SRC_MAC_DW0, spec->efs_dword[1], 325 FRF_CZ_TMFT_VLAN_ID, spec->efs_dword[0]); 326 dword3 = is_wild | spec->efs_dmaq_id << 1; 327 break; 328 } 329#endif /* EFSYS_OPT_SIENA */ 330 331 default: 332 EFSYS_ASSERT(B_FALSE); 333 } 334 335 key = spec->efs_dword[0] ^ spec->efs_dword[1] ^ spec->efs_dword[2] ^ dword3; 336 return (key); 337} 338 339static __checkReturn int 340efx_filter_push_entry( 341 __inout efx_nic_t *enp, 342 __in efx_filter_type_t type, 343 __in int index, 344 __in efx_oword_t *eop) 345{ 346 int rc; 347 348 switch (type) 349 { 350 case EFX_FILTER_RX_TCP_FULL: 351 case EFX_FILTER_RX_TCP_WILD: 352 case EFX_FILTER_RX_UDP_FULL: 353 case EFX_FILTER_RX_UDP_WILD: 354 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index, eop); 355 break; 356 357#if EFSYS_OPT_SIENA 358 case EFX_FILTER_RX_MAC_FULL: 359 case EFX_FILTER_RX_MAC_WILD: 360 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index, eop); 361 break; 362 363 case EFX_FILTER_TX_TCP_FULL: 364 case EFX_FILTER_TX_TCP_WILD: 365 case EFX_FILTER_TX_UDP_FULL: 366 case EFX_FILTER_TX_UDP_WILD: 367 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index, eop); 368 break; 369 370 case EFX_FILTER_TX_MAC_FULL: 371 case EFX_FILTER_TX_MAC_WILD: 372 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index, eop); 373 break; 374#endif /* EFSYS_OPT_SIENA */ 375 376 default: 377 rc = ENOTSUP; 378 goto fail1; 379 } 380 return (0); 381 382fail1: 383 return (rc); 384} 385 386 387static __checkReturn boolean_t 388efx_filter_equal( 389 __in const efx_filter_spec_t *left, 390 __in const efx_filter_spec_t *right) 391{ 392 efx_filter_tbl_id_t tbl_id = efx_filter_tbl_id(left->efs_type); 393 394 if (left->efs_type != right->efs_type) 395 return (B_FALSE); 396 397 if (memcmp(left->efs_dword, right->efs_dword, sizeof(left->efs_dword))) 398 return (B_FALSE); 399 400 if ((tbl_id == EFX_FILTER_TBL_TX_IP || 401 tbl_id == EFX_FILTER_TBL_TX_MAC) && 402 left->efs_dmaq_id != right->efs_dmaq_id) 403 return (B_FALSE); 404 405 return (B_TRUE); 406} 407 408static __checkReturn int 409efx_filter_search( 410 __in efx_filter_tbl_t *eftp, 411 __in efx_filter_spec_t *spec, 412 __in uint32_t key, 413 __in boolean_t for_insert, 414 __out int *filter_index, 415 __out int *depth_required) 416{ 417 unsigned hash, incr, filter_idx, depth; 418 419 hash = efx_filter_tbl_hash(key); 420 incr = efx_filter_tbl_increment(key); 421 422 filter_idx = hash & (eftp->eft_size - 1); 423 depth = 1; 424 425 for (;;) { 426 /* Return success if entry is used and matches this spec 427 * or entry is unused and we are trying to insert. 428 */ 429 if (efx_filter_test_used(eftp, filter_idx) ? 430 efx_filter_equal(spec, &eftp->eft_spec[filter_idx]) : 431 for_insert) { 432 *filter_index = filter_idx; 433 *depth_required = depth; 434 return (0); 435 } 436 437 /* Return failure if we reached the maximum search depth */ 438 if (depth == FILTER_CTL_SRCH_MAX) 439 return for_insert ? EBUSY : ENOENT; 440 441 filter_idx = (filter_idx + incr) & (eftp->eft_size - 1); 442 ++depth; 443 } 444} 445 446 __checkReturn int 447efx_filter_insert_filter( 448 __in efx_nic_t *enp, 449 __in efx_filter_spec_t *spec, 450 __in boolean_t replace) 451{ 452 efx_filter_t *efp = &enp->en_filter; 453 efx_filter_tbl_id_t tbl_id = efx_filter_tbl_id(spec->efs_type); 454 efx_filter_tbl_t *eftp = &efp->ef_tbl[tbl_id]; 455 efx_filter_spec_t *saved_spec; 456 efx_oword_t filter; 457 int filter_idx; 458 unsigned int depth; 459 int state; 460 uint32_t key; 461 int rc; 462 463 if (eftp->eft_size == 0) 464 return (EINVAL); 465 466 key = efx_filter_build(&filter, spec); 467 468 EFSYS_LOCK(enp->en_eslp, state); 469 470 rc = efx_filter_search(eftp, spec, key, B_TRUE, &filter_idx, &depth); 471 if (rc != 0) 472 goto done; 473 474 EFSYS_ASSERT3U(filter_idx, <, eftp->eft_size); 475 saved_spec = &eftp->eft_spec[filter_idx]; 476 477 if (efx_filter_test_used(eftp, filter_idx)) { 478 if (replace == B_FALSE) { 479 rc = EEXIST; 480 goto done; 481 } 482 } 483 efx_filter_set_used(eftp, filter_idx); 484 *saved_spec = *spec; 485 486 if (efp->ef_depth[spec->efs_type] < depth) { 487 efp->ef_depth[spec->efs_type] = depth; 488 if (tbl_id == EFX_FILTER_TBL_TX_IP || 489 tbl_id == EFX_FILTER_TBL_TX_MAC) 490 efx_filter_push_tx_limits(enp); 491 else 492 efx_filter_push_rx_limits(enp); 493 } 494 495 efx_filter_push_entry(enp, spec->efs_type, filter_idx, &filter); 496 497done: 498 EFSYS_UNLOCK(enp->en_eslp, state); 499 return (rc); 500} 501 502static void 503efx_filter_clear_entry( 504 __in efx_nic_t *enp, 505 __in efx_filter_tbl_t *eftp, 506 __in int index) 507{ 508 efx_oword_t filter; 509 510 if (efx_filter_test_used(eftp, index)) { 511 efx_filter_clear_used(eftp, index); 512 513 EFX_ZERO_OWORD(filter); 514 efx_filter_push_entry(enp, eftp->eft_spec[index].efs_type, 515 index, &filter); 516 517 memset(&eftp->eft_spec[index], 0, sizeof(eftp->eft_spec[0])); 518 } 519} 520 521 __checkReturn int 522efx_filter_remove_filter( 523 __in efx_nic_t *enp, 524 __in efx_filter_spec_t *spec) 525{ 526 efx_filter_t *efp = &enp->en_filter; 527 efx_filter_tbl_id_t tbl_id = efx_filter_tbl_id(spec->efs_type); 528 efx_filter_tbl_t *eftp = &efp->ef_tbl[tbl_id]; 529 efx_filter_spec_t *saved_spec; 530 efx_oword_t filter; 531 int filter_idx, depth; 532 int state; 533 uint32_t key; 534 int rc; 535 536 key = efx_filter_build(&filter, spec); 537 538 EFSYS_LOCK(enp->en_eslp, state); 539 540 rc = efx_filter_search(eftp, spec, key, B_FALSE, &filter_idx, &depth); 541 if (rc != 0) 542 goto out; 543 544 saved_spec = &eftp->eft_spec[filter_idx]; 545 546 efx_filter_clear_entry(enp, eftp, filter_idx); 547 if (eftp->eft_used == 0) 548 efx_filter_reset_search_depth(efp, tbl_id); 549 550 rc = 0; 551 552out: 553 EFSYS_UNLOCK(enp->en_eslp, state); 554 return (rc); 555} 556 557 void 558efx_filter_remove_index( 559 __inout efx_nic_t *enp, 560 __in efx_filter_type_t type, 561 __in int index) 562{ 563 efx_filter_t *efp = &enp->en_filter; 564 enum efx_filter_tbl_id tbl_id = efx_filter_tbl_id(type); 565 efx_filter_tbl_t *eftp = &efp->ef_tbl[tbl_id]; 566 int state; 567 568 if (index < 0) 569 return; 570 571 EFSYS_LOCK(enp->en_eslp, state); 572 573 efx_filter_clear_entry(enp, eftp, index); 574 if (eftp->eft_used == 0) 575 efx_filter_reset_search_depth(efp, tbl_id); 576 577 EFSYS_UNLOCK(enp->en_eslp, state); 578} 579 580 void 581efx_filter_tbl_clear( 582 __inout efx_nic_t *enp, 583 __in efx_filter_tbl_id_t tbl_id) 584{ 585 efx_filter_t *efp = &enp->en_filter; 586 efx_filter_tbl_t *eftp = &efp->ef_tbl[tbl_id]; 587 int index; 588 int state; 589 590 EFSYS_LOCK(enp->en_eslp, state); 591 592 for (index = 0; index < eftp->eft_size; ++index) { 593 efx_filter_clear_entry(enp, eftp, index); 594 } 595 596 if (eftp->eft_used == 0) 597 efx_filter_reset_search_depth(efp, tbl_id); 598 599 EFSYS_UNLOCK(enp->en_eslp, state); 600} 601 602/* Restore filter state after a reset */ 603 void 604efx_filter_restore( 605 __in efx_nic_t *enp) 606{ 607 efx_filter_t *efp = &enp->en_filter; 608 efx_filter_tbl_id_t tbl_id; 609 efx_filter_tbl_t *eftp; 610 efx_filter_spec_t *spec; 611 efx_oword_t filter; 612 int filter_idx; 613 int state; 614 615 EFSYS_LOCK(enp->en_eslp, state); 616 617 for (tbl_id = 0; tbl_id < EFX_FILTER_NTBLS; tbl_id++) { 618 eftp = &efp->ef_tbl[tbl_id]; 619 for (filter_idx = 0; filter_idx < eftp->eft_size; filter_idx++) { 620 if (!efx_filter_test_used(eftp, filter_idx)) 621 continue; 622 623 spec = &eftp->eft_spec[filter_idx]; 624 efx_filter_build(&filter, spec); 625 efx_filter_push_entry(enp, spec->efs_type, 626 filter_idx, &filter); 627 } 628 } 629 630 efx_filter_push_rx_limits(enp); 631 efx_filter_push_tx_limits(enp); 632 633 EFSYS_UNLOCK(enp->en_eslp, state); 634} 635 636 void 637efx_filter_redirect_index( 638 __inout efx_nic_t *enp, 639 __in efx_filter_type_t type, 640 __in int filter_index, 641 __in int rxq_index) 642{ 643 efx_filter_t *efp = &enp->en_filter; 644 efx_filter_tbl_t *eftp = 645 &efp->ef_tbl[efx_filter_tbl_id(type)]; 646 efx_filter_spec_t *spec; 647 efx_oword_t filter; 648 int state; 649 650 EFSYS_LOCK(enp->en_eslp, state); 651 652 spec = &eftp->eft_spec[filter_index]; 653 spec->efs_dmaq_id = (uint16_t)rxq_index; 654 655 efx_filter_build(&filter, spec); 656 efx_filter_push_entry(enp, spec->efs_type, filter_index, &filter); 657 658 EFSYS_UNLOCK(enp->en_eslp, state); 659} 660 661 __checkReturn int 662efx_filter_init( 663 __in efx_nic_t *enp) 664{ 665 efx_filter_t *efp = &enp->en_filter; 666 efx_filter_tbl_t *eftp; 667 int tbl_id; 668 int rc; 669 670 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 671 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 672 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER)); 673 674 switch (enp->en_family) 675 { 676#if EFSYS_OPT_FALCON 677 case EFX_FAMILY_FALCON: 678 eftp = &efp->ef_tbl[EFX_FILTER_TBL_RX_IP]; 679 eftp->eft_size = FR_AZ_RX_FILTER_TBL0_ROWS; 680 break; 681#endif /* EFSYS_OPT_FALCON */ 682 683#if EFSYS_OPT_SIENA 684 case EFX_FAMILY_SIENA: 685 eftp = &efp->ef_tbl[EFX_FILTER_TBL_RX_IP]; 686 eftp->eft_size = FR_AZ_RX_FILTER_TBL0_ROWS; 687 688 eftp = &efp->ef_tbl[EFX_FILTER_TBL_RX_MAC]; 689 eftp->eft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS; 690 691 eftp = &efp->ef_tbl[EFX_FILTER_TBL_TX_IP]; 692 eftp->eft_size = FR_CZ_TX_FILTER_TBL0_ROWS; 693 694 eftp = &efp->ef_tbl[EFX_FILTER_TBL_TX_MAC]; 695 eftp->eft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS; 696 break; 697#endif /* EFSYS_OPT_SIENA */ 698 699 default: 700 rc = ENOTSUP; 701 goto fail1; 702 } 703 704 for (tbl_id = 0; tbl_id < EFX_FILTER_NTBLS; tbl_id++) { 705 unsigned int bitmap_size; 706 707 eftp = &efp->ef_tbl[tbl_id]; 708 if (eftp->eft_size == 0) 709 continue; 710 711 EFX_STATIC_ASSERT(sizeof(eftp->eft_bitmap[0]) == sizeof(uint32_t)); 712 bitmap_size = (eftp->eft_size + (sizeof(uint32_t) * 8) - 1) / 8; 713 714 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, eftp->eft_bitmap); 715 if (!eftp->eft_bitmap) { 716 rc = ENOMEM; 717 goto fail2; 718 } 719 720 EFSYS_KMEM_ALLOC(enp->en_esip, eftp->eft_size * sizeof(*eftp->eft_spec), 721 eftp->eft_spec); 722 if (!eftp->eft_spec) { 723 rc = ENOMEM; 724 goto fail2; 725 } 726 memset(eftp->eft_spec, 0, eftp->eft_size * sizeof(*eftp->eft_spec)); 727 } 728 enp->en_mod_flags |= EFX_MOD_FILTER; 729 730 return (0); 731 732fail2: 733 EFSYS_PROBE(fail2); 734 efx_filter_fini(enp); 735 736fail1: 737 EFSYS_PROBE1(fail1, int, rc); 738 return (rc); 739} 740 741 void 742efx_filter_fini( 743 __in efx_nic_t *enp) 744{ 745 efx_filter_t *efp = &enp->en_filter; 746 efx_filter_tbl_id_t tbl_id; 747 748 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 749 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 750 751 for (tbl_id = 0; tbl_id < EFX_FILTER_NTBLS; tbl_id++) { 752 efx_filter_tbl_t *eftp = &efp->ef_tbl[tbl_id]; 753 unsigned int bitmap_size; 754 755 EFX_STATIC_ASSERT(sizeof(eftp->eft_bitmap[0]) == sizeof(uint32_t)); 756 bitmap_size = (eftp->eft_size + (sizeof(uint32_t) * 8) - 1) / 8; 757 758 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size, eftp->eft_bitmap); 759 eftp->eft_bitmap = NULL; 760 761 EFSYS_KMEM_FREE(enp->en_esip, eftp->eft_size * sizeof(*eftp->eft_spec), 762 eftp->eft_spec); 763 eftp->eft_spec = NULL; 764 } 765 766 enp->en_mod_flags &= ~EFX_MOD_FILTER; 767} 768 769extern void 770efx_filter_spec_rx_ipv4_tcp_full( 771 __inout efx_filter_spec_t *spec, 772 __in unsigned int flags, 773 __in uint32_t src_ip, 774 __in uint16_t src_tcp, 775 __in uint32_t dest_ip, 776 __in uint16_t dest_tcp) 777{ 778 EFSYS_ASSERT3P(spec, !=, NULL); 779 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS | 780 EFX_FILTER_FLAG_RX_SCATTER)) == 0); 781 782 spec->efs_type = EFX_FILTER_RX_TCP_FULL; 783 spec->efs_flags = (uint8_t)flags; 784 spec->efs_dword[0] = src_tcp | src_ip << 16; 785 spec->efs_dword[1] = dest_tcp << 16 | src_ip >> 16; 786 spec->efs_dword[2] = dest_ip; 787} 788 789extern void 790efx_filter_spec_rx_ipv4_tcp_wild( 791 __inout efx_filter_spec_t *spec, 792 __in unsigned int flags, 793 __in uint32_t dest_ip, 794 __in uint16_t dest_tcp) 795{ 796 EFSYS_ASSERT3P(spec, !=, NULL); 797 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS | 798 EFX_FILTER_FLAG_RX_SCATTER)) == 0); 799 800 spec->efs_type = EFX_FILTER_RX_TCP_WILD; 801 spec->efs_flags = (uint8_t)flags; 802 spec->efs_dword[0] = 0; 803 spec->efs_dword[1] = dest_tcp << 16; 804 spec->efs_dword[2] = dest_ip; 805} 806 807extern void 808efx_filter_spec_rx_ipv4_udp_full( 809 __inout efx_filter_spec_t *spec, 810 __in unsigned int flags, 811 __in uint32_t src_ip, 812 __in uint16_t src_udp, 813 __in uint32_t dest_ip, 814 __in uint16_t dest_udp) 815{ 816 EFSYS_ASSERT3P(spec, !=, NULL); 817 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS | 818 EFX_FILTER_FLAG_RX_SCATTER)) == 0); 819 820 spec->efs_type = EFX_FILTER_RX_UDP_FULL; 821 spec->efs_flags = (uint8_t)flags; 822 spec->efs_dword[0] = src_udp | src_ip << 16; 823 spec->efs_dword[1] = dest_udp << 16 | src_ip >> 16; 824 spec->efs_dword[2] = dest_ip; 825} 826 827extern void 828efx_filter_spec_rx_ipv4_udp_wild( 829 __inout efx_filter_spec_t *spec, 830 __in unsigned int flags, 831 __in uint32_t dest_ip, 832 __in uint16_t dest_udp) 833{ 834 EFSYS_ASSERT3P(spec, !=, NULL); 835 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS | 836 EFX_FILTER_FLAG_RX_SCATTER)) == 0); 837 838 spec->efs_type = EFX_FILTER_RX_UDP_WILD; 839 spec->efs_flags = (uint8_t)flags; 840 spec->efs_dword[0] = dest_udp; 841 spec->efs_dword[1] = 0; 842 spec->efs_dword[2] = dest_ip; 843} 844 845#if EFSYS_OPT_SIENA 846extern void 847efx_filter_spec_rx_mac_full( 848 __inout efx_filter_spec_t *spec, 849 __in unsigned int flags, 850 __in uint16_t vlan_id, 851 __in uint8_t *dest_mac) 852{ 853 EFSYS_ASSERT3P(spec, !=, NULL); 854 EFSYS_ASSERT3P(dest_mac, !=, NULL); 855 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS | 856 EFX_FILTER_FLAG_RX_SCATTER | 857 EFX_FILTER_FLAG_RX_OVERRIDE_IP)) == 0); 858 859 spec->efs_type = EFX_FILTER_RX_MAC_FULL; 860 spec->efs_flags = (uint8_t)flags; 861 spec->efs_dword[0] = vlan_id; 862 spec->efs_dword[1] = 863 dest_mac[2] << 24 | 864 dest_mac[3] << 16 | 865 dest_mac[4] << 8 | 866 dest_mac[5]; 867 spec->efs_dword[2] = 868 dest_mac[0] << 8 | 869 dest_mac[1]; 870} 871#endif /* EFSYS_OPT_SIENA */ 872 873#if EFSYS_OPT_SIENA 874extern void 875efx_filter_spec_rx_mac_wild( 876 __inout efx_filter_spec_t *spec, 877 __in unsigned int flags, 878 __in uint8_t *dest_mac) 879{ 880 EFSYS_ASSERT3P(spec, !=, NULL); 881 EFSYS_ASSERT3P(dest_mac, !=, NULL); 882 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS | 883 EFX_FILTER_FLAG_RX_SCATTER | 884 EFX_FILTER_FLAG_RX_OVERRIDE_IP)) == 0); 885 886 spec->efs_type = EFX_FILTER_RX_MAC_WILD; 887 spec->efs_flags = (uint8_t)flags; 888 spec->efs_dword[0] = 0; 889 spec->efs_dword[1] = 890 dest_mac[2] << 24 | 891 dest_mac[3] << 16 | 892 dest_mac[4] << 8 | 893 dest_mac[5]; 894 spec->efs_dword[2] = 895 dest_mac[0] << 8 | 896 dest_mac[1]; 897} 898#endif /* EFSYS_OPT_SIENA */ 899 900#if EFSYS_OPT_SIENA 901extern void 902efx_filter_spec_tx_ipv4_tcp_full( 903 __inout efx_filter_spec_t *spec, 904 __in uint32_t src_ip, 905 __in uint16_t src_tcp, 906 __in uint32_t dest_ip, 907 __in uint16_t dest_tcp) 908{ 909 EFSYS_ASSERT3P(spec, !=, NULL); 910 911 spec->efs_type = EFX_FILTER_TX_TCP_FULL; 912 spec->efs_flags = 0; 913 spec->efs_dword[0] = src_tcp | src_ip << 16; 914 spec->efs_dword[1] = dest_tcp << 16 | src_ip >> 16; 915 spec->efs_dword[2] = dest_ip; 916} 917#endif /* EFSYS_OPT_SIENA */ 918 919#if EFSYS_OPT_SIENA 920extern void 921efx_filter_spec_tx_ipv4_tcp_wild( 922 __inout efx_filter_spec_t *spec, 923 __in uint32_t src_ip, 924 __in uint16_t src_tcp) 925{ 926 EFSYS_ASSERT3P(spec, !=, NULL); 927 928 spec->efs_type = EFX_FILTER_TX_TCP_WILD; 929 spec->efs_flags = 0; 930 spec->efs_dword[0] = 0; 931 spec->efs_dword[1] = src_tcp << 16; 932 spec->efs_dword[2] = src_ip; 933} 934#endif /* EFSYS_OPT_SIENA */ 935 936#if EFSYS_OPT_SIENA 937extern void 938efx_filter_spec_tx_ipv4_udp_full( 939 __inout efx_filter_spec_t *spec, 940 __in uint32_t src_ip, 941 __in uint16_t src_udp, 942 __in uint32_t dest_ip, 943 __in uint16_t dest_udp) 944{ 945 EFSYS_ASSERT3P(spec, !=, NULL); 946 947 spec->efs_type = EFX_FILTER_TX_UDP_FULL; 948 spec->efs_flags = 0; 949 spec->efs_dword[0] = src_udp | src_ip << 16; 950 spec->efs_dword[1] = dest_udp << 16 | src_ip >> 16; 951 spec->efs_dword[2] = dest_ip; 952} 953#endif /* EFSYS_OPT_SIENA */ 954 955#if EFSYS_OPT_SIENA 956extern void 957efx_filter_spec_tx_ipv4_udp_wild( 958 __inout efx_filter_spec_t *spec, 959 __in uint32_t src_ip, 960 __in uint16_t src_udp) 961{ 962 EFSYS_ASSERT3P(spec, !=, NULL); 963 964 spec->efs_type = EFX_FILTER_TX_UDP_WILD; 965 spec->efs_flags = 0; 966 spec->efs_dword[0] = src_udp; 967 spec->efs_dword[1] = 0; 968 spec->efs_dword[2] = src_ip; 969} 970#endif /* EFSYS_OPT_SIENA */ 971 972#if EFSYS_OPT_SIENA 973extern void 974efx_filter_spec_tx_mac_full( 975 __inout efx_filter_spec_t *spec, 976 __in uint16_t vlan_id, 977 __in uint8_t *src_mac) 978{ 979 EFSYS_ASSERT3P(spec, !=, NULL); 980 EFSYS_ASSERT3P(src_mac, !=, NULL); 981 982 spec->efs_type = EFX_FILTER_TX_MAC_FULL; 983 spec->efs_flags = 0; 984 spec->efs_dword[0] = vlan_id; 985 spec->efs_dword[1] = 986 src_mac[2] << 24 | 987 src_mac[3] << 16 | 988 src_mac[4] << 8 | 989 src_mac[5]; 990 spec->efs_dword[2] = 991 src_mac[0] << 8 | 992 src_mac[1]; 993} 994#endif /* EFSYS_OPT_SIENA */ 995 996#if EFSYS_OPT_SIENA 997extern void 998efx_filter_spec_tx_mac_wild( 999 __inout efx_filter_spec_t *spec, 1000 __in uint8_t *src_mac) 1001{ 1002 EFSYS_ASSERT3P(spec, !=, NULL); 1003 EFSYS_ASSERT3P(src_mac, !=, NULL); 1004 1005 spec->efs_type = EFX_FILTER_TX_MAC_WILD; 1006 spec->efs_flags = 0; 1007 spec->efs_dword[0] = 0; 1008 spec->efs_dword[1] = 1009 src_mac[2] << 24 | 1010 src_mac[3] << 16 | 1011 src_mac[4] << 8 | 1012 src_mac[5]; 1013 spec->efs_dword[2] = 1014 src_mac[0] << 8 | 1015 src_mac[1]; 1016} 1017#endif /* EFSYS_OPT_SIENA */ 1018 1019 1020#endif /* EFSYS_OPT_FILTER */ 1021