diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst
index 163bc2533f..d66cb76dab 100644
--- a/doc/guides/nics/sfc_efx.rst
+++ b/doc/guides/nics/sfc_efx.rst
@@ -371,6 +371,19 @@ boolean parameters value.
   If this parameter is not specified then ef100 device will operate as
   network device.
 
+- ``switch_mode`` [legacy|switchdev] (see below for default)
+
+  In legacy mode, NIC firmware provides Ethernet virtual bridging (EVB) API
+  to configure switching inside NIC to deliver traffic to physical (PF) and
+  virtual (VF) PCI functions. PF driver is responsible to build the
+  infrastructure for VFs, and traffic goes to/from VF by default in accordance
+  with MAC address assigned, permissions and filters installed by VF drivers.
+  In switchdev mode VF traffic goes via port representor (if any) on PF, and
+  software virtual switch (for example, Open vSwitch) makes the decision.
+  Software virtual switch may install MAE rules to pass established traffic
+  flows via hardware and offload software datapath as the result.
+  Default is legacy.
+
 - ``rx_datapath`` [auto|efx|ef10|ef10_essb] (default **auto**)
 
   Choose receive datapath implementation.
diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 331e06bac6..b045baca9e 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -313,6 +313,8 @@ struct sfc_adapter {
 	boolean_t			tso_encap;
 
 	uint32_t			rxd_wait_timeout_ns;
+
+	bool				switchdev;
 };
 
 static inline struct sfc_adapter_shared *
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index 9dc5e5b3a3..b353bfe358 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -2189,6 +2189,46 @@ sfc_register_dp(void)
 	}
 }
 
+static int
+sfc_parse_switch_mode(struct sfc_adapter *sa)
+{
+	const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
+	const char *switch_mode = NULL;
+	int rc;
+
+	sfc_log_init(sa, "entry");
+
+	rc = sfc_kvargs_process(sa, SFC_KVARG_SWITCH_MODE,
+				sfc_kvarg_string_handler, &switch_mode);
+	if (rc != 0)
+		goto fail_kvargs;
+
+	if (switch_mode == NULL) {
+		sa->switchdev = encp->enc_mae_supported &&
+				!encp->enc_datapath_cap_evb;
+	} else if (strcasecmp(switch_mode, SFC_KVARG_SWITCH_MODE_LEGACY) == 0) {
+		sa->switchdev = false;
+	} else if (strcasecmp(switch_mode,
+			      SFC_KVARG_SWITCH_MODE_SWITCHDEV) == 0) {
+		sa->switchdev = true;
+	} else {
+		sfc_err(sa, "invalid switch mode device argument '%s'",
+			switch_mode);
+		rc = EINVAL;
+		goto fail_mode;
+	}
+
+	sfc_log_init(sa, "done");
+
+	return 0;
+
+fail_mode:
+fail_kvargs:
+	sfc_log_init(sa, "failed: %s", rte_strerror(rc));
+
+	return rc;
+}
+
 static int
 sfc_eth_dev_init(struct rte_eth_dev *dev)
 {
@@ -2276,6 +2316,14 @@ sfc_eth_dev_init(struct rte_eth_dev *dev)
 	if (rc != 0)
 		goto fail_probe;
 
+	/*
+	 * Selecting a default switch mode requires the NIC to be probed and
+	 * to have its capabilities filled in.
+	 */
+	rc = sfc_parse_switch_mode(sa);
+	if (rc != 0)
+		goto fail_switch_mode;
+
 	sfc_log_init(sa, "set device ops");
 	rc = sfc_eth_dev_set_ops(dev);
 	if (rc != 0)
@@ -2286,6 +2334,13 @@ sfc_eth_dev_init(struct rte_eth_dev *dev)
 	if (rc != 0)
 		goto fail_attach;
 
+	if (sa->switchdev && sa->mae.status != SFC_MAE_STATUS_SUPPORTED) {
+		sfc_err(sa,
+			"failed to enable switchdev mode without MAE support");
+		rc = ENOTSUP;
+		goto fail_switchdev_no_mae;
+	}
+
 	encp = efx_nic_cfg_get(sa->nic);
 
 	/*
@@ -2300,10 +2355,14 @@ sfc_eth_dev_init(struct rte_eth_dev *dev)
 	sfc_log_init(sa, "done");
 	return 0;
 
+fail_switchdev_no_mae:
+	sfc_detach(sa);
+
 fail_attach:
 	sfc_eth_dev_clear_ops(dev);
 
 fail_set_ops:
+fail_switch_mode:
 	sfc_unprobe(sa);
 
 fail_probe:
@@ -2371,6 +2430,7 @@ RTE_PMD_REGISTER_PCI(net_sfc_efx, sfc_efx_pmd);
 RTE_PMD_REGISTER_PCI_TABLE(net_sfc_efx, pci_id_sfc_efx_map);
 RTE_PMD_REGISTER_KMOD_DEP(net_sfc_efx, "* igb_uio | uio_pci_generic | vfio-pci");
 RTE_PMD_REGISTER_PARAM_STRING(net_sfc_efx,
+	SFC_KVARG_SWITCH_MODE "=" SFC_KVARG_VALUES_SWITCH_MODE " "
 	SFC_KVARG_RX_DATAPATH "=" SFC_KVARG_VALUES_RX_DATAPATH " "
 	SFC_KVARG_TX_DATAPATH "=" SFC_KVARG_VALUES_TX_DATAPATH " "
 	SFC_KVARG_PERF_PROFILE "=" SFC_KVARG_VALUES_PERF_PROFILE " "
diff --git a/drivers/net/sfc/sfc_kvargs.c b/drivers/net/sfc/sfc_kvargs.c
index 974c05e68e..cd16213637 100644
--- a/drivers/net/sfc/sfc_kvargs.c
+++ b/drivers/net/sfc/sfc_kvargs.c
@@ -22,6 +22,7 @@ sfc_kvargs_parse(struct sfc_adapter *sa)
 	struct rte_eth_dev *eth_dev = (sa)->eth_dev;
 	struct rte_devargs *devargs = eth_dev->device->devargs;
 	const char **params = (const char *[]){
+		SFC_KVARG_SWITCH_MODE,
 		SFC_KVARG_STATS_UPDATE_PERIOD_MS,
 		SFC_KVARG_PERF_PROFILE,
 		SFC_KVARG_RX_DATAPATH,
diff --git a/drivers/net/sfc/sfc_kvargs.h b/drivers/net/sfc/sfc_kvargs.h
index ff76e7d9fc..8e34ec92a2 100644
--- a/drivers/net/sfc/sfc_kvargs.h
+++ b/drivers/net/sfc/sfc_kvargs.h
@@ -18,6 +18,14 @@ extern "C" {
 
 #define SFC_KVARG_VALUES_BOOL		"[1|y|yes|on|0|n|no|off]"
 
+#define SFC_KVARG_SWITCH_MODE_LEGACY	"legacy"
+#define SFC_KVARG_SWITCH_MODE_SWITCHDEV	"switchdev"
+
+#define SFC_KVARG_SWITCH_MODE		"switch_mode"
+#define SFC_KVARG_VALUES_SWITCH_MODE \
+	"[" SFC_KVARG_SWITCH_MODE_LEGACY "|" \
+	    SFC_KVARG_SWITCH_MODE_SWITCHDEV "]"
+
 #define SFC_KVARG_PERF_PROFILE		"perf_profile"
 
 #define SFC_KVARG_PERF_PROFILE_AUTO		"auto"
diff --git a/drivers/net/sfc/sfc_sriov.c b/drivers/net/sfc/sfc_sriov.c
index baa0242433..385b172e2e 100644
--- a/drivers/net/sfc/sfc_sriov.c
+++ b/drivers/net/sfc/sfc_sriov.c
@@ -53,7 +53,7 @@ sfc_sriov_attach(struct sfc_adapter *sa)
 	sfc_log_init(sa, "entry");
 
 	sriov->num_vfs = pci_dev->max_vfs;
-	if (sriov->num_vfs == 0)
+	if (sa->switchdev || sriov->num_vfs == 0)
 		goto done;
 
 	vport_config = calloc(sriov->num_vfs + 1, sizeof(*vport_config));
@@ -110,6 +110,11 @@ sfc_sriov_vswitch_create(struct sfc_adapter *sa)
 
 	sfc_log_init(sa, "entry");
 
+	if (sa->switchdev) {
+		sfc_log_init(sa, "don't create vswitch in switchdev mode");
+		goto done;
+	}
+
 	if (sriov->num_vfs == 0) {
 		sfc_log_init(sa, "no VFs enabled");
 		goto done;
@@ -152,7 +157,7 @@ sfc_sriov_vswitch_destroy(struct sfc_adapter *sa)
 
 	sfc_log_init(sa, "entry");
 
-	if (sriov->num_vfs == 0)
+	if (sa->switchdev || sriov->num_vfs == 0)
 		goto done;
 
 	rc = efx_evb_vswitch_destroy(sa->nic, sriov->vswitch);
