+
+static boolean_t
+sfc_get_requested_all_ucast(struct sfc_port *port)
+{
+ return port->promisc;
+}
+
+static boolean_t
+sfc_get_requested_all_mcast(struct sfc_port *port)
+{
+ return port->promisc || port->allmulti;
+}
+
+int
+sfc_set_rx_mode_unchecked(struct sfc_adapter *sa)
+{
+ struct sfc_port *port = &sa->port;
+ boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port);
+ boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port);
+ int rc;
+
+ rc = efx_mac_filter_set(sa->nic, requested_all_ucast, B_TRUE,
+ requested_all_mcast, B_TRUE);
+ if (rc != 0)
+ return rc;
+
+ return 0;
+}
+
+int
+sfc_set_rx_mode(struct sfc_adapter *sa)
+{
+ struct sfc_port *port = &sa->port;
+ boolean_t old_all_ucast;
+ boolean_t old_all_mcast;
+ boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port);
+ boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port);
+ boolean_t actual_all_ucast;
+ boolean_t actual_all_mcast;
+ int rc;
+
+ efx_mac_filter_get_all_ucast_mcast(sa->nic, &old_all_ucast,
+ &old_all_mcast);
+
+ rc = sfc_set_rx_mode_unchecked(sa);
+ if (rc != 0)
+ return rc;
+
+ efx_mac_filter_get_all_ucast_mcast(sa->nic, &actual_all_ucast,
+ &actual_all_mcast);
+
+ if (actual_all_ucast != requested_all_ucast ||
+ actual_all_mcast != requested_all_mcast) {
+ /*
+ * MAC filter set succeeded but not all requested modes
+ * were applied. The rollback is necessary to bring back the
+ * consistent old state.
+ */
+ (void)efx_mac_filter_set(sa->nic, old_all_ucast, B_TRUE,
+ old_all_mcast, B_TRUE);
+
+ return EPERM;
+ }
+
+ return 0;
+}
+
+void
+sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
+ struct rte_eth_link *link_info)
+{
+ SFC_ASSERT(link_mode < EFX_LINK_NMODES);
+
+ memset(link_info, 0, sizeof(*link_info));
+ if ((link_mode == EFX_LINK_DOWN) || (link_mode == EFX_LINK_UNKNOWN))
+ link_info->link_status = ETH_LINK_DOWN;
+ else
+ link_info->link_status = ETH_LINK_UP;
+
+ switch (link_mode) {
+ case EFX_LINK_10HDX:
+ link_info->link_speed = ETH_SPEED_NUM_10M;
+ link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
+ break;
+ case EFX_LINK_10FDX:
+ link_info->link_speed = ETH_SPEED_NUM_10M;
+ link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
+ break;
+ case EFX_LINK_100HDX:
+ link_info->link_speed = ETH_SPEED_NUM_100M;
+ link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
+ break;
+ case EFX_LINK_100FDX:
+ link_info->link_speed = ETH_SPEED_NUM_100M;
+ link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
+ break;
+ case EFX_LINK_1000HDX:
+ link_info->link_speed = ETH_SPEED_NUM_1G;
+ link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
+ break;
+ case EFX_LINK_1000FDX:
+ link_info->link_speed = ETH_SPEED_NUM_1G;
+ link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
+ break;
+ case EFX_LINK_10000FDX:
+ link_info->link_speed = ETH_SPEED_NUM_10G;
+ link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
+ break;
+ case EFX_LINK_25000FDX:
+ link_info->link_speed = ETH_SPEED_NUM_25G;
+ link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
+ break;
+ case EFX_LINK_40000FDX:
+ link_info->link_speed = ETH_SPEED_NUM_40G;
+ link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
+ break;
+ case EFX_LINK_50000FDX:
+ link_info->link_speed = ETH_SPEED_NUM_50G;
+ link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
+ break;
+ case EFX_LINK_100000FDX:
+ link_info->link_speed = ETH_SPEED_NUM_100G;
+ link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
+ break;
+ default:
+ SFC_ASSERT(B_FALSE);
+ /* FALLTHROUGH */
+ case EFX_LINK_UNKNOWN:
+ case EFX_LINK_DOWN:
+ link_info->link_speed = ETH_SPEED_NUM_NONE;
+ link_info->link_duplex = 0;
+ break;
+ }
+
+ link_info->link_autoneg = ETH_LINK_AUTONEG;
+}