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