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 */