1 /* 2 * Copyright (c) 2007-2015 Solarflare Communications Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * The views and conclusions contained in the software and documentation are 27 * those of the authors and should not be interpreted as representing official 28 * policies, either expressed or implied, of the FreeBSD Project. 29 */ 30 31 #include "efx.h" 32 #include "efx_impl.h" 33 34 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 35 36 #if EFSYS_OPT_FILTER 37 38 #define EFE_SPEC(eftp, index) ((eftp)->eft_entry[(index)].efe_spec) 39 40 static efx_filter_spec_t * 41 ef10_filter_entry_spec( 42 __in const ef10_filter_table_t *eftp, 43 __in unsigned int index) 44 { 45 return ((efx_filter_spec_t *)(EFE_SPEC(eftp, index) & 46 ~(uintptr_t)EFX_EF10_FILTER_FLAGS)); 47 } 48 49 static boolean_t 50 ef10_filter_entry_is_busy( 51 __in const ef10_filter_table_t *eftp, 52 __in unsigned int index) 53 { 54 if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_BUSY) 55 return (B_TRUE); 56 else 57 return (B_FALSE); 58 } 59 60 static boolean_t 61 ef10_filter_entry_is_auto_old( 62 __in const ef10_filter_table_t *eftp, 63 __in unsigned int index) 64 { 65 if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_AUTO_OLD) 66 return (B_TRUE); 67 else 68 return (B_FALSE); 69 } 70 71 static void 72 ef10_filter_set_entry( 73 __inout ef10_filter_table_t *eftp, 74 __in unsigned int index, 75 __in_opt const efx_filter_spec_t *efsp) 76 { 77 EFE_SPEC(eftp, index) = (uintptr_t)efsp; 78 } 79 80 static void 81 ef10_filter_set_entry_busy( 82 __inout ef10_filter_table_t *eftp, 83 __in unsigned int index) 84 { 85 EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_BUSY; 86 } 87 88 static void 89 ef10_filter_set_entry_not_busy( 90 __inout ef10_filter_table_t *eftp, 91 __in unsigned int index) 92 { 93 EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_BUSY; 94 } 95 96 static void 97 ef10_filter_set_entry_auto_old( 98 __inout ef10_filter_table_t *eftp, 99 __in unsigned int index) 100 { 101 EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL); 102 EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD; 103 } 104 105 static void 106 ef10_filter_set_entry_not_auto_old( 107 __inout ef10_filter_table_t *eftp, 108 __in unsigned int index) 109 { 110 EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD; 111 EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL); 112 } 113 114 __checkReturn efx_rc_t 115 ef10_filter_init( 116 __in efx_nic_t *enp) 117 { 118 efx_rc_t rc; 119 ef10_filter_table_t *eftp; 120 121 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 122 enp->en_family == EFX_FAMILY_MEDFORD); 123 124 #define MATCH_MASK(match) (EFX_MASK32(match) << EFX_LOW_BIT(match)) 125 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_HOST == 126 MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_IP)); 127 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_HOST == 128 MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_IP)); 129 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_MAC == 130 MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_MAC)); 131 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_PORT == 132 MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_PORT)); 133 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_MAC == 134 MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_MAC)); 135 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_PORT == 136 MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_PORT)); 137 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_ETHER_TYPE == 138 MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_ETHER_TYPE)); 139 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_INNER_VID == 140 MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_INNER_VLAN)); 141 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_OUTER_VID == 142 MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_OUTER_VLAN)); 143 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO == 144 MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_IP_PROTO)); 145 #undef MATCH_MASK 146 147 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (ef10_filter_table_t), eftp); 148 149 if (!eftp) { 150 rc = ENOMEM; 151 goto fail1; 152 } 153 154 enp->en_filter.ef_ef10_filter_table = eftp; 155 156 return (0); 157 158 fail1: 159 EFSYS_PROBE1(fail1, efx_rc_t, rc); 160 161 return (rc); 162 } 163 164 void 165 ef10_filter_fini( 166 __in efx_nic_t *enp) 167 { 168 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 169 enp->en_family == EFX_FAMILY_MEDFORD); 170 171 if (enp->en_filter.ef_ef10_filter_table != NULL) { 172 EFSYS_KMEM_FREE(enp->en_esip, sizeof (ef10_filter_table_t), 173 enp->en_filter.ef_ef10_filter_table); 174 } 175 } 176 177 static __checkReturn efx_rc_t 178 efx_mcdi_filter_op_add( 179 __in efx_nic_t *enp, 180 __in efx_filter_spec_t *spec, 181 __in unsigned int filter_op, 182 __inout ef10_filter_handle_t *handle) 183 { 184 efx_mcdi_req_t req; 185 uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN, 186 MC_CMD_FILTER_OP_OUT_LEN)]; 187 uint32_t match_fields = 0; 188 efx_rc_t rc; 189 190 (void) memset(payload, 0, sizeof (payload)); 191 req.emr_cmd = MC_CMD_FILTER_OP; 192 req.emr_in_buf = payload; 193 req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN; 194 req.emr_out_buf = payload; 195 req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN; 196 197 switch (filter_op) { 198 case MC_CMD_FILTER_OP_IN_OP_REPLACE: 199 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, 200 handle->efh_lo); 201 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, 202 handle->efh_hi); 203 /* FALLTHROUGH */ 204 case MC_CMD_FILTER_OP_IN_OP_INSERT: 205 case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE: 206 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, filter_op); 207 break; 208 default: 209 EFSYS_ASSERT(0); 210 rc = EINVAL; 211 goto fail1; 212 } 213 214 if (spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC_IG) { 215 /* 216 * The LOC_MAC_IG match flag can represent unknown unicast 217 * or multicast filters - use the MAC address to distinguish 218 * them. 219 */ 220 if (EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) 221 match_fields |= 1U << 222 MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN; 223 else 224 match_fields |= 1U << 225 MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN; 226 } 227 228 match_fields |= spec->efs_match_flags & (~EFX_FILTER_MATCH_LOC_MAC_IG); 229 230 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_PORT_ID, 231 EVB_PORT_ID_ASSIGNED); 232 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_MATCH_FIELDS, 233 match_fields); 234 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_DEST, 235 MC_CMD_FILTER_OP_IN_RX_DEST_HOST); 236 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_QUEUE, 237 spec->efs_dmaq_id); 238 if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) { 239 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_CONTEXT, 240 spec->efs_rss_context); 241 } 242 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_MODE, 243 spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ? 244 MC_CMD_FILTER_OP_IN_RX_MODE_RSS : 245 MC_CMD_FILTER_OP_IN_RX_MODE_SIMPLE); 246 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_TX_DEST, 247 MC_CMD_FILTER_OP_IN_TX_DEST_DEFAULT); 248 249 if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) { 250 /* 251 * NOTE: Unlike most MCDI requests, the filter fields 252 * are presented in network (big endian) byte order. 253 */ 254 (void) memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_MAC), 255 spec->efs_rem_mac, EFX_MAC_ADDR_LEN); 256 (void) memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_MAC), 257 spec->efs_loc_mac, EFX_MAC_ADDR_LEN); 258 259 MCDI_IN_SET_WORD(req, FILTER_OP_IN_SRC_PORT, 260 __CPU_TO_BE_16(spec->efs_rem_port)); 261 MCDI_IN_SET_WORD(req, FILTER_OP_IN_DST_PORT, 262 __CPU_TO_BE_16(spec->efs_loc_port)); 263 264 MCDI_IN_SET_WORD(req, FILTER_OP_IN_ETHER_TYPE, 265 __CPU_TO_BE_16(spec->efs_ether_type)); 266 267 MCDI_IN_SET_WORD(req, FILTER_OP_IN_INNER_VLAN, 268 __CPU_TO_BE_16(spec->efs_inner_vid)); 269 MCDI_IN_SET_WORD(req, FILTER_OP_IN_OUTER_VLAN, 270 __CPU_TO_BE_16(spec->efs_outer_vid)); 271 272 /* IP protocol (in low byte, high byte is zero) */ 273 MCDI_IN_SET_BYTE(req, FILTER_OP_IN_IP_PROTO, 274 spec->efs_ip_proto); 275 276 EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) == 277 MC_CMD_FILTER_OP_IN_SRC_IP_LEN); 278 EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) == 279 MC_CMD_FILTER_OP_IN_DST_IP_LEN); 280 281 (void) memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_IP), 282 &spec->efs_rem_host.eo_byte[0], 283 MC_CMD_FILTER_OP_IN_SRC_IP_LEN); 284 (void) memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_IP), 285 &spec->efs_loc_host.eo_byte[0], 286 MC_CMD_FILTER_OP_IN_DST_IP_LEN); 287 } 288 289 efx_mcdi_execute(enp, &req); 290 291 if (req.emr_rc != 0) { 292 rc = req.emr_rc; 293 goto fail2; 294 } 295 296 if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) { 297 rc = EMSGSIZE; 298 goto fail3; 299 } 300 301 handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_LO); 302 handle->efh_hi = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_HI); 303 304 return (0); 305 306 fail3: 307 EFSYS_PROBE(fail3); 308 fail2: 309 EFSYS_PROBE(fail2); 310 fail1: 311 EFSYS_PROBE1(fail1, efx_rc_t, rc); 312 313 return (rc); 314 315 } 316 317 static __checkReturn efx_rc_t 318 efx_mcdi_filter_op_delete( 319 __in efx_nic_t *enp, 320 __in unsigned int filter_op, 321 __inout ef10_filter_handle_t *handle) 322 { 323 efx_mcdi_req_t req; 324 uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN, 325 MC_CMD_FILTER_OP_OUT_LEN)]; 326 efx_rc_t rc; 327 328 (void) memset(payload, 0, sizeof (payload)); 329 req.emr_cmd = MC_CMD_FILTER_OP; 330 req.emr_in_buf = payload; 331 req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN; 332 req.emr_out_buf = payload; 333 req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN; 334 335 switch (filter_op) { 336 case MC_CMD_FILTER_OP_IN_OP_REMOVE: 337 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, 338 MC_CMD_FILTER_OP_IN_OP_REMOVE); 339 break; 340 case MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE: 341 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, 342 MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE); 343 break; 344 default: 345 EFSYS_ASSERT(0); 346 rc = EINVAL; 347 goto fail1; 348 } 349 350 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, handle->efh_lo); 351 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, handle->efh_hi); 352 353 efx_mcdi_execute(enp, &req); 354 355 if (req.emr_rc != 0) { 356 rc = req.emr_rc; 357 goto fail2; 358 } 359 360 if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) { 361 rc = EMSGSIZE; 362 goto fail3; 363 } 364 365 return (0); 366 367 fail3: 368 EFSYS_PROBE(fail3); 369 370 fail2: 371 EFSYS_PROBE(fail2); 372 fail1: 373 EFSYS_PROBE1(fail1, efx_rc_t, rc); 374 375 return (rc); 376 } 377 378 static __checkReturn boolean_t 379 ef10_filter_equal( 380 __in const efx_filter_spec_t *left, 381 __in const efx_filter_spec_t *right) 382 { 383 /* FIXME: Consider rx vs tx filters (look at efs_flags) */ 384 if (left->efs_match_flags != right->efs_match_flags) 385 return (B_FALSE); 386 if (!EFX_OWORD_IS_EQUAL(left->efs_rem_host, right->efs_rem_host)) 387 return (B_FALSE); 388 if (!EFX_OWORD_IS_EQUAL(left->efs_loc_host, right->efs_loc_host)) 389 return (B_FALSE); 390 if (memcmp(left->efs_rem_mac, right->efs_rem_mac, EFX_MAC_ADDR_LEN)) 391 return (B_FALSE); 392 if (memcmp(left->efs_loc_mac, right->efs_loc_mac, EFX_MAC_ADDR_LEN)) 393 return (B_FALSE); 394 if (left->efs_rem_port != right->efs_rem_port) 395 return (B_FALSE); 396 if (left->efs_loc_port != right->efs_loc_port) 397 return (B_FALSE); 398 if (left->efs_inner_vid != right->efs_inner_vid) 399 return (B_FALSE); 400 if (left->efs_outer_vid != right->efs_outer_vid) 401 return (B_FALSE); 402 if (left->efs_ether_type != right->efs_ether_type) 403 return (B_FALSE); 404 if (left->efs_ip_proto != right->efs_ip_proto) 405 return (B_FALSE); 406 407 return (B_TRUE); 408 409 } 410 411 static __checkReturn boolean_t 412 ef10_filter_same_dest( 413 __in const efx_filter_spec_t *left, 414 __in const efx_filter_spec_t *right) 415 { 416 if ((left->efs_flags & EFX_FILTER_FLAG_RX_RSS) && 417 (right->efs_flags & EFX_FILTER_FLAG_RX_RSS)) { 418 if (left->efs_rss_context == right->efs_rss_context) 419 return (B_TRUE); 420 } else if ((~(left->efs_flags) & EFX_FILTER_FLAG_RX_RSS) && 421 (~(right->efs_flags) & EFX_FILTER_FLAG_RX_RSS)) { 422 if (left->efs_dmaq_id == right->efs_dmaq_id) 423 return (B_TRUE); 424 } 425 return (B_FALSE); 426 } 427 428 static __checkReturn uint32_t 429 ef10_filter_hash( 430 __in efx_filter_spec_t *spec) 431 { 432 EFX_STATIC_ASSERT((sizeof (efx_filter_spec_t) % sizeof (uint32_t)) 433 == 0); 434 EFX_STATIC_ASSERT((EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid) % 435 sizeof (uint32_t)) == 0); 436 437 /* 438 * As the area of the efx_filter_spec_t we need to hash is DWORD 439 * aligned and an exact number of DWORDs in size we can use the 440 * optimised efx_hash_dwords() rather than efx_hash_bytes() 441 */ 442 return (efx_hash_dwords((const void *)&spec->efs_outer_vid, 443 (sizeof (efx_filter_spec_t) - 444 EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid)) / 445 sizeof (uint32_t), 0)); 446 } 447 448 /* 449 * Decide whether a filter should be exclusive or else should allow 450 * delivery to additional recipients. Currently we decide that 451 * filters for specific local unicast MAC and IP addresses are 452 * exclusive. 453 */ 454 static __checkReturn boolean_t 455 ef10_filter_is_exclusive( 456 __in efx_filter_spec_t *spec) 457 { 458 if ((spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC) && 459 !EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) 460 return (B_TRUE); 461 462 if ((spec->efs_match_flags & 463 (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) == 464 (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) { 465 if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV4) && 466 ((spec->efs_loc_host.eo_u8[0] & 0xf) != 0xe)) 467 return (B_TRUE); 468 if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV6) && 469 (spec->efs_loc_host.eo_u8[0] != 0xff)) 470 return (B_TRUE); 471 } 472 473 return (B_FALSE); 474 } 475 476 __checkReturn efx_rc_t 477 ef10_filter_restore( 478 __in efx_nic_t *enp) 479 { 480 int tbl_id; 481 efx_filter_spec_t *spec; 482 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 483 boolean_t restoring; 484 int state; 485 efx_rc_t rc; 486 487 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 488 enp->en_family == EFX_FAMILY_MEDFORD); 489 490 for (tbl_id = 0; tbl_id < EFX_EF10_FILTER_TBL_ROWS; tbl_id++) { 491 492 EFSYS_LOCK(enp->en_eslp, state); 493 494 spec = ef10_filter_entry_spec(eftp, tbl_id); 495 if (spec == NULL) { 496 restoring = B_FALSE; 497 } else if (ef10_filter_entry_is_busy(eftp, tbl_id)) { 498 /* Ignore busy entries. */ 499 restoring = B_FALSE; 500 } else { 501 ef10_filter_set_entry_busy(eftp, tbl_id); 502 restoring = B_TRUE; 503 } 504 505 EFSYS_UNLOCK(enp->en_eslp, state); 506 507 if (restoring == B_FALSE) 508 continue; 509 510 if (ef10_filter_is_exclusive(spec)) { 511 rc = efx_mcdi_filter_op_add(enp, spec, 512 MC_CMD_FILTER_OP_IN_OP_INSERT, 513 &eftp->eft_entry[tbl_id].efe_handle); 514 } else { 515 rc = efx_mcdi_filter_op_add(enp, spec, 516 MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, 517 &eftp->eft_entry[tbl_id].efe_handle); 518 } 519 520 if (rc != 0) 521 goto fail1; 522 523 EFSYS_LOCK(enp->en_eslp, state); 524 525 ef10_filter_set_entry_not_busy(eftp, tbl_id); 526 527 EFSYS_UNLOCK(enp->en_eslp, state); 528 } 529 530 return (0); 531 532 fail1: 533 EFSYS_PROBE1(fail1, efx_rc_t, rc); 534 535 return (rc); 536 } 537 538 /* 539 * An arbitrary search limit for the software hash table. As per the linux net 540 * driver. 541 */ 542 #define EF10_FILTER_SEARCH_LIMIT 200 543 544 static __checkReturn efx_rc_t 545 ef10_filter_add_internal( 546 __in efx_nic_t *enp, 547 __inout efx_filter_spec_t *spec, 548 __in boolean_t may_replace, 549 __out_opt uint32_t *filter_id) 550 { 551 efx_rc_t rc; 552 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 553 efx_filter_spec_t *saved_spec; 554 uint32_t hash; 555 unsigned int depth; 556 int ins_index; 557 boolean_t replacing = B_FALSE; 558 unsigned int i; 559 int state; 560 boolean_t locked = B_FALSE; 561 562 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 563 enp->en_family == EFX_FAMILY_MEDFORD); 564 565 #if EFSYS_OPT_RX_SCALE 566 spec->efs_rss_context = enp->en_rss_context; 567 #endif 568 569 hash = ef10_filter_hash(spec); 570 571 /* 572 * FIXME: Add support for inserting filters of different priorities 573 * and removing lower priority multicast filters (bug 42378) 574 */ 575 576 /* 577 * Find any existing filters with the same match tuple or 578 * else a free slot to insert at. If any of them are busy, 579 * we have to wait and retry. 580 */ 581 for (;;) { 582 ins_index = -1; 583 depth = 1; 584 EFSYS_LOCK(enp->en_eslp, state); 585 locked = B_TRUE; 586 587 for (;;) { 588 i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); 589 saved_spec = ef10_filter_entry_spec(eftp, i); 590 591 if (!saved_spec) { 592 if (ins_index < 0) { 593 ins_index = i; 594 } 595 } else if (ef10_filter_equal(spec, saved_spec)) { 596 if (ef10_filter_entry_is_busy(eftp, i)) 597 break; 598 if (saved_spec->efs_priority 599 == EFX_FILTER_PRI_AUTO) { 600 ins_index = i; 601 goto found; 602 } else if (ef10_filter_is_exclusive(spec)) { 603 if (may_replace) { 604 ins_index = i; 605 goto found; 606 } else { 607 rc = EEXIST; 608 goto fail1; 609 } 610 } 611 612 /* Leave existing */ 613 } 614 615 /* 616 * Once we reach the maximum search depth, use 617 * the first suitable slot or return EBUSY if 618 * there was none. 619 */ 620 if (depth == EF10_FILTER_SEARCH_LIMIT) { 621 if (ins_index < 0) { 622 rc = EBUSY; 623 goto fail2; 624 } 625 goto found; 626 } 627 depth++; 628 } 629 EFSYS_UNLOCK(enp->en_eslp, state); 630 locked = B_FALSE; 631 } 632 633 found: 634 /* 635 * Create a software table entry if necessary, and mark it 636 * busy. We might yet fail to insert, but any attempt to 637 * insert a conflicting filter while we're waiting for the 638 * firmware must find the busy entry. 639 */ 640 saved_spec = ef10_filter_entry_spec(eftp, ins_index); 641 if (saved_spec) { 642 if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) { 643 /* This is a filter we are refreshing */ 644 ef10_filter_set_entry_not_auto_old(eftp, ins_index); 645 goto out_unlock; 646 647 } 648 replacing = B_TRUE; 649 } else { 650 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec); 651 if (!saved_spec) { 652 rc = ENOMEM; 653 goto fail3; 654 } 655 *saved_spec = *spec; 656 ef10_filter_set_entry(eftp, ins_index, saved_spec); 657 } 658 ef10_filter_set_entry_busy(eftp, ins_index); 659 660 EFSYS_UNLOCK(enp->en_eslp, state); 661 locked = B_FALSE; 662 663 /* 664 * On replacing the filter handle may change after after a successful 665 * replace operation. 666 */ 667 if (replacing) { 668 rc = efx_mcdi_filter_op_add(enp, spec, 669 MC_CMD_FILTER_OP_IN_OP_REPLACE, 670 &eftp->eft_entry[ins_index].efe_handle); 671 } else if (ef10_filter_is_exclusive(spec)) { 672 rc = efx_mcdi_filter_op_add(enp, spec, 673 MC_CMD_FILTER_OP_IN_OP_INSERT, 674 &eftp->eft_entry[ins_index].efe_handle); 675 } else { 676 rc = efx_mcdi_filter_op_add(enp, spec, 677 MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, 678 &eftp->eft_entry[ins_index].efe_handle); 679 } 680 681 if (rc != 0) 682 goto fail4; 683 684 EFSYS_LOCK(enp->en_eslp, state); 685 locked = B_TRUE; 686 687 if (replacing) { 688 /* Update the fields that may differ */ 689 saved_spec->efs_priority = spec->efs_priority; 690 saved_spec->efs_flags = spec->efs_flags; 691 saved_spec->efs_rss_context = spec->efs_rss_context; 692 saved_spec->efs_dmaq_id = spec->efs_dmaq_id; 693 } 694 695 ef10_filter_set_entry_not_busy(eftp, ins_index); 696 697 out_unlock: 698 699 EFSYS_UNLOCK(enp->en_eslp, state); 700 locked = B_FALSE; 701 702 if (filter_id) 703 *filter_id = ins_index; 704 705 return (0); 706 707 fail4: 708 EFSYS_PROBE(fail4); 709 710 if (!replacing) { 711 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec); 712 saved_spec = NULL; 713 } 714 ef10_filter_set_entry_not_busy(eftp, ins_index); 715 ef10_filter_set_entry(eftp, ins_index, NULL); 716 717 fail3: 718 EFSYS_PROBE(fail3); 719 720 fail2: 721 EFSYS_PROBE(fail2); 722 723 fail1: 724 EFSYS_PROBE1(fail1, efx_rc_t, rc); 725 726 if (locked) 727 EFSYS_UNLOCK(enp->en_eslp, state); 728 729 return (rc); 730 } 731 732 __checkReturn efx_rc_t 733 ef10_filter_add( 734 __in efx_nic_t *enp, 735 __inout efx_filter_spec_t *spec, 736 __in boolean_t may_replace) 737 { 738 efx_rc_t rc; 739 740 rc = ef10_filter_add_internal(enp, spec, may_replace, NULL); 741 if (rc != 0) 742 goto fail1; 743 744 return (0); 745 746 fail1: 747 EFSYS_PROBE1(fail1, efx_rc_t, rc); 748 749 return (rc); 750 } 751 752 753 static __checkReturn efx_rc_t 754 ef10_filter_delete_internal( 755 __in efx_nic_t *enp, 756 __in uint32_t filter_id) 757 { 758 efx_rc_t rc; 759 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 760 efx_filter_spec_t *spec; 761 int state; 762 uint32_t filter_idx = filter_id % EFX_EF10_FILTER_TBL_ROWS; 763 764 /* 765 * Find the software table entry and mark it busy. Don't 766 * remove it yet; any attempt to update while we're waiting 767 * for the firmware must find the busy entry. 768 * 769 * FIXME: What if the busy flag is never cleared? 770 */ 771 EFSYS_LOCK(enp->en_eslp, state); 772 while (ef10_filter_entry_is_busy(table, filter_idx)) { 773 EFSYS_UNLOCK(enp->en_eslp, state); 774 EFSYS_SPIN(1); 775 EFSYS_LOCK(enp->en_eslp, state); 776 } 777 if ((spec = ef10_filter_entry_spec(table, filter_idx)) != NULL) { 778 ef10_filter_set_entry_busy(table, filter_idx); 779 } 780 EFSYS_UNLOCK(enp->en_eslp, state); 781 782 if (spec == NULL) { 783 rc = ENOENT; 784 goto fail1; 785 } 786 787 /* 788 * Try to remove the hardware filter. This may fail if the MC has 789 * rebooted (which frees all hardware filter resources). 790 */ 791 if (ef10_filter_is_exclusive(spec)) { 792 rc = efx_mcdi_filter_op_delete(enp, 793 MC_CMD_FILTER_OP_IN_OP_REMOVE, 794 &table->eft_entry[filter_idx].efe_handle); 795 } else { 796 rc = efx_mcdi_filter_op_delete(enp, 797 MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE, 798 &table->eft_entry[filter_idx].efe_handle); 799 } 800 801 /* Free the software table entry */ 802 EFSYS_LOCK(enp->en_eslp, state); 803 ef10_filter_set_entry_not_busy(table, filter_idx); 804 ef10_filter_set_entry(table, filter_idx, NULL); 805 EFSYS_UNLOCK(enp->en_eslp, state); 806 807 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec); 808 809 /* Check result of hardware filter removal */ 810 if (rc != 0) 811 goto fail2; 812 813 return (0); 814 815 fail2: 816 EFSYS_PROBE(fail2); 817 818 fail1: 819 EFSYS_PROBE1(fail1, efx_rc_t, rc); 820 821 return (rc); 822 } 823 824 __checkReturn efx_rc_t 825 ef10_filter_delete( 826 __in efx_nic_t *enp, 827 __inout efx_filter_spec_t *spec) 828 { 829 efx_rc_t rc; 830 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 831 efx_filter_spec_t *saved_spec; 832 unsigned int hash; 833 unsigned int depth; 834 unsigned int i; 835 int state; 836 boolean_t locked = B_FALSE; 837 838 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 839 enp->en_family == EFX_FAMILY_MEDFORD); 840 841 hash = ef10_filter_hash(spec); 842 843 EFSYS_LOCK(enp->en_eslp, state); 844 locked = B_TRUE; 845 846 depth = 1; 847 for (;;) { 848 i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); 849 saved_spec = ef10_filter_entry_spec(table, i); 850 if (saved_spec && ef10_filter_equal(spec, saved_spec) && 851 ef10_filter_same_dest(spec, saved_spec)) { 852 break; 853 } 854 if (depth == EF10_FILTER_SEARCH_LIMIT) { 855 rc = ENOENT; 856 goto fail1; 857 } 858 depth++; 859 } 860 861 EFSYS_UNLOCK(enp->en_eslp, state); 862 locked = B_FALSE; 863 864 rc = ef10_filter_delete_internal(enp, i); 865 if (rc != 0) 866 goto fail2; 867 868 return (0); 869 870 fail2: 871 EFSYS_PROBE(fail2); 872 873 fail1: 874 EFSYS_PROBE1(fail1, efx_rc_t, rc); 875 876 if (locked) 877 EFSYS_UNLOCK(enp->en_eslp, state); 878 879 return (rc); 880 } 881 882 static __checkReturn efx_rc_t 883 efx_mcdi_get_parser_disp_info( 884 __in efx_nic_t *enp, 885 __out uint32_t *list, 886 __out size_t *length) 887 { 888 efx_mcdi_req_t req; 889 uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN, 890 MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)]; 891 efx_rc_t rc; 892 uint32_t i; 893 boolean_t support_unknown_ucast = B_FALSE; 894 boolean_t support_unknown_mcast = B_FALSE; 895 896 (void) memset(payload, 0, sizeof (payload)); 897 req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO; 898 req.emr_in_buf = payload; 899 req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN; 900 req.emr_out_buf = payload; 901 req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX; 902 903 MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, 904 MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES); 905 906 efx_mcdi_execute(enp, &req); 907 908 if (req.emr_rc != 0) { 909 rc = req.emr_rc; 910 goto fail1; 911 } 912 913 *length = MCDI_OUT_DWORD(req, 914 GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES); 915 916 if (req.emr_out_length_used < 917 MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(*length)) { 918 rc = EMSGSIZE; 919 goto fail2; 920 } 921 922 (void) memcpy(list, 923 MCDI_OUT2(req, 924 void, 925 GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES), 926 (*length) * sizeof (uint32_t)); 927 EFX_STATIC_ASSERT(sizeof (uint32_t) == 928 MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN); 929 930 /* 931 * Remove UNKNOWN UCAST and MCAST flags, and if both are present, change 932 * the lower priority one to LOC_MAC_IG. 933 */ 934 for (i = 0; i < *length; i++) { 935 if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN) { 936 list[i] &= 937 (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN); 938 support_unknown_ucast = B_TRUE; 939 } 940 if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN) { 941 list[i] &= 942 (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN); 943 support_unknown_mcast = B_TRUE; 944 } 945 946 if (support_unknown_ucast && support_unknown_mcast) { 947 list[i] &= EFX_FILTER_MATCH_LOC_MAC_IG; 948 break; 949 } 950 } 951 952 return (0); 953 954 fail2: 955 EFSYS_PROBE(fail2); 956 fail1: 957 EFSYS_PROBE1(fail1, efx_rc_t, rc); 958 959 return (rc); 960 } 961 962 __checkReturn efx_rc_t 963 ef10_filter_supported_filters( 964 __in efx_nic_t *enp, 965 __out uint32_t *list, 966 __out size_t *length) 967 { 968 efx_rc_t rc; 969 970 if ((rc = efx_mcdi_get_parser_disp_info(enp, list, length)) != 0) 971 goto fail1; 972 973 return (0); 974 975 fail1: 976 EFSYS_PROBE1(fail1, efx_rc_t, rc); 977 978 return (rc); 979 } 980 981 static __checkReturn efx_rc_t 982 ef10_filter_insert_unicast( 983 __in efx_nic_t *enp, 984 __in_ecount(6) uint8_t const *addr, 985 __in efx_filter_flag_t filter_flags) 986 { 987 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 988 efx_filter_spec_t spec; 989 efx_rc_t rc; 990 991 /* Insert the filter for the local station address */ 992 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 993 filter_flags, 994 eftp->eft_default_rxq); 995 (void) efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, 996 addr); 997 998 rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 999 &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]); 1000 if (rc != 0) 1001 goto fail1; 1002 1003 eftp->eft_unicst_filter_count++; 1004 EFSYS_ASSERT(eftp->eft_unicst_filter_count <= 1005 EFX_EF10_FILTER_UNICAST_FILTERS_MAX); 1006 1007 return (0); 1008 1009 fail1: 1010 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1011 return (rc); 1012 } 1013 1014 static __checkReturn efx_rc_t 1015 ef10_filter_insert_all_unicast( 1016 __in efx_nic_t *enp, 1017 __in efx_filter_flag_t filter_flags) 1018 { 1019 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1020 efx_filter_spec_t spec; 1021 efx_rc_t rc; 1022 1023 /* Insert the unknown unicast filter */ 1024 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1025 filter_flags, 1026 eftp->eft_default_rxq); 1027 (void) efx_filter_spec_set_uc_def(&spec); 1028 rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1029 &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]); 1030 if (rc != 0) 1031 goto fail1; 1032 1033 eftp->eft_unicst_filter_count++; 1034 EFSYS_ASSERT(eftp->eft_unicst_filter_count <= 1035 EFX_EF10_FILTER_UNICAST_FILTERS_MAX); 1036 1037 return (0); 1038 1039 fail1: 1040 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1041 return (rc); 1042 } 1043 1044 static __checkReturn efx_rc_t 1045 ef10_filter_insert_multicast_list( 1046 __in efx_nic_t *enp, 1047 __in boolean_t mulcst, 1048 __in boolean_t brdcst, 1049 __in_ecount(6*count) uint8_t const *addrs, 1050 __in uint32_t count, 1051 __in efx_filter_flag_t filter_flags, 1052 __in boolean_t rollback) 1053 { 1054 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1055 efx_filter_spec_t spec; 1056 uint8_t addr[6]; 1057 uint32_t i; 1058 uint32_t filter_index; 1059 uint32_t filter_count; 1060 efx_rc_t rc; 1061 1062 if (mulcst == B_FALSE) 1063 count = 0; 1064 1065 if (count + (brdcst ? 1 : 0) > 1066 EFX_ARRAY_SIZE(eftp->eft_mulcst_filter_indexes)) { 1067 /* Too many MAC addresses */ 1068 rc = EINVAL; 1069 goto fail1; 1070 } 1071 1072 /* Insert/renew multicast address list filters */ 1073 filter_count = 0; 1074 for (i = 0; i < count; i++) { 1075 efx_filter_spec_init_rx(&spec, 1076 EFX_FILTER_PRI_AUTO, 1077 filter_flags, 1078 eftp->eft_default_rxq); 1079 1080 (void) efx_filter_spec_set_eth_local(&spec, 1081 EFX_FILTER_SPEC_VID_UNSPEC, 1082 &addrs[i * EFX_MAC_ADDR_LEN]); 1083 1084 rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1085 &filter_index); 1086 1087 if (rc == 0) { 1088 eftp->eft_mulcst_filter_indexes[filter_count] = 1089 filter_index; 1090 filter_count++; 1091 } else if (rollback == B_TRUE) { 1092 /* Only stop upon failure if told to rollback */ 1093 goto rollback; 1094 } 1095 1096 } 1097 1098 if (brdcst == B_TRUE) { 1099 /* Insert/renew broadcast address filter */ 1100 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1101 filter_flags, 1102 eftp->eft_default_rxq); 1103 1104 EFX_MAC_BROADCAST_ADDR_SET(addr); 1105 (void) efx_filter_spec_set_eth_local(&spec, 1106 EFX_FILTER_SPEC_VID_UNSPEC, 1107 addr); 1108 1109 rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1110 &filter_index); 1111 1112 if (rc == 0) { 1113 eftp->eft_mulcst_filter_indexes[filter_count] = 1114 filter_index; 1115 filter_count++; 1116 } else if (rollback == B_TRUE) { 1117 /* Only stop upon failure if told to rollback */ 1118 goto rollback; 1119 } 1120 } 1121 1122 eftp->eft_mulcst_filter_count = filter_count; 1123 eftp->eft_using_all_mulcst = B_FALSE; 1124 1125 return (0); 1126 1127 rollback: 1128 /* Remove any filters we have inserted */ 1129 i = filter_count; 1130 while (i--) { 1131 (void) ef10_filter_delete_internal(enp, 1132 eftp->eft_mulcst_filter_indexes[i]); 1133 } 1134 eftp->eft_mulcst_filter_count = 0; 1135 1136 fail1: 1137 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1138 1139 return (rc); 1140 } 1141 1142 static __checkReturn efx_rc_t 1143 ef10_filter_insert_all_multicast( 1144 __in efx_nic_t *enp, 1145 __in efx_filter_flag_t filter_flags) 1146 { 1147 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1148 efx_filter_spec_t spec; 1149 efx_rc_t rc; 1150 1151 /* Insert the unknown multicast filter */ 1152 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1153 filter_flags, 1154 eftp->eft_default_rxq); 1155 (void) efx_filter_spec_set_mc_def(&spec); 1156 1157 rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1158 &eftp->eft_mulcst_filter_indexes[0]); 1159 if (rc != 0) 1160 goto fail1; 1161 1162 eftp->eft_mulcst_filter_count = 1; 1163 eftp->eft_using_all_mulcst = B_TRUE; 1164 1165 /* 1166 * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic. 1167 */ 1168 1169 return (0); 1170 1171 fail1: 1172 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1173 1174 return (rc); 1175 } 1176 1177 static void 1178 ef10_filter_remove_old( 1179 __in efx_nic_t *enp) 1180 { 1181 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1182 uint32_t i; 1183 1184 for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { 1185 if (ef10_filter_entry_is_auto_old(table, i)) { 1186 (void) ef10_filter_delete_internal(enp, i); 1187 } 1188 } 1189 } 1190 1191 1192 static __checkReturn efx_rc_t 1193 ef10_filter_get_workarounds( 1194 __in efx_nic_t *enp) 1195 { 1196 efx_nic_cfg_t *encp = &enp->en_nic_cfg; 1197 uint32_t implemented = 0; 1198 uint32_t enabled = 0; 1199 efx_rc_t rc; 1200 1201 rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled); 1202 if (rc == 0) { 1203 /* Check if chained multicast filter support is enabled */ 1204 if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807) 1205 encp->enc_bug26807_workaround = B_TRUE; 1206 else 1207 encp->enc_bug26807_workaround = B_FALSE; 1208 } else if (rc == ENOTSUP) { 1209 /* 1210 * Firmware is too old to support GET_WORKAROUNDS, and support 1211 * for this workaround was implemented later. 1212 */ 1213 encp->enc_bug26807_workaround = B_FALSE; 1214 } else { 1215 goto fail1; 1216 } 1217 1218 return (0); 1219 1220 fail1: 1221 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1222 1223 return (rc); 1224 1225 } 1226 1227 1228 /* 1229 * Reconfigure all filters. 1230 * If all_unicst and/or all mulcst filters cannot be applied then 1231 * return ENOTSUP (Note the filters for the specified addresses are 1232 * still applied in this case). 1233 */ 1234 __checkReturn efx_rc_t 1235 ef10_filter_reconfigure( 1236 __in efx_nic_t *enp, 1237 __in_ecount(6) uint8_t const *mac_addr, 1238 __in boolean_t all_unicst, 1239 __in boolean_t mulcst, 1240 __in boolean_t all_mulcst, 1241 __in boolean_t brdcst, 1242 __in_ecount(6*count) uint8_t const *addrs, 1243 __in uint32_t count) 1244 { 1245 efx_nic_cfg_t *encp = &enp->en_nic_cfg; 1246 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1247 efx_filter_flag_t filter_flags; 1248 unsigned i; 1249 efx_rc_t all_unicst_rc = 0; 1250 efx_rc_t all_mulcst_rc = 0; 1251 efx_rc_t rc; 1252 1253 if (table->eft_default_rxq == NULL) { 1254 /* 1255 * Filters direct traffic to the default RXQ, and so cannot be 1256 * inserted until it is available. Any currently configured 1257 * filters must be removed (ignore errors in case the MC 1258 * has rebooted, which removes hardware filters). 1259 */ 1260 for (i = 0; i < table->eft_unicst_filter_count; i++) { 1261 (void) ef10_filter_delete_internal(enp, 1262 table->eft_unicst_filter_indexes[i]); 1263 } 1264 table->eft_unicst_filter_count = 0; 1265 1266 for (i = 0; i < table->eft_mulcst_filter_count; i++) { 1267 (void) ef10_filter_delete_internal(enp, 1268 table->eft_mulcst_filter_indexes[i]); 1269 } 1270 table->eft_mulcst_filter_count = 0; 1271 1272 return (0); 1273 } 1274 1275 if (table->eft_using_rss) 1276 filter_flags = EFX_FILTER_FLAG_RX_RSS; 1277 else 1278 filter_flags = 0; 1279 1280 /* Mark old filters which may need to be removed */ 1281 for (i = 0; i < table->eft_unicst_filter_count; i++) { 1282 ef10_filter_set_entry_auto_old(table, 1283 table->eft_unicst_filter_indexes[i]); 1284 } 1285 for (i = 0; i < table->eft_mulcst_filter_count; i++) { 1286 ef10_filter_set_entry_auto_old(table, 1287 table->eft_mulcst_filter_indexes[i]); 1288 } 1289 1290 /* 1291 * Insert or renew unicast filters. 1292 * 1293 * Frimware does not perform chaining on unicast filters. As traffic is 1294 * therefore only delivered to the first matching filter, we should 1295 * always insert the specific filter for our MAC address, to try and 1296 * ensure we get that traffic. 1297 * 1298 * (If the filter for our MAC address has already been inserted by 1299 * another function, we won't receive traffic sent to us, even if we 1300 * insert a unicast mismatch filter. To prevent traffic stealing, this 1301 * therefore relies on the privilege model only allowing functions to 1302 * insert filters for their own MAC address unless explicitly given 1303 * additional privileges by the user. This also means that, even on a 1304 * priviliged function, inserting a unicast mismatch filter may not 1305 * catch all traffic in multi PCI function scenarios.) 1306 */ 1307 table->eft_unicst_filter_count = 0; 1308 rc = ef10_filter_insert_unicast(enp, mac_addr, filter_flags); 1309 if (all_unicst || (rc != 0)) { 1310 all_unicst_rc = ef10_filter_insert_all_unicast(enp, 1311 filter_flags); 1312 if ((rc != 0) && (all_unicst_rc != 0)) 1313 goto fail1; 1314 } 1315 1316 /* 1317 * WORKAROUND_BUG26807 controls firmware support for chained multicast 1318 * filters, and can only be enabled or disabled when the hardware filter 1319 * table is empty. 1320 * 1321 * Chained multicast filters require support from the datapath firmware, 1322 * and may not be available (e.g. low-latency variants or old Huntington 1323 * firmware). 1324 * 1325 * Firmware will reset (FLR) functions which have inserted filters in 1326 * the hardware filter table when the workaround is enabled/disabled. 1327 * Functions without any hardware filters are not reset. 1328 * 1329 * Re-check if the workaround is enabled after adding unicast hardware 1330 * filters. This ensures that encp->enc_bug26807_workaround matches the 1331 * firmware state, and that later changes to enable/disable the 1332 * workaround will result in this function seeing a reset (FLR). 1333 * 1334 * In common-code drivers, we only support multiple PCI function 1335 * scenarios with firmware that supports multicast chaining, so we can 1336 * assume it is enabled for such cases and hence simplify the filter 1337 * insertion logic. Firmware that does not support multicast chaining 1338 * does not support multiple PCI function configurations either, so 1339 * filter insertion is much simpler and the same strategies can still be 1340 * used. 1341 */ 1342 if ((rc = ef10_filter_get_workarounds(enp)) != 0) 1343 goto fail2; 1344 1345 if ((table->eft_using_all_mulcst != all_mulcst) && 1346 (encp->enc_bug26807_workaround == B_TRUE)) { 1347 /* 1348 * Multicast filter chaining is enabled, so traffic that matches 1349 * more than one multicast filter will be replicated and 1350 * delivered to multiple recipients. To avoid this duplicate 1351 * delivery, remove old multicast filters before inserting new 1352 * multicast filters. 1353 */ 1354 ef10_filter_remove_old(enp); 1355 } 1356 1357 /* Insert or renew multicast filters */ 1358 if (all_mulcst == B_TRUE) { 1359 /* 1360 * Insert the all multicast filter. If that fails, try to insert 1361 * all of our multicast filters (but without rollback on 1362 * failure). 1363 */ 1364 all_mulcst_rc = ef10_filter_insert_all_multicast(enp, 1365 filter_flags); 1366 if (all_mulcst_rc != 0) { 1367 rc = ef10_filter_insert_multicast_list(enp, B_TRUE, 1368 brdcst, addrs, count, filter_flags, B_FALSE); 1369 if (rc != 0) 1370 goto fail3; 1371 } 1372 } else { 1373 /* 1374 * Insert filters for multicast addresses. 1375 * If any insertion fails, then rollback and try to insert the 1376 * all multicast filter instead. 1377 * If that also fails, try to insert all of the multicast 1378 * filters (but without rollback on failure). 1379 */ 1380 rc = ef10_filter_insert_multicast_list(enp, mulcst, brdcst, 1381 addrs, count, filter_flags, B_TRUE); 1382 if (rc != 0) { 1383 if ((table->eft_using_all_mulcst == B_FALSE) && 1384 (encp->enc_bug26807_workaround == B_TRUE)) { 1385 /* 1386 * Multicast filter chaining is on, so remove 1387 * old filters before inserting the multicast 1388 * all filter to avoid duplicate delivery caused 1389 * by packets matching multiple filters. 1390 */ 1391 ef10_filter_remove_old(enp); 1392 } 1393 1394 rc = ef10_filter_insert_all_multicast(enp, 1395 filter_flags); 1396 if (rc != 0) { 1397 rc = ef10_filter_insert_multicast_list(enp, 1398 mulcst, brdcst, 1399 addrs, count, filter_flags, B_FALSE); 1400 if (rc != 0) 1401 goto fail4; 1402 } 1403 } 1404 } 1405 1406 /* Remove old filters which were not renewed */ 1407 ef10_filter_remove_old(enp); 1408 1409 /* report if any optional flags were rejected */ 1410 if (((all_unicst != B_FALSE) && (all_unicst_rc != 0)) || 1411 ((all_mulcst != B_FALSE) && (all_mulcst_rc != 0))) { 1412 rc = ENOTSUP; 1413 } 1414 1415 return (rc); 1416 1417 fail4: 1418 EFSYS_PROBE(fail4); 1419 fail3: 1420 EFSYS_PROBE(fail3); 1421 fail2: 1422 EFSYS_PROBE(fail2); 1423 fail1: 1424 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1425 1426 /* Clear auto old flags */ 1427 for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { 1428 if (ef10_filter_entry_is_auto_old(table, i)) { 1429 ef10_filter_set_entry_not_auto_old(table, i); 1430 } 1431 } 1432 1433 return (rc); 1434 } 1435 1436 void 1437 ef10_filter_get_default_rxq( 1438 __in efx_nic_t *enp, 1439 __out efx_rxq_t **erpp, 1440 __out boolean_t *using_rss) 1441 { 1442 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1443 1444 *erpp = table->eft_default_rxq; 1445 *using_rss = table->eft_using_rss; 1446 } 1447 1448 1449 void 1450 ef10_filter_default_rxq_set( 1451 __in efx_nic_t *enp, 1452 __in efx_rxq_t *erp, 1453 __in boolean_t using_rss) 1454 { 1455 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1456 1457 #if EFSYS_OPT_RX_SCALE 1458 EFSYS_ASSERT((using_rss == B_FALSE) || 1459 (enp->en_rss_context != EF10_RSS_CONTEXT_INVALID)); 1460 table->eft_using_rss = using_rss; 1461 #else 1462 EFSYS_ASSERT(using_rss == B_FALSE); 1463 table->eft_using_rss = B_FALSE; 1464 #endif 1465 table->eft_default_rxq = erp; 1466 } 1467 1468 void 1469 ef10_filter_default_rxq_clear( 1470 __in efx_nic_t *enp) 1471 { 1472 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1473 1474 table->eft_default_rxq = NULL; 1475 table->eft_using_rss = B_FALSE; 1476 } 1477 1478 1479 #endif /* EFSYS_OPT_FILTER */ 1480 1481 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */