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