ef10_filter.c revision 342440
1/*- 2 * Copyright (c) 2007-2016 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/11/sys/dev/sfxge/common/ef10_filter.c 342440 2018-12-25 07:20:41Z 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_EXT_IN_MATCH_SRC_IP)); 130 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_HOST == 131 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_IP)); 132 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_MAC == 133 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_MAC)); 134 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_PORT == 135 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_PORT)); 136 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_MAC == 137 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_MAC)); 138 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_PORT == 139 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_PORT)); 140 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_ETHER_TYPE == 141 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_ETHER_TYPE)); 142 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_INNER_VID == 143 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_INNER_VLAN)); 144 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_OUTER_VID == 145 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN)); 146 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO == 147 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO)); 148 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST == 149 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST)); 150 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST == 151 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_UCAST_DST)); 152 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_UNKNOWN_MCAST_DST == 153 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_MCAST_DST)); 154 EFX_STATIC_ASSERT((uint32_t)EFX_FILTER_MATCH_UNKNOWN_UCAST_DST == 155 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_UCAST_DST)); 156#undef MATCH_MASK 157 158 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (ef10_filter_table_t), eftp); 159 160 if (!eftp) { 161 rc = ENOMEM; 162 goto fail1; 163 } 164 165 enp->en_filter.ef_ef10_filter_table = eftp; 166 167 return (0); 168 169fail1: 170 EFSYS_PROBE1(fail1, efx_rc_t, rc); 171 172 return (rc); 173} 174 175 void 176ef10_filter_fini( 177 __in efx_nic_t *enp) 178{ 179 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 180 enp->en_family == EFX_FAMILY_MEDFORD); 181 182 if (enp->en_filter.ef_ef10_filter_table != NULL) { 183 EFSYS_KMEM_FREE(enp->en_esip, sizeof (ef10_filter_table_t), 184 enp->en_filter.ef_ef10_filter_table); 185 } 186} 187 188static __checkReturn efx_rc_t 189efx_mcdi_filter_op_add( 190 __in efx_nic_t *enp, 191 __in efx_filter_spec_t *spec, 192 __in unsigned int filter_op, 193 __inout ef10_filter_handle_t *handle) 194{ 195 efx_mcdi_req_t req; 196 uint8_t payload[MAX(MC_CMD_FILTER_OP_EXT_IN_LEN, 197 MC_CMD_FILTER_OP_EXT_OUT_LEN)]; 198 efx_rc_t rc; 199 200 memset(payload, 0, sizeof (payload)); 201 req.emr_cmd = MC_CMD_FILTER_OP; 202 req.emr_in_buf = payload; 203 req.emr_in_length = MC_CMD_FILTER_OP_EXT_IN_LEN; 204 req.emr_out_buf = payload; 205 req.emr_out_length = MC_CMD_FILTER_OP_EXT_OUT_LEN; 206 207 switch (filter_op) { 208 case MC_CMD_FILTER_OP_IN_OP_REPLACE: 209 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_LO, 210 handle->efh_lo); 211 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_HI, 212 handle->efh_hi); 213 /* Fall through */ 214 case MC_CMD_FILTER_OP_IN_OP_INSERT: 215 case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE: 216 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP, filter_op); 217 break; 218 default: 219 EFSYS_ASSERT(0); 220 rc = EINVAL; 221 goto fail1; 222 } 223 224 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_PORT_ID, 225 EVB_PORT_ID_ASSIGNED); 226 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_MATCH_FIELDS, 227 spec->efs_match_flags); 228 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_DEST, 229 MC_CMD_FILTER_OP_EXT_IN_RX_DEST_HOST); 230 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_QUEUE, 231 spec->efs_dmaq_id); 232 if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) { 233 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_CONTEXT, 234 spec->efs_rss_context); 235 } 236 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_MODE, 237 spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ? 238 MC_CMD_FILTER_OP_EXT_IN_RX_MODE_RSS : 239 MC_CMD_FILTER_OP_EXT_IN_RX_MODE_SIMPLE); 240 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_TX_DEST, 241 MC_CMD_FILTER_OP_EXT_IN_TX_DEST_DEFAULT); 242 243 if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) { 244 /* 245 * NOTE: Unlike most MCDI requests, the filter fields 246 * are presented in network (big endian) byte order. 247 */ 248 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_SRC_MAC), 249 spec->efs_rem_mac, EFX_MAC_ADDR_LEN); 250 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_DST_MAC), 251 spec->efs_loc_mac, EFX_MAC_ADDR_LEN); 252 253 MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_SRC_PORT, 254 __CPU_TO_BE_16(spec->efs_rem_port)); 255 MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_DST_PORT, 256 __CPU_TO_BE_16(spec->efs_loc_port)); 257 258 MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_ETHER_TYPE, 259 __CPU_TO_BE_16(spec->efs_ether_type)); 260 261 MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_INNER_VLAN, 262 __CPU_TO_BE_16(spec->efs_inner_vid)); 263 MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_OUTER_VLAN, 264 __CPU_TO_BE_16(spec->efs_outer_vid)); 265 266 /* IP protocol (in low byte, high byte is zero) */ 267 MCDI_IN_SET_BYTE(req, FILTER_OP_EXT_IN_IP_PROTO, 268 spec->efs_ip_proto); 269 270 EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) == 271 MC_CMD_FILTER_OP_EXT_IN_SRC_IP_LEN); 272 EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) == 273 MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN); 274 275 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_SRC_IP), 276 &spec->efs_rem_host.eo_byte[0], 277 MC_CMD_FILTER_OP_EXT_IN_SRC_IP_LEN); 278 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_DST_IP), 279 &spec->efs_loc_host.eo_byte[0], 280 MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN); 281 282 /* 283 * On Medford, filters for encapsulated packets match based on 284 * the ether type and IP protocol in the outer frame. In 285 * addition we need to fill in the VNI or VSID type field. 286 */ 287 switch (spec->efs_encap_type) { 288 case EFX_TUNNEL_PROTOCOL_NONE: 289 break; 290 case EFX_TUNNEL_PROTOCOL_VXLAN: 291 case EFX_TUNNEL_PROTOCOL_GENEVE: 292 MCDI_IN_POPULATE_DWORD_1(req, 293 FILTER_OP_EXT_IN_VNI_OR_VSID, 294 FILTER_OP_EXT_IN_VNI_TYPE, 295 spec->efs_encap_type == EFX_TUNNEL_PROTOCOL_VXLAN ? 296 MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_VXLAN : 297 MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_GENEVE); 298 break; 299 case EFX_TUNNEL_PROTOCOL_NVGRE: 300 MCDI_IN_POPULATE_DWORD_1(req, 301 FILTER_OP_EXT_IN_VNI_OR_VSID, 302 FILTER_OP_EXT_IN_VSID_TYPE, 303 MC_CMD_FILTER_OP_EXT_IN_VSID_TYPE_NVGRE); 304 break; 305 default: 306 EFSYS_ASSERT(0); 307 rc = EINVAL; 308 goto fail2; 309 } 310 } 311 312 efx_mcdi_execute(enp, &req); 313 314 if (req.emr_rc != 0) { 315 rc = req.emr_rc; 316 goto fail3; 317 } 318 319 if (req.emr_out_length_used < MC_CMD_FILTER_OP_EXT_OUT_LEN) { 320 rc = EMSGSIZE; 321 goto fail4; 322 } 323 324 handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_EXT_OUT_HANDLE_LO); 325 handle->efh_hi = MCDI_OUT_DWORD(req, FILTER_OP_EXT_OUT_HANDLE_HI); 326 327 return (0); 328 329fail4: 330 EFSYS_PROBE(fail4); 331fail3: 332 EFSYS_PROBE(fail3); 333fail2: 334 EFSYS_PROBE(fail2); 335fail1: 336 EFSYS_PROBE1(fail1, efx_rc_t, rc); 337 338 return (rc); 339 340} 341 342static __checkReturn efx_rc_t 343efx_mcdi_filter_op_delete( 344 __in efx_nic_t *enp, 345 __in unsigned int filter_op, 346 __inout ef10_filter_handle_t *handle) 347{ 348 efx_mcdi_req_t req; 349 uint8_t payload[MAX(MC_CMD_FILTER_OP_EXT_IN_LEN, 350 MC_CMD_FILTER_OP_EXT_OUT_LEN)]; 351 efx_rc_t rc; 352 353 memset(payload, 0, sizeof (payload)); 354 req.emr_cmd = MC_CMD_FILTER_OP; 355 req.emr_in_buf = payload; 356 req.emr_in_length = MC_CMD_FILTER_OP_EXT_IN_LEN; 357 req.emr_out_buf = payload; 358 req.emr_out_length = MC_CMD_FILTER_OP_EXT_OUT_LEN; 359 360 switch (filter_op) { 361 case MC_CMD_FILTER_OP_IN_OP_REMOVE: 362 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP, 363 MC_CMD_FILTER_OP_IN_OP_REMOVE); 364 break; 365 case MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE: 366 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP, 367 MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE); 368 break; 369 default: 370 EFSYS_ASSERT(0); 371 rc = EINVAL; 372 goto fail1; 373 } 374 375 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_LO, handle->efh_lo); 376 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_HI, handle->efh_hi); 377 378 efx_mcdi_execute_quiet(enp, &req); 379 380 if (req.emr_rc != 0) { 381 rc = req.emr_rc; 382 goto fail2; 383 } 384 385 if (req.emr_out_length_used < MC_CMD_FILTER_OP_EXT_OUT_LEN) { 386 rc = EMSGSIZE; 387 goto fail3; 388 } 389 390 return (0); 391 392fail3: 393 EFSYS_PROBE(fail3); 394 395fail2: 396 EFSYS_PROBE(fail2); 397fail1: 398 EFSYS_PROBE1(fail1, efx_rc_t, rc); 399 400 return (rc); 401} 402 403static __checkReturn boolean_t 404ef10_filter_equal( 405 __in const efx_filter_spec_t *left, 406 __in const efx_filter_spec_t *right) 407{ 408 /* FIXME: Consider rx vs tx filters (look at efs_flags) */ 409 if (left->efs_match_flags != right->efs_match_flags) 410 return (B_FALSE); 411 if (!EFX_OWORD_IS_EQUAL(left->efs_rem_host, right->efs_rem_host)) 412 return (B_FALSE); 413 if (!EFX_OWORD_IS_EQUAL(left->efs_loc_host, right->efs_loc_host)) 414 return (B_FALSE); 415 if (memcmp(left->efs_rem_mac, right->efs_rem_mac, EFX_MAC_ADDR_LEN)) 416 return (B_FALSE); 417 if (memcmp(left->efs_loc_mac, right->efs_loc_mac, EFX_MAC_ADDR_LEN)) 418 return (B_FALSE); 419 if (left->efs_rem_port != right->efs_rem_port) 420 return (B_FALSE); 421 if (left->efs_loc_port != right->efs_loc_port) 422 return (B_FALSE); 423 if (left->efs_inner_vid != right->efs_inner_vid) 424 return (B_FALSE); 425 if (left->efs_outer_vid != right->efs_outer_vid) 426 return (B_FALSE); 427 if (left->efs_ether_type != right->efs_ether_type) 428 return (B_FALSE); 429 if (left->efs_ip_proto != right->efs_ip_proto) 430 return (B_FALSE); 431 if (left->efs_encap_type != right->efs_encap_type) 432 return (B_FALSE); 433 434 return (B_TRUE); 435 436} 437 438static __checkReturn boolean_t 439ef10_filter_same_dest( 440 __in const efx_filter_spec_t *left, 441 __in const efx_filter_spec_t *right) 442{ 443 if ((left->efs_flags & EFX_FILTER_FLAG_RX_RSS) && 444 (right->efs_flags & EFX_FILTER_FLAG_RX_RSS)) { 445 if (left->efs_rss_context == right->efs_rss_context) 446 return (B_TRUE); 447 } else if ((~(left->efs_flags) & EFX_FILTER_FLAG_RX_RSS) && 448 (~(right->efs_flags) & EFX_FILTER_FLAG_RX_RSS)) { 449 if (left->efs_dmaq_id == right->efs_dmaq_id) 450 return (B_TRUE); 451 } 452 return (B_FALSE); 453} 454 455static __checkReturn uint32_t 456ef10_filter_hash( 457 __in efx_filter_spec_t *spec) 458{ 459 EFX_STATIC_ASSERT((sizeof (efx_filter_spec_t) % sizeof (uint32_t)) 460 == 0); 461 EFX_STATIC_ASSERT((EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid) % 462 sizeof (uint32_t)) == 0); 463 464 /* 465 * As the area of the efx_filter_spec_t we need to hash is DWORD 466 * aligned and an exact number of DWORDs in size we can use the 467 * optimised efx_hash_dwords() rather than efx_hash_bytes() 468 */ 469 return (efx_hash_dwords((const uint32_t *)&spec->efs_outer_vid, 470 (sizeof (efx_filter_spec_t) - 471 EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid)) / 472 sizeof (uint32_t), 0)); 473} 474 475/* 476 * Decide whether a filter should be exclusive or else should allow 477 * delivery to additional recipients. Currently we decide that 478 * filters for specific local unicast MAC and IP addresses are 479 * exclusive. 480 */ 481static __checkReturn boolean_t 482ef10_filter_is_exclusive( 483 __in efx_filter_spec_t *spec) 484{ 485 if ((spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC) && 486 !EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) 487 return (B_TRUE); 488 489 if ((spec->efs_match_flags & 490 (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) == 491 (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) { 492 if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV4) && 493 ((spec->efs_loc_host.eo_u8[0] & 0xf) != 0xe)) 494 return (B_TRUE); 495 if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV6) && 496 (spec->efs_loc_host.eo_u8[0] != 0xff)) 497 return (B_TRUE); 498 } 499 500 return (B_FALSE); 501} 502 503 __checkReturn efx_rc_t 504ef10_filter_restore( 505 __in efx_nic_t *enp) 506{ 507 int tbl_id; 508 efx_filter_spec_t *spec; 509 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 510 boolean_t restoring; 511 efsys_lock_state_t state; 512 efx_rc_t rc; 513 514 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 515 enp->en_family == EFX_FAMILY_MEDFORD); 516 517 for (tbl_id = 0; tbl_id < EFX_EF10_FILTER_TBL_ROWS; tbl_id++) { 518 519 EFSYS_LOCK(enp->en_eslp, state); 520 521 spec = ef10_filter_entry_spec(eftp, tbl_id); 522 if (spec == NULL) { 523 restoring = B_FALSE; 524 } else if (ef10_filter_entry_is_busy(eftp, tbl_id)) { 525 /* Ignore busy entries. */ 526 restoring = B_FALSE; 527 } else { 528 ef10_filter_set_entry_busy(eftp, tbl_id); 529 restoring = B_TRUE; 530 } 531 532 EFSYS_UNLOCK(enp->en_eslp, state); 533 534 if (restoring == B_FALSE) 535 continue; 536 537 if (ef10_filter_is_exclusive(spec)) { 538 rc = efx_mcdi_filter_op_add(enp, spec, 539 MC_CMD_FILTER_OP_IN_OP_INSERT, 540 &eftp->eft_entry[tbl_id].efe_handle); 541 } else { 542 rc = efx_mcdi_filter_op_add(enp, spec, 543 MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, 544 &eftp->eft_entry[tbl_id].efe_handle); 545 } 546 547 if (rc != 0) 548 goto fail1; 549 550 EFSYS_LOCK(enp->en_eslp, state); 551 552 ef10_filter_set_entry_not_busy(eftp, tbl_id); 553 554 EFSYS_UNLOCK(enp->en_eslp, state); 555 } 556 557 return (0); 558 559fail1: 560 EFSYS_PROBE1(fail1, efx_rc_t, rc); 561 562 return (rc); 563} 564 565/* 566 * An arbitrary search limit for the software hash table. As per the linux net 567 * driver. 568 */ 569#define EF10_FILTER_SEARCH_LIMIT 200 570 571static __checkReturn efx_rc_t 572ef10_filter_add_internal( 573 __in efx_nic_t *enp, 574 __inout efx_filter_spec_t *spec, 575 __in boolean_t may_replace, 576 __out_opt uint32_t *filter_id) 577{ 578 efx_rc_t rc; 579 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 580 efx_filter_spec_t *saved_spec; 581 uint32_t hash; 582 unsigned int depth; 583 int ins_index; 584 boolean_t replacing = B_FALSE; 585 unsigned int i; 586 efsys_lock_state_t state; 587 boolean_t locked = B_FALSE; 588 589 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 590 enp->en_family == EFX_FAMILY_MEDFORD); 591 592#if EFSYS_OPT_RX_SCALE 593 spec->efs_rss_context = enp->en_rss_context; 594#endif 595 596 hash = ef10_filter_hash(spec); 597 598 /* 599 * FIXME: Add support for inserting filters of different priorities 600 * and removing lower priority multicast filters (bug 42378) 601 */ 602 603 /* 604 * Find any existing filters with the same match tuple or 605 * else a free slot to insert at. If any of them are busy, 606 * we have to wait and retry. 607 */ 608 for (;;) { 609 ins_index = -1; 610 depth = 1; 611 EFSYS_LOCK(enp->en_eslp, state); 612 locked = B_TRUE; 613 614 for (;;) { 615 i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); 616 saved_spec = ef10_filter_entry_spec(eftp, i); 617 618 if (!saved_spec) { 619 if (ins_index < 0) { 620 ins_index = i; 621 } 622 } else if (ef10_filter_equal(spec, saved_spec)) { 623 if (ef10_filter_entry_is_busy(eftp, i)) 624 break; 625 if (saved_spec->efs_priority 626 == EFX_FILTER_PRI_AUTO) { 627 ins_index = i; 628 goto found; 629 } else if (ef10_filter_is_exclusive(spec)) { 630 if (may_replace) { 631 ins_index = i; 632 goto found; 633 } else { 634 rc = EEXIST; 635 goto fail1; 636 } 637 } 638 639 /* Leave existing */ 640 } 641 642 /* 643 * Once we reach the maximum search depth, use 644 * the first suitable slot or return EBUSY if 645 * there was none. 646 */ 647 if (depth == EF10_FILTER_SEARCH_LIMIT) { 648 if (ins_index < 0) { 649 rc = EBUSY; 650 goto fail2; 651 } 652 goto found; 653 } 654 depth++; 655 } 656 EFSYS_UNLOCK(enp->en_eslp, state); 657 locked = B_FALSE; 658 } 659 660found: 661 /* 662 * Create a software table entry if necessary, and mark it 663 * busy. We might yet fail to insert, but any attempt to 664 * insert a conflicting filter while we're waiting for the 665 * firmware must find the busy entry. 666 */ 667 saved_spec = ef10_filter_entry_spec(eftp, ins_index); 668 if (saved_spec) { 669 if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) { 670 /* This is a filter we are refreshing */ 671 ef10_filter_set_entry_not_auto_old(eftp, ins_index); 672 goto out_unlock; 673 674 } 675 replacing = B_TRUE; 676 } else { 677 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec); 678 if (!saved_spec) { 679 rc = ENOMEM; 680 goto fail3; 681 } 682 *saved_spec = *spec; 683 ef10_filter_set_entry(eftp, ins_index, saved_spec); 684 } 685 ef10_filter_set_entry_busy(eftp, ins_index); 686 687 EFSYS_UNLOCK(enp->en_eslp, state); 688 locked = B_FALSE; 689 690 /* 691 * On replacing the filter handle may change after after a successful 692 * replace operation. 693 */ 694 if (replacing) { 695 rc = efx_mcdi_filter_op_add(enp, spec, 696 MC_CMD_FILTER_OP_IN_OP_REPLACE, 697 &eftp->eft_entry[ins_index].efe_handle); 698 } else if (ef10_filter_is_exclusive(spec)) { 699 rc = efx_mcdi_filter_op_add(enp, spec, 700 MC_CMD_FILTER_OP_IN_OP_INSERT, 701 &eftp->eft_entry[ins_index].efe_handle); 702 } else { 703 rc = efx_mcdi_filter_op_add(enp, spec, 704 MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, 705 &eftp->eft_entry[ins_index].efe_handle); 706 } 707 708 if (rc != 0) 709 goto fail4; 710 711 EFSYS_LOCK(enp->en_eslp, state); 712 locked = B_TRUE; 713 714 if (replacing) { 715 /* Update the fields that may differ */ 716 saved_spec->efs_priority = spec->efs_priority; 717 saved_spec->efs_flags = spec->efs_flags; 718 saved_spec->efs_rss_context = spec->efs_rss_context; 719 saved_spec->efs_dmaq_id = spec->efs_dmaq_id; 720 } 721 722 ef10_filter_set_entry_not_busy(eftp, ins_index); 723 724out_unlock: 725 726 EFSYS_UNLOCK(enp->en_eslp, state); 727 locked = B_FALSE; 728 729 if (filter_id) 730 *filter_id = ins_index; 731 732 return (0); 733 734fail4: 735 EFSYS_PROBE(fail4); 736 737 if (!replacing) { 738 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec); 739 saved_spec = NULL; 740 } 741 ef10_filter_set_entry_not_busy(eftp, ins_index); 742 ef10_filter_set_entry(eftp, ins_index, NULL); 743 744fail3: 745 EFSYS_PROBE(fail3); 746 747fail2: 748 EFSYS_PROBE(fail2); 749 750fail1: 751 EFSYS_PROBE1(fail1, efx_rc_t, rc); 752 753 if (locked) 754 EFSYS_UNLOCK(enp->en_eslp, state); 755 756 return (rc); 757} 758 759 __checkReturn efx_rc_t 760ef10_filter_add( 761 __in efx_nic_t *enp, 762 __inout efx_filter_spec_t *spec, 763 __in boolean_t may_replace) 764{ 765 efx_rc_t rc; 766 767 rc = ef10_filter_add_internal(enp, spec, may_replace, NULL); 768 if (rc != 0) 769 goto fail1; 770 771 return (0); 772 773fail1: 774 EFSYS_PROBE1(fail1, efx_rc_t, rc); 775 776 return (rc); 777} 778 779 780static __checkReturn efx_rc_t 781ef10_filter_delete_internal( 782 __in efx_nic_t *enp, 783 __in uint32_t filter_id) 784{ 785 efx_rc_t rc; 786 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 787 efx_filter_spec_t *spec; 788 efsys_lock_state_t state; 789 uint32_t filter_idx = filter_id % EFX_EF10_FILTER_TBL_ROWS; 790 791 /* 792 * Find the software table entry and mark it busy. Don't 793 * remove it yet; any attempt to update while we're waiting 794 * for the firmware must find the busy entry. 795 * 796 * FIXME: What if the busy flag is never cleared? 797 */ 798 EFSYS_LOCK(enp->en_eslp, state); 799 while (ef10_filter_entry_is_busy(table, filter_idx)) { 800 EFSYS_UNLOCK(enp->en_eslp, state); 801 EFSYS_SPIN(1); 802 EFSYS_LOCK(enp->en_eslp, state); 803 } 804 if ((spec = ef10_filter_entry_spec(table, filter_idx)) != NULL) { 805 ef10_filter_set_entry_busy(table, filter_idx); 806 } 807 EFSYS_UNLOCK(enp->en_eslp, state); 808 809 if (spec == NULL) { 810 rc = ENOENT; 811 goto fail1; 812 } 813 814 /* 815 * Try to remove the hardware filter. This may fail if the MC has 816 * rebooted (which frees all hardware filter resources). 817 */ 818 if (ef10_filter_is_exclusive(spec)) { 819 rc = efx_mcdi_filter_op_delete(enp, 820 MC_CMD_FILTER_OP_IN_OP_REMOVE, 821 &table->eft_entry[filter_idx].efe_handle); 822 } else { 823 rc = efx_mcdi_filter_op_delete(enp, 824 MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE, 825 &table->eft_entry[filter_idx].efe_handle); 826 } 827 828 /* Free the software table entry */ 829 EFSYS_LOCK(enp->en_eslp, state); 830 ef10_filter_set_entry_not_busy(table, filter_idx); 831 ef10_filter_set_entry(table, filter_idx, NULL); 832 EFSYS_UNLOCK(enp->en_eslp, state); 833 834 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec); 835 836 /* Check result of hardware filter removal */ 837 if (rc != 0) 838 goto fail2; 839 840 return (0); 841 842fail2: 843 EFSYS_PROBE(fail2); 844 845fail1: 846 EFSYS_PROBE1(fail1, efx_rc_t, rc); 847 848 return (rc); 849} 850 851 __checkReturn efx_rc_t 852ef10_filter_delete( 853 __in efx_nic_t *enp, 854 __inout efx_filter_spec_t *spec) 855{ 856 efx_rc_t rc; 857 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 858 efx_filter_spec_t *saved_spec; 859 unsigned int hash; 860 unsigned int depth; 861 unsigned int i; 862 efsys_lock_state_t state; 863 boolean_t locked = B_FALSE; 864 865 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 866 enp->en_family == EFX_FAMILY_MEDFORD); 867 868 hash = ef10_filter_hash(spec); 869 870 EFSYS_LOCK(enp->en_eslp, state); 871 locked = B_TRUE; 872 873 depth = 1; 874 for (;;) { 875 i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); 876 saved_spec = ef10_filter_entry_spec(table, i); 877 if (saved_spec && ef10_filter_equal(spec, saved_spec) && 878 ef10_filter_same_dest(spec, saved_spec)) { 879 break; 880 } 881 if (depth == EF10_FILTER_SEARCH_LIMIT) { 882 rc = ENOENT; 883 goto fail1; 884 } 885 depth++; 886 } 887 888 EFSYS_UNLOCK(enp->en_eslp, state); 889 locked = B_FALSE; 890 891 rc = ef10_filter_delete_internal(enp, i); 892 if (rc != 0) 893 goto fail2; 894 895 return (0); 896 897fail2: 898 EFSYS_PROBE(fail2); 899 900fail1: 901 EFSYS_PROBE1(fail1, efx_rc_t, rc); 902 903 if (locked) 904 EFSYS_UNLOCK(enp->en_eslp, state); 905 906 return (rc); 907} 908 909static __checkReturn efx_rc_t 910efx_mcdi_get_parser_disp_info( 911 __in efx_nic_t *enp, 912 __out_ecount(buffer_length) uint32_t *buffer, 913 __in size_t buffer_length, 914 __out size_t *list_lengthp) 915{ 916 efx_mcdi_req_t req; 917 uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN, 918 MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)]; 919 size_t matches_count; 920 size_t list_size; 921 efx_rc_t rc; 922 923 (void) memset(payload, 0, sizeof (payload)); 924 req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO; 925 req.emr_in_buf = payload; 926 req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN; 927 req.emr_out_buf = payload; 928 req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX; 929 930 MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, 931 MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES); 932 933 efx_mcdi_execute(enp, &req); 934 935 if (req.emr_rc != 0) { 936 rc = req.emr_rc; 937 goto fail1; 938 } 939 940 matches_count = MCDI_OUT_DWORD(req, 941 GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES); 942 943 if (req.emr_out_length_used < 944 MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(matches_count)) { 945 rc = EMSGSIZE; 946 goto fail2; 947 } 948 949 *list_lengthp = matches_count; 950 951 if (buffer_length < matches_count) { 952 rc = ENOSPC; 953 goto fail3; 954 } 955 956 /* 957 * Check that the elements in the list in the MCDI response are the size 958 * we expect, so we can just copy them directly. Any conversion of the 959 * flags is handled by the caller. 960 */ 961 EFX_STATIC_ASSERT(sizeof (uint32_t) == 962 MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN); 963 964 list_size = matches_count * 965 MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN; 966 memcpy(buffer, 967 MCDI_OUT2(req, uint32_t, 968 GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES), 969 list_size); 970 971 return (0); 972 973fail3: 974 EFSYS_PROBE(fail3); 975fail2: 976 EFSYS_PROBE(fail2); 977fail1: 978 EFSYS_PROBE1(fail1, efx_rc_t, rc); 979 980 return (rc); 981} 982 983 __checkReturn efx_rc_t 984ef10_filter_supported_filters( 985 __in efx_nic_t *enp, 986 __out_ecount(buffer_length) uint32_t *buffer, 987 __in size_t buffer_length, 988 __out size_t *list_lengthp) 989{ 990 991 size_t mcdi_list_length; 992 size_t list_length; 993 uint32_t i; 994 efx_rc_t rc; 995 efx_filter_match_flags_t all_filter_flags = 996 (EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_LOC_HOST | 997 EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_REM_PORT | 998 EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_PORT | 999 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_INNER_VID | 1000 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_IP_PROTO | 1001 EFX_FILTER_MATCH_UNKNOWN_MCAST_DST | 1002 EFX_FILTER_MATCH_UNKNOWN_UCAST_DST); 1003 1004 rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length, 1005 &mcdi_list_length); 1006 if (rc != 0) { 1007 if (rc == ENOSPC) { 1008 /* Pass through mcdi_list_length for the list length */ 1009 *list_lengthp = mcdi_list_length; 1010 } 1011 goto fail1; 1012 } 1013 1014 /* 1015 * The static assertions in ef10_filter_init() ensure that the values of 1016 * the EFX_FILTER_MATCH flags match those used by MCDI, so they don't 1017 * need to be converted. 1018 * 1019 * In case support is added to MCDI for additional flags, remove any 1020 * matches from the list which include flags we don't support. The order 1021 * of the matches is preserved as they are ordered from highest to 1022 * lowest priority. 1023 */ 1024 EFSYS_ASSERT(mcdi_list_length <= buffer_length); 1025 list_length = 0; 1026 for (i = 0; i < mcdi_list_length; i++) { 1027 if ((buffer[i] & ~all_filter_flags) == 0) { 1028 buffer[list_length] = buffer[i]; 1029 list_length++; 1030 } 1031 } 1032 1033 *list_lengthp = list_length; 1034 1035 return (0); 1036 1037fail1: 1038 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1039 1040 return (rc); 1041} 1042 1043static __checkReturn efx_rc_t 1044ef10_filter_insert_unicast( 1045 __in efx_nic_t *enp, 1046 __in_ecount(6) uint8_t const *addr, 1047 __in efx_filter_flags_t filter_flags) 1048{ 1049 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1050 efx_filter_spec_t spec; 1051 efx_rc_t rc; 1052 1053 /* Insert the filter for the local station address */ 1054 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1055 filter_flags, 1056 eftp->eft_default_rxq); 1057 rc = efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, 1058 addr); 1059 if (rc != 0) 1060 goto fail1; 1061 1062 rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1063 &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]); 1064 if (rc != 0) 1065 goto fail2; 1066 1067 eftp->eft_unicst_filter_count++; 1068 EFSYS_ASSERT(eftp->eft_unicst_filter_count <= 1069 EFX_EF10_FILTER_UNICAST_FILTERS_MAX); 1070 1071 return (0); 1072 1073fail2: 1074 EFSYS_PROBE(fail2); 1075fail1: 1076 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1077 return (rc); 1078} 1079 1080static __checkReturn efx_rc_t 1081ef10_filter_insert_all_unicast( 1082 __in efx_nic_t *enp, 1083 __in efx_filter_flags_t filter_flags) 1084{ 1085 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1086 efx_filter_spec_t spec; 1087 efx_rc_t rc; 1088 1089 /* Insert the unknown unicast filter */ 1090 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1091 filter_flags, 1092 eftp->eft_default_rxq); 1093 rc = efx_filter_spec_set_uc_def(&spec); 1094 if (rc != 0) 1095 goto fail1; 1096 rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1097 &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]); 1098 if (rc != 0) 1099 goto fail2; 1100 1101 eftp->eft_unicst_filter_count++; 1102 EFSYS_ASSERT(eftp->eft_unicst_filter_count <= 1103 EFX_EF10_FILTER_UNICAST_FILTERS_MAX); 1104 1105 return (0); 1106 1107fail2: 1108 EFSYS_PROBE(fail2); 1109fail1: 1110 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1111 return (rc); 1112} 1113 1114static __checkReturn efx_rc_t 1115ef10_filter_insert_multicast_list( 1116 __in efx_nic_t *enp, 1117 __in boolean_t mulcst, 1118 __in boolean_t brdcst, 1119 __in_ecount(6*count) uint8_t const *addrs, 1120 __in uint32_t count, 1121 __in efx_filter_flags_t filter_flags, 1122 __in boolean_t rollback) 1123{ 1124 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1125 efx_filter_spec_t spec; 1126 uint8_t addr[6]; 1127 uint32_t i; 1128 uint32_t filter_index; 1129 uint32_t filter_count; 1130 efx_rc_t rc; 1131 1132 if (mulcst == B_FALSE) 1133 count = 0; 1134 1135 if (count + (brdcst ? 1 : 0) > 1136 EFX_ARRAY_SIZE(eftp->eft_mulcst_filter_indexes)) { 1137 /* Too many MAC addresses */ 1138 rc = EINVAL; 1139 goto fail1; 1140 } 1141 1142 /* Insert/renew multicast address list filters */ 1143 filter_count = 0; 1144 for (i = 0; i < count; i++) { 1145 efx_filter_spec_init_rx(&spec, 1146 EFX_FILTER_PRI_AUTO, 1147 filter_flags, 1148 eftp->eft_default_rxq); 1149 1150 rc = efx_filter_spec_set_eth_local(&spec, 1151 EFX_FILTER_SPEC_VID_UNSPEC, 1152 &addrs[i * EFX_MAC_ADDR_LEN]); 1153 if (rc != 0) { 1154 if (rollback == B_TRUE) { 1155 /* Only stop upon failure if told to rollback */ 1156 goto rollback; 1157 } else { 1158 /* 1159 * Don't try to add a filter with a corrupt 1160 * specification. 1161 */ 1162 continue; 1163 } 1164 } 1165 1166 rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1167 &filter_index); 1168 1169 if (rc == 0) { 1170 eftp->eft_mulcst_filter_indexes[filter_count] = 1171 filter_index; 1172 filter_count++; 1173 } else if (rollback == B_TRUE) { 1174 /* Only stop upon failure if told to rollback */ 1175 goto rollback; 1176 } 1177 1178 } 1179 1180 if (brdcst == B_TRUE) { 1181 /* Insert/renew broadcast address filter */ 1182 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1183 filter_flags, 1184 eftp->eft_default_rxq); 1185 1186 EFX_MAC_BROADCAST_ADDR_SET(addr); 1187 rc = efx_filter_spec_set_eth_local(&spec, 1188 EFX_FILTER_SPEC_VID_UNSPEC, addr); 1189 if ((rc != 0) && (rollback == B_TRUE)) { 1190 /* Only stop upon failure if told to rollback */ 1191 goto rollback; 1192 } 1193 1194 rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1195 &filter_index); 1196 1197 if (rc == 0) { 1198 eftp->eft_mulcst_filter_indexes[filter_count] = 1199 filter_index; 1200 filter_count++; 1201 } else if (rollback == B_TRUE) { 1202 /* Only stop upon failure if told to rollback */ 1203 goto rollback; 1204 } 1205 } 1206 1207 eftp->eft_mulcst_filter_count = filter_count; 1208 eftp->eft_using_all_mulcst = B_FALSE; 1209 1210 return (0); 1211 1212rollback: 1213 /* Remove any filters we have inserted */ 1214 i = filter_count; 1215 while (i--) { 1216 (void) ef10_filter_delete_internal(enp, 1217 eftp->eft_mulcst_filter_indexes[i]); 1218 } 1219 eftp->eft_mulcst_filter_count = 0; 1220 1221fail1: 1222 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1223 1224 return (rc); 1225} 1226 1227static __checkReturn efx_rc_t 1228ef10_filter_insert_all_multicast( 1229 __in efx_nic_t *enp, 1230 __in efx_filter_flags_t filter_flags) 1231{ 1232 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1233 efx_filter_spec_t spec; 1234 efx_rc_t rc; 1235 1236 /* Insert the unknown multicast filter */ 1237 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1238 filter_flags, 1239 eftp->eft_default_rxq); 1240 rc = efx_filter_spec_set_mc_def(&spec); 1241 if (rc != 0) 1242 goto fail1; 1243 1244 rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1245 &eftp->eft_mulcst_filter_indexes[0]); 1246 if (rc != 0) 1247 goto fail2; 1248 1249 eftp->eft_mulcst_filter_count = 1; 1250 eftp->eft_using_all_mulcst = B_TRUE; 1251 1252 /* 1253 * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic. 1254 */ 1255 1256 return (0); 1257 1258fail2: 1259 EFSYS_PROBE(fail2); 1260fail1: 1261 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1262 1263 return (rc); 1264} 1265 1266typedef struct ef10_filter_encap_entry_s { 1267 uint16_t ether_type; 1268 efx_tunnel_protocol_t encap_type; 1269 uint32_t inner_frame_match; 1270} ef10_filter_encap_entry_t; 1271 1272#define EF10_ENCAP_FILTER_ENTRY(ipv, encap_type, inner_frame_match) \ 1273 { EFX_ETHER_TYPE_##ipv, EFX_TUNNEL_PROTOCOL_##encap_type, \ 1274 EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_##inner_frame_match } 1275 1276static ef10_filter_encap_entry_t ef10_filter_encap_list[] = { 1277 EF10_ENCAP_FILTER_ENTRY(IPV4, VXLAN, UCAST_DST), 1278 EF10_ENCAP_FILTER_ENTRY(IPV4, VXLAN, MCAST_DST), 1279 EF10_ENCAP_FILTER_ENTRY(IPV6, VXLAN, UCAST_DST), 1280 EF10_ENCAP_FILTER_ENTRY(IPV6, VXLAN, MCAST_DST), 1281 1282 EF10_ENCAP_FILTER_ENTRY(IPV4, GENEVE, UCAST_DST), 1283 EF10_ENCAP_FILTER_ENTRY(IPV4, GENEVE, MCAST_DST), 1284 EF10_ENCAP_FILTER_ENTRY(IPV6, GENEVE, UCAST_DST), 1285 EF10_ENCAP_FILTER_ENTRY(IPV6, GENEVE, MCAST_DST), 1286 1287 EF10_ENCAP_FILTER_ENTRY(IPV4, NVGRE, UCAST_DST), 1288 EF10_ENCAP_FILTER_ENTRY(IPV4, NVGRE, MCAST_DST), 1289 EF10_ENCAP_FILTER_ENTRY(IPV6, NVGRE, UCAST_DST), 1290 EF10_ENCAP_FILTER_ENTRY(IPV6, NVGRE, MCAST_DST), 1291}; 1292 1293#undef EF10_ENCAP_FILTER_ENTRY 1294 1295static __checkReturn efx_rc_t 1296ef10_filter_insert_encap_filters( 1297 __in efx_nic_t *enp, 1298 __in boolean_t mulcst, 1299 __in efx_filter_flags_t filter_flags) 1300{ 1301 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1302 uint32_t i; 1303 efx_rc_t rc; 1304 1305 EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(ef10_filter_encap_list) <= 1306 EFX_ARRAY_SIZE(table->eft_encap_filter_indexes)); 1307 1308 /* 1309 * On Medford, full-featured firmware can identify packets as being 1310 * tunnel encapsulated, even if no encapsulated packet offloads are in 1311 * use. When packets are identified as such, ordinary filters are not 1312 * applied, only ones specific to encapsulated packets. Hence we need to 1313 * insert filters for encapsulated packets in order to receive them. 1314 * 1315 * Separate filters need to be inserted for each ether type, 1316 * encapsulation type, and inner frame type (unicast or multicast). To 1317 * keep things simple and reduce the number of filters needed, catch-all 1318 * filters for all combinations of types are inserted, even if 1319 * all_unicst or all_mulcst have not been set. (These catch-all filters 1320 * may well, however, fail to insert on unprivileged functions.) 1321 */ 1322 table->eft_encap_filter_count = 0; 1323 for (i = 0; i < EFX_ARRAY_SIZE(ef10_filter_encap_list); i++) { 1324 efx_filter_spec_t spec; 1325 ef10_filter_encap_entry_t *encap_filter = 1326 &ef10_filter_encap_list[i]; 1327 1328 /* 1329 * Skip multicast filters if we've not been asked for 1330 * any multicast traffic. 1331 */ 1332 if ((mulcst == B_FALSE) && 1333 (encap_filter->inner_frame_match == 1334 EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST)) 1335 continue; 1336 1337 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1338 filter_flags, 1339 table->eft_default_rxq); 1340 efx_filter_spec_set_ether_type(&spec, encap_filter->ether_type); 1341 rc = efx_filter_spec_set_encap_type(&spec, 1342 encap_filter->encap_type, 1343 encap_filter->inner_frame_match); 1344 if (rc != 0) 1345 goto fail1; 1346 1347 rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1348 &table->eft_encap_filter_indexes[ 1349 table->eft_encap_filter_count]); 1350 if (rc != 0) { 1351 if (rc != EACCES) 1352 goto fail2; 1353 } else { 1354 table->eft_encap_filter_count++; 1355 } 1356 } 1357 1358 return (0); 1359 1360fail2: 1361 EFSYS_PROBE(fail2); 1362fail1: 1363 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1364 1365 return (rc); 1366} 1367 1368static void 1369ef10_filter_remove_old( 1370 __in efx_nic_t *enp) 1371{ 1372 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1373 uint32_t i; 1374 1375 for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { 1376 if (ef10_filter_entry_is_auto_old(table, i)) { 1377 (void) ef10_filter_delete_internal(enp, i); 1378 } 1379 } 1380} 1381 1382 1383static __checkReturn efx_rc_t 1384ef10_filter_get_workarounds( 1385 __in efx_nic_t *enp) 1386{ 1387 efx_nic_cfg_t *encp = &enp->en_nic_cfg; 1388 uint32_t implemented = 0; 1389 uint32_t enabled = 0; 1390 efx_rc_t rc; 1391 1392 rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled); 1393 if (rc == 0) { 1394 /* Check if chained multicast filter support is enabled */ 1395 if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807) 1396 encp->enc_bug26807_workaround = B_TRUE; 1397 else 1398 encp->enc_bug26807_workaround = B_FALSE; 1399 } else if (rc == ENOTSUP) { 1400 /* 1401 * Firmware is too old to support GET_WORKAROUNDS, and support 1402 * for this workaround was implemented later. 1403 */ 1404 encp->enc_bug26807_workaround = B_FALSE; 1405 } else { 1406 goto fail1; 1407 } 1408 1409 return (0); 1410 1411fail1: 1412 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1413 1414 return (rc); 1415 1416} 1417 1418 1419/* 1420 * Reconfigure all filters. 1421 * If all_unicst and/or all mulcst filters cannot be applied then 1422 * return ENOTSUP (Note the filters for the specified addresses are 1423 * still applied in this case). 1424 */ 1425 __checkReturn efx_rc_t 1426ef10_filter_reconfigure( 1427 __in efx_nic_t *enp, 1428 __in_ecount(6) uint8_t const *mac_addr, 1429 __in boolean_t all_unicst, 1430 __in boolean_t mulcst, 1431 __in boolean_t all_mulcst, 1432 __in boolean_t brdcst, 1433 __in_ecount(6*count) uint8_t const *addrs, 1434 __in uint32_t count) 1435{ 1436 efx_nic_cfg_t *encp = &enp->en_nic_cfg; 1437 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1438 efx_filter_flags_t filter_flags; 1439 unsigned int i; 1440 efx_rc_t all_unicst_rc = 0; 1441 efx_rc_t all_mulcst_rc = 0; 1442 efx_rc_t rc; 1443 1444 if (table->eft_default_rxq == NULL) { 1445 /* 1446 * Filters direct traffic to the default RXQ, and so cannot be 1447 * inserted until it is available. Any currently configured 1448 * filters must be removed (ignore errors in case the MC 1449 * has rebooted, which removes hardware filters). 1450 */ 1451 for (i = 0; i < table->eft_unicst_filter_count; i++) { 1452 (void) ef10_filter_delete_internal(enp, 1453 table->eft_unicst_filter_indexes[i]); 1454 } 1455 table->eft_unicst_filter_count = 0; 1456 1457 for (i = 0; i < table->eft_mulcst_filter_count; i++) { 1458 (void) ef10_filter_delete_internal(enp, 1459 table->eft_mulcst_filter_indexes[i]); 1460 } 1461 table->eft_mulcst_filter_count = 0; 1462 1463 for (i = 0; i < table->eft_encap_filter_count; i++) { 1464 (void) ef10_filter_delete_internal(enp, 1465 table->eft_encap_filter_indexes[i]); 1466 } 1467 table->eft_encap_filter_count = 0; 1468 1469 return (0); 1470 } 1471 1472 if (table->eft_using_rss) 1473 filter_flags = EFX_FILTER_FLAG_RX_RSS; 1474 else 1475 filter_flags = 0; 1476 1477 /* Mark old filters which may need to be removed */ 1478 for (i = 0; i < table->eft_unicst_filter_count; i++) { 1479 ef10_filter_set_entry_auto_old(table, 1480 table->eft_unicst_filter_indexes[i]); 1481 } 1482 for (i = 0; i < table->eft_mulcst_filter_count; i++) { 1483 ef10_filter_set_entry_auto_old(table, 1484 table->eft_mulcst_filter_indexes[i]); 1485 } 1486 for (i = 0; i < table->eft_encap_filter_count; i++) { 1487 ef10_filter_set_entry_auto_old(table, 1488 table->eft_encap_filter_indexes[i]); 1489 } 1490 1491 /* 1492 * Insert or renew unicast filters. 1493 * 1494 * Frimware does not perform chaining on unicast filters. As traffic is 1495 * therefore only delivered to the first matching filter, we should 1496 * always insert the specific filter for our MAC address, to try and 1497 * ensure we get that traffic. 1498 * 1499 * (If the filter for our MAC address has already been inserted by 1500 * another function, we won't receive traffic sent to us, even if we 1501 * insert a unicast mismatch filter. To prevent traffic stealing, this 1502 * therefore relies on the privilege model only allowing functions to 1503 * insert filters for their own MAC address unless explicitly given 1504 * additional privileges by the user. This also means that, even on a 1505 * priviliged function, inserting a unicast mismatch filter may not 1506 * catch all traffic in multi PCI function scenarios.) 1507 */ 1508 table->eft_unicst_filter_count = 0; 1509 rc = ef10_filter_insert_unicast(enp, mac_addr, filter_flags); 1510 if (all_unicst || (rc != 0)) { 1511 all_unicst_rc = ef10_filter_insert_all_unicast(enp, 1512 filter_flags); 1513 if ((rc != 0) && (all_unicst_rc != 0)) 1514 goto fail1; 1515 } 1516 1517 /* 1518 * WORKAROUND_BUG26807 controls firmware support for chained multicast 1519 * filters, and can only be enabled or disabled when the hardware filter 1520 * table is empty. 1521 * 1522 * Chained multicast filters require support from the datapath firmware, 1523 * and may not be available (e.g. low-latency variants or old Huntington 1524 * firmware). 1525 * 1526 * Firmware will reset (FLR) functions which have inserted filters in 1527 * the hardware filter table when the workaround is enabled/disabled. 1528 * Functions without any hardware filters are not reset. 1529 * 1530 * Re-check if the workaround is enabled after adding unicast hardware 1531 * filters. This ensures that encp->enc_bug26807_workaround matches the 1532 * firmware state, and that later changes to enable/disable the 1533 * workaround will result in this function seeing a reset (FLR). 1534 * 1535 * In common-code drivers, we only support multiple PCI function 1536 * scenarios with firmware that supports multicast chaining, so we can 1537 * assume it is enabled for such cases and hence simplify the filter 1538 * insertion logic. Firmware that does not support multicast chaining 1539 * does not support multiple PCI function configurations either, so 1540 * filter insertion is much simpler and the same strategies can still be 1541 * used. 1542 */ 1543 if ((rc = ef10_filter_get_workarounds(enp)) != 0) 1544 goto fail2; 1545 1546 if ((table->eft_using_all_mulcst != all_mulcst) && 1547 (encp->enc_bug26807_workaround == B_TRUE)) { 1548 /* 1549 * Multicast filter chaining is enabled, so traffic that matches 1550 * more than one multicast filter will be replicated and 1551 * delivered to multiple recipients. To avoid this duplicate 1552 * delivery, remove old multicast filters before inserting new 1553 * multicast filters. 1554 */ 1555 ef10_filter_remove_old(enp); 1556 } 1557 1558 /* Insert or renew multicast filters */ 1559 if (all_mulcst == B_TRUE) { 1560 /* 1561 * Insert the all multicast filter. If that fails, try to insert 1562 * all of our multicast filters (but without rollback on 1563 * failure). 1564 */ 1565 all_mulcst_rc = ef10_filter_insert_all_multicast(enp, 1566 filter_flags); 1567 if (all_mulcst_rc != 0) { 1568 rc = ef10_filter_insert_multicast_list(enp, B_TRUE, 1569 brdcst, addrs, count, filter_flags, B_FALSE); 1570 if (rc != 0) 1571 goto fail3; 1572 } 1573 } else { 1574 /* 1575 * Insert filters for multicast addresses. 1576 * If any insertion fails, then rollback and try to insert the 1577 * all multicast filter instead. 1578 * If that also fails, try to insert all of the multicast 1579 * filters (but without rollback on failure). 1580 */ 1581 rc = ef10_filter_insert_multicast_list(enp, mulcst, brdcst, 1582 addrs, count, filter_flags, B_TRUE); 1583 if (rc != 0) { 1584 if ((table->eft_using_all_mulcst == B_FALSE) && 1585 (encp->enc_bug26807_workaround == B_TRUE)) { 1586 /* 1587 * Multicast filter chaining is on, so remove 1588 * old filters before inserting the multicast 1589 * all filter to avoid duplicate delivery caused 1590 * by packets matching multiple filters. 1591 */ 1592 ef10_filter_remove_old(enp); 1593 } 1594 1595 rc = ef10_filter_insert_all_multicast(enp, 1596 filter_flags); 1597 if (rc != 0) { 1598 rc = ef10_filter_insert_multicast_list(enp, 1599 mulcst, brdcst, 1600 addrs, count, filter_flags, B_FALSE); 1601 if (rc != 0) 1602 goto fail4; 1603 } 1604 } 1605 } 1606 1607 if (encp->enc_tunnel_encapsulations_supported != 0) { 1608 /* Try to insert filters for encapsulated packets. */ 1609 (void) ef10_filter_insert_encap_filters(enp, 1610 mulcst || all_mulcst || brdcst, 1611 filter_flags); 1612 } 1613 1614 /* Remove old filters which were not renewed */ 1615 ef10_filter_remove_old(enp); 1616 1617 /* report if any optional flags were rejected */ 1618 if (((all_unicst != B_FALSE) && (all_unicst_rc != 0)) || 1619 ((all_mulcst != B_FALSE) && (all_mulcst_rc != 0))) { 1620 rc = ENOTSUP; 1621 } 1622 1623 return (rc); 1624 1625fail4: 1626 EFSYS_PROBE(fail4); 1627fail3: 1628 EFSYS_PROBE(fail3); 1629fail2: 1630 EFSYS_PROBE(fail2); 1631fail1: 1632 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1633 1634 /* Clear auto old flags */ 1635 for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { 1636 if (ef10_filter_entry_is_auto_old(table, i)) { 1637 ef10_filter_set_entry_not_auto_old(table, i); 1638 } 1639 } 1640 1641 return (rc); 1642} 1643 1644 void 1645ef10_filter_get_default_rxq( 1646 __in efx_nic_t *enp, 1647 __out efx_rxq_t **erpp, 1648 __out boolean_t *using_rss) 1649{ 1650 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1651 1652 *erpp = table->eft_default_rxq; 1653 *using_rss = table->eft_using_rss; 1654} 1655 1656 1657 void 1658ef10_filter_default_rxq_set( 1659 __in efx_nic_t *enp, 1660 __in efx_rxq_t *erp, 1661 __in boolean_t using_rss) 1662{ 1663 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1664 1665#if EFSYS_OPT_RX_SCALE 1666 EFSYS_ASSERT((using_rss == B_FALSE) || 1667 (enp->en_rss_context != EF10_RSS_CONTEXT_INVALID)); 1668 table->eft_using_rss = using_rss; 1669#else 1670 EFSYS_ASSERT(using_rss == B_FALSE); 1671 table->eft_using_rss = B_FALSE; 1672#endif 1673 table->eft_default_rxq = erp; 1674} 1675 1676 void 1677ef10_filter_default_rxq_clear( 1678 __in efx_nic_t *enp) 1679{ 1680 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1681 1682 table->eft_default_rxq = NULL; 1683 table->eft_using_rss = B_FALSE; 1684} 1685 1686 1687#endif /* EFSYS_OPT_FILTER */ 1688 1689#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 1690