xref: /dpdk/drivers/net/sfc/sfc_sriov.c (revision 1f37cb2bb46b1fd403faa7c3bf8884e6a4dfde66)
1dd45b880SAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause
2dd45b880SAndrew Rybchenko  *
398d26ef7SAndrew Rybchenko  * Copyright(c) 2019-2021 Xilinx, Inc.
4dd45b880SAndrew Rybchenko  * Copyright(c) 2019 Solarflare Communications Inc.
5dd45b880SAndrew Rybchenko  *
6dd45b880SAndrew Rybchenko  * This software was jointly developed between OKTET Labs (under contract
7dd45b880SAndrew Rybchenko  * for Solarflare) and Solarflare Communications, Inc.
8dd45b880SAndrew Rybchenko  */
9dd45b880SAndrew Rybchenko 
10dd45b880SAndrew Rybchenko #include <rte_common.h>
11*1f37cb2bSDavid Marchand #include <bus_pci_driver.h>
12dd45b880SAndrew Rybchenko 
13dd45b880SAndrew Rybchenko #include "sfc.h"
14dd45b880SAndrew Rybchenko #include "sfc_log.h"
15dd45b880SAndrew Rybchenko 
16dd45b880SAndrew Rybchenko #include "efx.h"
17dd45b880SAndrew Rybchenko 
18dd45b880SAndrew Rybchenko 
19dd45b880SAndrew Rybchenko /*
20dd45b880SAndrew Rybchenko  * Check if a MAC address is already assigned to one of previously
21dd45b880SAndrew Rybchenko  * configured vPorts (either PF itself or one of already configured VFs).
22dd45b880SAndrew Rybchenko  *
23dd45b880SAndrew Rybchenko  * Typically the first vPort which corresponds to PF has globally
24dd45b880SAndrew Rybchenko  * administered unicast address, but it still could be locally
25dd45b880SAndrew Rybchenko  * administered if user assigned it or in the case of unconfigured NIC.
26dd45b880SAndrew Rybchenko  * So, it is safer to include it as well in uniqueness check.
27dd45b880SAndrew Rybchenko  */
28dd45b880SAndrew Rybchenko static bool
sriov_mac_addr_assigned(const efx_vport_config_t * vport_config,unsigned int num,const uint8_t * mac_addr)29dd45b880SAndrew Rybchenko sriov_mac_addr_assigned(const efx_vport_config_t *vport_config,
30dd45b880SAndrew Rybchenko 			unsigned int num, const uint8_t *mac_addr)
31dd45b880SAndrew Rybchenko {
32dd45b880SAndrew Rybchenko 	unsigned int i;
33dd45b880SAndrew Rybchenko 
34dd45b880SAndrew Rybchenko 	/* Check PF's MAC address as well as explained above */
35dd45b880SAndrew Rybchenko 	for (i = 0; i < num; ++i) {
36dd45b880SAndrew Rybchenko 		if (memcmp(mac_addr, vport_config[i].evc_mac_addr,
37dd45b880SAndrew Rybchenko 			   sizeof(vport_config[i].evc_mac_addr)) == 0)
38dd45b880SAndrew Rybchenko 			return true;
39dd45b880SAndrew Rybchenko 	}
40dd45b880SAndrew Rybchenko 
41dd45b880SAndrew Rybchenko 	return false;
42dd45b880SAndrew Rybchenko }
43dd45b880SAndrew Rybchenko 
44dd45b880SAndrew Rybchenko int
sfc_sriov_attach(struct sfc_adapter * sa)45dd45b880SAndrew Rybchenko sfc_sriov_attach(struct sfc_adapter *sa)
46dd45b880SAndrew Rybchenko {
47dd45b880SAndrew Rybchenko 	const struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(sa->eth_dev);
48dd45b880SAndrew Rybchenko 	struct sfc_sriov *sriov = &sa->sriov;
49dd45b880SAndrew Rybchenko 	efx_vport_config_t *vport_config;
50dd45b880SAndrew Rybchenko 	unsigned int i;
51dd45b880SAndrew Rybchenko 	int rc;
52dd45b880SAndrew Rybchenko 
53dd45b880SAndrew Rybchenko 	sfc_log_init(sa, "entry");
54dd45b880SAndrew Rybchenko 
55dd45b880SAndrew Rybchenko 	sriov->num_vfs = pci_dev->max_vfs;
56f8778b16SIgor Romanov 	if (sa->switchdev || sriov->num_vfs == 0)
57dd45b880SAndrew Rybchenko 		goto done;
58dd45b880SAndrew Rybchenko 
59dd45b880SAndrew Rybchenko 	vport_config = calloc(sriov->num_vfs + 1, sizeof(*vport_config));
60dd45b880SAndrew Rybchenko 	if (vport_config == NULL) {
61dd45b880SAndrew Rybchenko 		rc = ENOMEM;
62dd45b880SAndrew Rybchenko 		goto fail_alloc_vport_config;
63dd45b880SAndrew Rybchenko 	}
64dd45b880SAndrew Rybchenko 
65dd45b880SAndrew Rybchenko 	vport_config[0].evc_function = 0xffff;
66dd45b880SAndrew Rybchenko 	vport_config[0].evc_vid = EFX_VF_VID_DEFAULT;
67dd45b880SAndrew Rybchenko 	vport_config[0].evc_vlan_restrict = B_FALSE;
68dd45b880SAndrew Rybchenko 
69dd45b880SAndrew Rybchenko 	for (i = 1; i <= sriov->num_vfs; ++i) {
70dd45b880SAndrew Rybchenko 		vport_config[i].evc_function = i - 1;
71dd45b880SAndrew Rybchenko 		vport_config[i].evc_vid = EFX_VF_VID_DEFAULT;
72dd45b880SAndrew Rybchenko 		vport_config[i].evc_vlan_restrict = B_FALSE;
73dd45b880SAndrew Rybchenko 		do {
74dd45b880SAndrew Rybchenko 			rte_eth_random_addr(vport_config[i].evc_mac_addr);
75dd45b880SAndrew Rybchenko 		} while (sriov_mac_addr_assigned(vport_config, i,
76dd45b880SAndrew Rybchenko 						 vport_config[i].evc_mac_addr));
77dd45b880SAndrew Rybchenko 	}
78dd45b880SAndrew Rybchenko 
79dd45b880SAndrew Rybchenko 	sriov->vport_config = vport_config;
80dd45b880SAndrew Rybchenko 
81dd45b880SAndrew Rybchenko done:
82dd45b880SAndrew Rybchenko 	sfc_log_init(sa, "done");
83dd45b880SAndrew Rybchenko 	return 0;
84dd45b880SAndrew Rybchenko 
85dd45b880SAndrew Rybchenko fail_alloc_vport_config:
86dd45b880SAndrew Rybchenko 	sriov->num_vfs = 0;
87dd45b880SAndrew Rybchenko 	return rc;
88dd45b880SAndrew Rybchenko }
89dd45b880SAndrew Rybchenko 
90dd45b880SAndrew Rybchenko void
sfc_sriov_detach(struct sfc_adapter * sa)91dd45b880SAndrew Rybchenko sfc_sriov_detach(struct sfc_adapter *sa)
92dd45b880SAndrew Rybchenko {
93dd45b880SAndrew Rybchenko 	struct sfc_sriov *sriov = &sa->sriov;
94dd45b880SAndrew Rybchenko 
95dd45b880SAndrew Rybchenko 	sfc_log_init(sa, "entry");
96dd45b880SAndrew Rybchenko 
97dd45b880SAndrew Rybchenko 	free(sriov->vport_config);
98dd45b880SAndrew Rybchenko 	sriov->vport_config = NULL;
99dd45b880SAndrew Rybchenko 	sriov->num_vfs = 0;
100dd45b880SAndrew Rybchenko 
101dd45b880SAndrew Rybchenko 	sfc_log_init(sa, "done");
102dd45b880SAndrew Rybchenko }
103dd45b880SAndrew Rybchenko 
104dd45b880SAndrew Rybchenko int
sfc_sriov_vswitch_create(struct sfc_adapter * sa)105dd45b880SAndrew Rybchenko sfc_sriov_vswitch_create(struct sfc_adapter *sa)
106dd45b880SAndrew Rybchenko {
107dd45b880SAndrew Rybchenko 	struct sfc_sriov *sriov = &sa->sriov;
108dd45b880SAndrew Rybchenko 	efx_vport_config_t *vport_config = sriov->vport_config;
109dd45b880SAndrew Rybchenko 	int rc;
110dd45b880SAndrew Rybchenko 
111dd45b880SAndrew Rybchenko 	sfc_log_init(sa, "entry");
112dd45b880SAndrew Rybchenko 
113f8778b16SIgor Romanov 	if (sa->switchdev) {
114f8778b16SIgor Romanov 		sfc_log_init(sa, "don't create vswitch in switchdev mode");
115f8778b16SIgor Romanov 		goto done;
116f8778b16SIgor Romanov 	}
117f8778b16SIgor Romanov 
118dd45b880SAndrew Rybchenko 	if (sriov->num_vfs == 0) {
119dd45b880SAndrew Rybchenko 		sfc_log_init(sa, "no VFs enabled");
120dd45b880SAndrew Rybchenko 		goto done;
121dd45b880SAndrew Rybchenko 	}
122dd45b880SAndrew Rybchenko 
123dd45b880SAndrew Rybchenko 	rc = efx_evb_init(sa->nic);
124dd45b880SAndrew Rybchenko 	if (rc != 0) {
125dd45b880SAndrew Rybchenko 		sfc_err(sa, "EVB init failed %d", rc);
126dd45b880SAndrew Rybchenko 		goto fail_evb_init;
127dd45b880SAndrew Rybchenko 	}
128dd45b880SAndrew Rybchenko 
129dd45b880SAndrew Rybchenko 	RTE_BUILD_BUG_ON(sizeof(sa->port.default_mac_addr) !=
130dd45b880SAndrew Rybchenko 			 sizeof(vport_config[0].evc_mac_addr));
131dd45b880SAndrew Rybchenko 	rte_ether_addr_copy(&sa->port.default_mac_addr,
132dd45b880SAndrew Rybchenko 		(struct rte_ether_addr *)vport_config[0].evc_mac_addr);
133dd45b880SAndrew Rybchenko 
134dd45b880SAndrew Rybchenko 	rc = efx_evb_vswitch_create(sa->nic, sriov->num_vfs + 1,
135dd45b880SAndrew Rybchenko 				    vport_config, &sriov->vswitch);
136dd45b880SAndrew Rybchenko 	if (rc != 0) {
137dd45b880SAndrew Rybchenko 		sfc_err(sa, "EVB vSwitch create failed %d", rc);
138dd45b880SAndrew Rybchenko 		goto fail_evb_vswitch_create;
139dd45b880SAndrew Rybchenko 	}
140dd45b880SAndrew Rybchenko 
141dd45b880SAndrew Rybchenko done:
142dd45b880SAndrew Rybchenko 	sfc_log_init(sa, "done");
143dd45b880SAndrew Rybchenko 	return 0;
144dd45b880SAndrew Rybchenko 
145dd45b880SAndrew Rybchenko fail_evb_vswitch_create:
146dd45b880SAndrew Rybchenko 	efx_evb_fini(sa->nic);
147dd45b880SAndrew Rybchenko 
148dd45b880SAndrew Rybchenko fail_evb_init:
149dd45b880SAndrew Rybchenko 	return rc;
150dd45b880SAndrew Rybchenko }
151dd45b880SAndrew Rybchenko 
152dd45b880SAndrew Rybchenko void
sfc_sriov_vswitch_destroy(struct sfc_adapter * sa)153dd45b880SAndrew Rybchenko sfc_sriov_vswitch_destroy(struct sfc_adapter *sa)
154dd45b880SAndrew Rybchenko {
155dd45b880SAndrew Rybchenko 	struct sfc_sriov *sriov = &sa->sriov;
156dd45b880SAndrew Rybchenko 	int rc;
157dd45b880SAndrew Rybchenko 
158dd45b880SAndrew Rybchenko 	sfc_log_init(sa, "entry");
159dd45b880SAndrew Rybchenko 
160f8778b16SIgor Romanov 	if (sa->switchdev || sriov->num_vfs == 0)
161dd45b880SAndrew Rybchenko 		goto done;
162dd45b880SAndrew Rybchenko 
163dd45b880SAndrew Rybchenko 	rc = efx_evb_vswitch_destroy(sa->nic, sriov->vswitch);
164dd45b880SAndrew Rybchenko 	if (rc != 0)
165dd45b880SAndrew Rybchenko 		sfc_err(sa, "efx_evb_vswitch_destroy() failed %d", rc);
166dd45b880SAndrew Rybchenko 
167dd45b880SAndrew Rybchenko 	sriov->vswitch = NULL;
168dd45b880SAndrew Rybchenko 
169dd45b880SAndrew Rybchenko 	efx_evb_fini(sa->nic);
170dd45b880SAndrew Rybchenko 
171dd45b880SAndrew Rybchenko done:
172dd45b880SAndrew Rybchenko 	sfc_log_init(sa, "done");
173dd45b880SAndrew Rybchenko }
174