From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <dev-bounces@dpdk.org>
Received: from dpdk.org (dpdk.org [92.243.14.124])
	by dpdk.space (Postfix) with ESMTP id 19AFCA0495
	for <public@inbox.dpdk.org>; Mon, 10 Jun 2019 09:40:57 +0200 (CEST)
Received: from [92.243.14.124] (localhost [127.0.0.1])
	by dpdk.org (Postfix) with ESMTP id 69C991BF0C;
	Mon, 10 Jun 2019 09:39:26 +0200 (CEST)
Received: from dispatch1-us1.ppe-hosted.com (dispatch1-us1.ppe-hosted.com
 [67.231.154.164]) by dpdk.org (Postfix) with ESMTP id C551D1BE99
 for <dev@dpdk.org>; Mon, 10 Jun 2019 09:38:56 +0200 (CEST)
X-Virus-Scanned: Proofpoint Essentials engine
Received: from webmail.solarflare.com (webmail.solarflare.com [12.187.104.26])
 (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits))
 (No client certificate requested)
 by mx1-us5.ppe-hosted.com (PPE Hosted ESMTP Server) with ESMTPS id D75084C0058
 for <dev@dpdk.org>; Mon, 10 Jun 2019 07:38:55 +0000 (UTC)
Received: from ocex03.SolarFlarecom.com (10.20.40.36) by
 ocex03.SolarFlarecom.com (10.20.40.36) with Microsoft SMTP Server (TLS) id
 15.0.1395.4; Mon, 10 Jun 2019 00:38:51 -0700
Received: from opal.uk.solarflarecom.com (10.17.10.1) by
 ocex03.SolarFlarecom.com (10.20.40.36) with Microsoft SMTP Server (TLS) id
 15.0.1395.4 via Frontend Transport; Mon, 10 Jun 2019 00:38:51 -0700
Received: from ukv-loginhost.uk.solarflarecom.com
 (ukv-loginhost.uk.solarflarecom.com [10.17.10.39])
 by opal.uk.solarflarecom.com (8.13.8/8.13.8) with ESMTP id x5A7cou7008841;
 Mon, 10 Jun 2019 08:38:50 +0100
Received: from ukv-loginhost.uk.solarflarecom.com (localhost [127.0.0.1])
 by ukv-loginhost.uk.solarflarecom.com (Postfix) with ESMTP id 0BEB01627D7;
 Mon, 10 Jun 2019 08:38:50 +0100 (BST)
From: Andrew Rybchenko <arybchenko@solarflare.com>
To: <dev@dpdk.org>
CC: Gautam Dawar <gdawar@solarflare.com>
Date: Mon, 10 Jun 2019 08:38:36 +0100
Message-ID: <1560152324-20538-22-git-send-email-arybchenko@solarflare.com>
X-Mailer: git-send-email 1.8.3.1
In-Reply-To: <1560152324-20538-1-git-send-email-arybchenko@solarflare.com>
References: <1560152324-20538-1-git-send-email-arybchenko@solarflare.com>
MIME-Version: 1.0
Content-Type: text/plain
X-TM-AS-Product-Ver: SMEX-12.5.0.1300-8.5.1010-24664.003
X-TM-AS-Result: No-7.145600-4.000000-10
X-TMASE-MatchedRID: +engLLOnT3btSrqhUiNirv3HILfxLV/969xONVZSrH3mWHHSYEnI8dWZ
 DZFp9sK+qHdHXw8EW4pTvVffeIwvQ8HVNeDWrWSGnFVnNmvv47vGzDycs+smMN9RlPzeVuQQqjq
 FxcD2zqTueEO1qlH4lCVURVaeV0Rggb1XSSpDa5DnZxuPj9aY+ytTx/ehjzxgj4jFvt2M5IKZu9
 GZpmUaWCqO1+vEcPReqb1YkDVelmHdXve1wYbDSiXTnAZkhKflQo4ZOAclX1K+GYmD5FwZEpKi/
 9O2b8wfIEbqlyPU4c5HhDA5WM1bF61mYT2CMxpdGjzBgnFZvQ66hgVvSdGKo3QWhLVqLFM1KDvv
 C6BqZx61DpGeEMqeQGzHwL0ty3zWGHO3b96QmYNAwvZYEy8IBdUtYzexhQ5/JLfQYoCQHFYTw7j
 CStQ0rmpecsbV1dfSKbxcKDI8Nr+9j8fJltl0iJ4CIKY/Hg3AGdQnQSTrKGPEQdG7H66TyMdRT5
 TQAJnAdDAOSXoybxqKeGZtJ2CYhChe8at/tBZ0IlAn8VS3Z3qeqD9WtJkSIw==
X-TM-AS-User-Approved-Sender: No
X-TM-AS-User-Blocked-Sender: No
X-TMASE-Result: 10--7.145600-4.000000
X-TMASE-Version: SMEX-12.5.0.1300-8.5.1010-24664.003
X-MDID: 1560152336-6kkX4IQLwkMf
Subject: [dpdk-dev] [PATCH 21/29] net/sfc/base: implement vSwitch
	create/destroy
X-BeenThere: dev@dpdk.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id: DPDK patches and discussions <dev.dpdk.org>
List-Unsubscribe: <https://mails.dpdk.org/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://mails.dpdk.org/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <https://mails.dpdk.org/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
Errors-To: dev-bounces@dpdk.org
Sender: "dev" <dev-bounces@dpdk.org>

From: Gautam Dawar <gdawar@solarflare.com>

The vSwitch create API takes an array of num_vports client driver
allocated vPort config entries where entry at index 0 contains the PF
configuration and rest num_vports-1 entries refer to vPort configuration
for VFs 0 to (num_vports-2). The required hierarchy
(vswitch/vport/vadaptor) is created within this API. The destroy API
tears down this hierarchy and releases memory for the vSwitch object.

Signed-off-by: Gautam Dawar <gdawar@solarflare.com>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
---
 drivers/net/sfc/base/efx.h      |  40 ++++++
 drivers/net/sfc/base/efx_evb.c  | 269 +++++++++++++++++++++++++++++++++++++++-
 drivers/net/sfc/base/efx_impl.h |  16 +++
 3 files changed, 324 insertions(+), 1 deletion(-)

diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h
index 664efc8..492c8c6 100644
--- a/drivers/net/sfc/base/efx.h
+++ b/drivers/net/sfc/base/efx.h
@@ -1411,6 +1411,9 @@ enum {
 	uint32_t		enc_assigned_port;
 } efx_nic_cfg_t;
 
+#define	EFX_VPORT_PCI_FUNCTION_IS_PF(configp) \
+	((configp)->evc_function == 0xffff)
+
 #define	EFX_PCI_FUNCTION_IS_PF(_encp)	((_encp)->enc_vf == 0xffff)
 #define	EFX_PCI_FUNCTION_IS_VF(_encp)	((_encp)->enc_vf != 0xffff)
 
@@ -3369,6 +3372,31 @@ extern	__checkReturn	__success(return != B_FALSE)	boolean_t
 #define	EFX_FILTER_VID_UNSPEC	0xffff
 #define	EFX_DEFAULT_VSWITCH_ID	1
 
+/* Default VF VLAN ID on creation */
+#define		EFX_VF_VID_DEFAULT	EFX_FILTER_VID_UNSPEC
+#define		EFX_VPORT_ID_INVALID	0
+
+typedef struct efx_vport_config_s {
+	/* Either VF index or 0xffff for PF */
+	uint16_t	evc_function;
+	/* VLAN ID of the associated function */
+	uint16_t	evc_vid;
+	/* vport id shared with client driver */
+	efx_vport_id_t	evc_vport_id;
+	/* MAC address of the associated function */
+	uint8_t		evc_mac_addr[EFX_MAC_ADDR_LEN];
+	/*
+	 * vports created with this flag set may only transfer traffic on the
+	 * VLANs permitted by the vport. Also, an attempt to install filter with
+	 * VLAN will be refused unless requesting function has VLAN privilege.
+	 */
+	boolean_t	evc_vlan_restrict;
+	/* Whether this function is assigned or not */
+	boolean_t	evc_vport_assigned;
+} efx_vport_config_t;
+
+typedef	struct	efx_vswitch_s	efx_vswitch_t;
+
 extern	__checkReturn	efx_rc_t
 efx_evb_init(
 	__in		efx_nic_t *enp);
@@ -3377,6 +3405,18 @@ extern	__checkReturn	__success(return != B_FALSE)	boolean_t
 efx_evb_fini(
 	__in		efx_nic_t *enp);
 
+extern	__checkReturn	efx_rc_t
+efx_evb_vswitch_create(
+	__in				efx_nic_t *enp,
+	__in				uint32_t num_vports,
+	__inout_ecount(num_vports)	efx_vport_config_t *vport_configp,
+	__deref_out			efx_vswitch_t **evpp);
+
+extern	__checkReturn	efx_rc_t
+efx_evb_vswitch_destroy(
+	__in				efx_nic_t *enp,
+	__in				efx_vswitch_t *evp);
+
 #endif /* EFSYS_OPT_EVB */
 
 #ifdef	__cplusplus
diff --git a/drivers/net/sfc/base/efx_evb.c b/drivers/net/sfc/base/efx_evb.c
index ff240f9..27b466f 100644
--- a/drivers/net/sfc/base/efx_evb.c
+++ b/drivers/net/sfc/base/efx_evb.c
@@ -107,7 +107,7 @@
 	return (rc);
 }
 
-	void
+			void
 efx_evb_fini(
 	__in		efx_nic_t *enp)
 {
@@ -125,4 +125,271 @@
 	enp->en_mod_flags &= ~EFX_MOD_EVB;
 }
 
+/*
+ * efx_is_zero_eth_addr returns TRUE if the passed MAC address has all bytes
+ * equal to zero. A vport is assigned a MAC address after creation and this
+ * function checks if that has happened. It is called in the clean-up function
+ * before calling eeo_vport_mac_addr_del to ensure that the vport actually had
+ * an allocated MAC address.
+ */
+
+__checkReturn				boolean_t
+efx_is_zero_eth_addr(
+	__in_bcount(EFX_MAC_ADDR_LEN)	const uint8_t *addrp)
+{
+	return (!(addrp[0] | addrp[1] | addrp[2] |
+		addrp[3] | addrp[4] | addrp[5]));
+}
+
+static			void
+efx_evb_free_vport(
+	__in		efx_nic_t *enp,
+	__in		efx_vswitch_id_t vswitch_id,
+	__inout		efx_vport_config_t *configp)
+{
+	const efx_evb_ops_t *eeop = enp->en_eeop;
+
+	/* If any callback fails, continue clean-up with others functions */
+	if (EFX_VPORT_PCI_FUNCTION_IS_PF(configp)) {
+		/* free vadaptor */
+		if ((configp->evc_vport_id != EFX_VPORT_ID_INVALID) &&
+		    (eeop->eeo_vadaptor_free(enp, vswitch_id,
+		    configp->evc_vport_id) != 0)) {
+			EFSYS_PROBE2(eeo_vadaptor_free,
+			    uint16_t, configp->evc_function,
+			    uint32_t, configp->evc_vport_id);
+		}
+	} else {
+		if (configp->evc_vport_assigned == B_TRUE) {
+			if (eeop->eeo_vport_assign(enp, vswitch_id,
+			    EVB_PORT_ID_NULL,
+			    configp->evc_function) != 0) {
+				EFSYS_PROBE1(eeo_vport_assign,
+				    uint16_t, configp->evc_function);
+			}
+			configp->evc_vport_assigned = B_FALSE;
+		}
+	}
+
+	/*
+	 * Call eeo_vport_mac_addr_del after checking that this vport is
+	 * actually allocated a MAC address in call to efx_evb_configure_vport
+	 */
+	if (!efx_is_zero_eth_addr(configp->evc_mac_addr)) {
+		if (eeop->eeo_vport_mac_addr_del(enp, vswitch_id,
+		    configp->evc_vport_id,
+		    configp->evc_mac_addr) != 0) {
+			EFSYS_PROBE1(eeo_vport_mac_addr_del,
+			    uint16_t, configp->evc_function);
+		}
+		memset(configp->evc_mac_addr, 0x00, EFX_MAC_ADDR_LEN);
+	}
+
+	if (configp->evc_vport_id != EFX_VPORT_ID_INVALID) {
+		if (eeop->eeo_vport_free(enp, vswitch_id,
+		    configp->evc_vport_id) != 0) {
+			EFSYS_PROBE1(eeo_vport_free,
+			    uint16_t, configp->evc_function);
+		}
+		configp->evc_vport_id = EFX_VPORT_ID_INVALID;
+	}
+}
+
+static					void
+efx_evb_free_vports(
+	__in				efx_nic_t *enp,
+	__in				efx_vswitch_id_t vswitch_id,
+	__in				uint32_t num_vports,
+	__inout_ecount(num_vports)	efx_vport_config_t *vport_configp)
+{
+	efx_vport_config_t *configp;
+	uint32_t i;
+
+	if (vport_configp == NULL) {
+		EFSYS_PROBE(null_vport_config);
+		return;
+	}
+
+	for (i = 0; i < num_vports; i++) {
+		configp = vport_configp + i;
+		efx_evb_free_vport(enp, vswitch_id, configp);
+	}
+}
+
+static	__checkReturn	efx_rc_t
+efx_evb_configure_vport(
+	__in		efx_nic_t *enp,
+	__in		efx_vswitch_id_t vswitch_id,
+	__in		const efx_evb_ops_t *eeop,
+	__inout		efx_vport_config_t *configp)
+{
+	efx_rc_t rc;
+	efx_vport_id_t vport_id;
+
+	if ((rc = eeop->eeo_vport_alloc(enp, vswitch_id,
+			EFX_VPORT_TYPE_NORMAL, configp->evc_vid,
+			configp->evc_vlan_restrict, &vport_id)) != 0)
+		goto fail1;
+
+	configp->evc_vport_id = vport_id;
+
+	if ((rc = eeop->eeo_vport_mac_addr_add(enp, vswitch_id,
+			configp->evc_vport_id,
+			configp->evc_mac_addr)) != 0)
+		goto fail2;
+
+	if (EFX_VPORT_PCI_FUNCTION_IS_PF(configp)) {
+		if ((rc = eeop->eeo_vadaptor_alloc(enp, vswitch_id,
+				configp->evc_vport_id)) != 0)
+			goto fail3;
+	} else {
+		if ((rc = eeop->eeo_vport_assign(enp, vswitch_id,
+				configp->evc_vport_id,
+				configp->evc_function)) != 0)
+			goto fail4;
+		configp->evc_vport_assigned = B_TRUE;
+	}
+
+	return (0);
+
+fail4:
+	EFSYS_PROBE(fail4);
+fail3:
+	EFSYS_PROBE(fail3);
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+	__checkReturn			efx_rc_t
+efx_evb_vswitch_create(
+	__in				efx_nic_t *enp,
+	__in				uint32_t num_vports,
+	__inout_ecount(num_vports)	efx_vport_config_t *vport_configp,
+	__deref_out			efx_vswitch_t **evpp)
+{
+	efx_vswitch_t *evp;
+	efx_rc_t rc;
+	efx_vswitch_id_t vswitch_id;
+	efx_vport_config_t *configp;
+	const efx_evb_ops_t *eeop = enp->en_eeop;
+	uint32_t i;
+
+	/* vport_configp is a caller allocated array filled in with vports
+	 * configuration. Index 0 carries the PF vport configuration and next
+	 * num_vports - 1 indices carry VFs configuration.
+	 */
+	EFSYS_ASSERT((num_vports != 0) && (vport_configp != NULL) &&
+		(evpp != NULL));
+	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB);
+	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
+
+	if ((eeop->eeo_vswitch_alloc == NULL) ||
+	    (eeop->eeo_vport_alloc == NULL) ||
+	    (eeop->eeo_vport_free == NULL) ||
+	    (eeop->eeo_vport_mac_addr_add == NULL) ||
+	    (eeop->eeo_vport_mac_addr_del == NULL) ||
+	    (eeop->eeo_vadaptor_alloc == NULL) ||
+	    (eeop->eeo_vadaptor_free == NULL) ||
+	    (eeop->eeo_vport_assign == NULL) ||
+	    (eeop->eeo_vswitch_free == NULL)) {
+		rc = ENOTSUP;
+		goto fail1;
+	}
+
+	/* Allocate a vSwitch object */
+	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_vswitch_t), evp);
+
+	if (evp == NULL) {
+		rc = ENOMEM;
+		goto fail2;
+	}
+
+	if ((rc = eeop->eeo_vswitch_alloc(enp, &vswitch_id)) != 0)
+		goto fail3;
+
+	evp->ev_enp = enp;
+	evp->ev_num_vports = num_vports;
+	evp->ev_evcp = vport_configp;
+	evp->ev_vswitch_id = vswitch_id;
+
+	for (i = 0; i < num_vports; i++) {
+		configp = vport_configp + i;
+
+		if ((rc = efx_evb_configure_vport(enp, vswitch_id, eeop,
+				configp)) != 0)
+			goto fail4;
+	}
+
+	enp->en_vswitchp = evp;
+	*evpp = evp;
+	return (0);
+
+fail4:
+	EFSYS_PROBE(fail4);
+	efx_evb_free_vports(enp, vswitch_id, i + 1, vport_configp);
+	/* Free the vSwitch */
+	eeop->eeo_vswitch_free(enp, vswitch_id);
+
+fail3:
+	EFSYS_PROBE(fail3);
+	/* Free the vSwitch object */
+	EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_vswitch_t), evp);
+
+fail2:
+	EFSYS_PROBE(fail2);
+
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+
+	__checkReturn	efx_rc_t
+efx_evb_vswitch_destroy(
+	__in		efx_nic_t *enp,
+	__in		efx_vswitch_t *evp)
+{
+	const efx_evb_ops_t *eeop = enp->en_eeop;
+	efx_vswitch_id_t vswitch_id;
+	efx_rc_t rc;
+
+	EFSYS_ASSERT(evp != NULL);
+	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB);
+
+	if ((eeop->eeo_vport_mac_addr_del == NULL) ||
+	    (eeop->eeo_vadaptor_free == NULL) ||
+	    (eeop->eeo_vport_assign == NULL) ||
+	    (eeop->eeo_vport_free == NULL) ||
+	    (eeop->eeo_vswitch_free == NULL)) {
+		rc = ENOTSUP;
+		goto fail1;
+	}
+
+	vswitch_id  = evp->ev_vswitch_id;
+	efx_evb_free_vports(enp, vswitch_id,
+		evp->ev_num_vports, evp->ev_evcp);
+
+	/* Free the vSwitch object */
+	EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_vswitch_t), evp);
+	enp->en_vswitchp = NULL;
+
+	/* Free the vSwitch */
+	if ((rc = eeop->eeo_vswitch_free(enp, vswitch_id)) != 0)
+		goto fail2;
+
+	return (0);
+
+fail2:
+	EFSYS_PROBE(fail2);
+
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+	return (rc);
+}
+
 #endif
diff --git a/drivers/net/sfc/base/efx_impl.h b/drivers/net/sfc/base/efx_impl.h
index ef6a97a..46d5389 100644
--- a/drivers/net/sfc/base/efx_impl.h
+++ b/drivers/net/sfc/base/efx_impl.h
@@ -652,6 +652,17 @@
 
 #if EFSYS_OPT_EVB
 
+struct efx_vswitch_s {
+	efx_nic_t		*ev_enp;
+	efx_vswitch_id_t	ev_vswitch_id;
+	uint32_t		ev_num_vports;
+	/*
+	 * Vport configuration array: index 0 to store PF configuration
+	 * and next ev_num_vports-1 entries hold VFs configuration.
+	 */
+	efx_vport_config_t	*ev_evcp;
+};
+
 typedef struct efx_evb_ops_s {
 	efx_rc_t	(*eeo_init)(efx_nic_t *);
 	void		(*eeo_fini)(efx_nic_t *);
@@ -674,6 +685,10 @@
 						efx_vport_id_t, uint32_t);
 } efx_evb_ops_t;
 
+extern __checkReturn	boolean_t
+efx_is_zero_eth_addr(
+	__in_bcount(EFX_MAC_ADDR_LEN)	const uint8_t *addrp);
+
 #endif /* EFSYS_OPT_EVB */
 
 #define	EFX_DRV_VER_MAX		20
@@ -776,6 +791,7 @@ struct efx_nic_s {
 #endif	/* EFX_OPTS_EF10() */
 #if EFSYS_OPT_EVB
 	const efx_evb_ops_t	*en_eeop;
+	struct efx_vswitch_s    *en_vswitchp;
 #endif	/* EFSYS_OPT_EVB */
 };
 
-- 
1.8.3.1