The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/sfxge/common/ef10_filter.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 6cd484a08f15392e8e9ff0c091501c65


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.