xref: /linux/drivers/net/ethernet/netronome/nfp/abm/main.c (revision 13a370b9d275959ac75e92dc14e43eeae75804f8)
1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
2 /*
3  * Copyright (C) 2018 Netronome Systems, Inc.
4  *
5  * This software is dual licensed under the GNU General License Version 2,
6  * June 1991 as shown in the file COPYING in the top-level directory of this
7  * source tree or the BSD 2-Clause License provided below.  You have the
8  * option to license this software under the complete terms of either license.
9  *
10  * The BSD 2-Clause License:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      1. Redistributions of source code must retain the above
17  *         copyright notice, this list of conditions and the following
18  *         disclaimer.
19  *
20  *      2. Redistributions in binary form must reproduce the above
21  *         copyright notice, this list of conditions and the following
22  *         disclaimer in the documentation and/or other materials
23  *         provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  */
34 
35 #include <linux/bitfield.h>
36 #include <linux/etherdevice.h>
37 #include <linux/lockdep.h>
38 #include <linux/netdevice.h>
39 #include <linux/rcupdate.h>
40 #include <linux/slab.h>
41 
42 #include "../nfpcore/nfp.h"
43 #include "../nfpcore/nfp_cpp.h"
44 #include "../nfpcore/nfp_nsp.h"
45 #include "../nfp_app.h"
46 #include "../nfp_main.h"
47 #include "../nfp_net.h"
48 #include "../nfp_net_repr.h"
49 #include "../nfp_port.h"
50 #include "main.h"
51 
52 static u32 nfp_abm_portid(enum nfp_repr_type rtype, unsigned int id)
53 {
54 	return FIELD_PREP(NFP_ABM_PORTID_TYPE, rtype) |
55 	       FIELD_PREP(NFP_ABM_PORTID_ID, id);
56 }
57 
58 static struct net_device *nfp_abm_repr_get(struct nfp_app *app, u32 port_id)
59 {
60 	enum nfp_repr_type rtype;
61 	struct nfp_reprs *reprs;
62 	u8 port;
63 
64 	rtype = FIELD_GET(NFP_ABM_PORTID_TYPE, port_id);
65 	port = FIELD_GET(NFP_ABM_PORTID_ID, port_id);
66 
67 	reprs = rcu_dereference(app->reprs[rtype]);
68 	if (!reprs)
69 		return NULL;
70 
71 	if (port >= reprs->num_reprs)
72 		return NULL;
73 
74 	return rcu_dereference(reprs->reprs[port]);
75 }
76 
77 static int
78 nfp_abm_spawn_repr(struct nfp_app *app, struct nfp_abm_link *alink,
79 		   enum nfp_port_type ptype)
80 {
81 	struct net_device *netdev;
82 	enum nfp_repr_type rtype;
83 	struct nfp_reprs *reprs;
84 	struct nfp_repr *repr;
85 	struct nfp_port *port;
86 	int err;
87 
88 	if (ptype == NFP_PORT_PHYS_PORT)
89 		rtype = NFP_REPR_TYPE_PHYS_PORT;
90 	else
91 		rtype = NFP_REPR_TYPE_PF;
92 
93 	netdev = nfp_repr_alloc(app);
94 	if (!netdev)
95 		return -ENOMEM;
96 	repr = netdev_priv(netdev);
97 	repr->app_priv = alink;
98 
99 	port = nfp_port_alloc(app, ptype, netdev);
100 	if (IS_ERR(port)) {
101 		err = PTR_ERR(port);
102 		goto err_free_repr;
103 	}
104 
105 	if (ptype == NFP_PORT_PHYS_PORT) {
106 		port->eth_forced = true;
107 		err = nfp_port_init_phy_port(app->pf, app, port, alink->id);
108 		if (err)
109 			goto err_free_port;
110 	} else {
111 		port->pf_id = alink->abm->pf_id;
112 		port->pf_split = app->pf->max_data_vnics > 1;
113 		port->pf_split_id = alink->id;
114 		port->vnic = alink->vnic->dp.ctrl_bar;
115 	}
116 
117 	SET_NETDEV_DEV(netdev, &alink->vnic->pdev->dev);
118 	eth_hw_addr_random(netdev);
119 
120 	err = nfp_repr_init(app, netdev, nfp_abm_portid(rtype, alink->id),
121 			    port, alink->vnic->dp.netdev);
122 	if (err)
123 		goto err_free_port;
124 
125 	reprs = nfp_reprs_get_locked(app, rtype);
126 	WARN(nfp_repr_get_locked(app, reprs, alink->id), "duplicate repr");
127 	rcu_assign_pointer(reprs->reprs[alink->id], netdev);
128 
129 	nfp_info(app->cpp, "%s Port %d Representor(%s) created\n",
130 		 ptype == NFP_PORT_PF_PORT ? "PCIe" : "Phys",
131 		 alink->id, netdev->name);
132 
133 	return 0;
134 
135 err_free_port:
136 	nfp_port_free(port);
137 err_free_repr:
138 	nfp_repr_free(netdev);
139 	return err;
140 }
141 
142 static void
143 nfp_abm_kill_repr(struct nfp_app *app, struct nfp_abm_link *alink,
144 		  enum nfp_repr_type rtype)
145 {
146 	struct net_device *netdev;
147 	struct nfp_reprs *reprs;
148 
149 	reprs = nfp_reprs_get_locked(app, rtype);
150 	netdev = nfp_repr_get_locked(app, reprs, alink->id);
151 	if (!netdev)
152 		return;
153 	rcu_assign_pointer(reprs->reprs[alink->id], NULL);
154 	synchronize_rcu();
155 	/* Cast to make sure nfp_repr_clean_and_free() takes a nfp_repr */
156 	nfp_repr_clean_and_free((struct nfp_repr *)netdev_priv(netdev));
157 }
158 
159 static void
160 nfp_abm_kill_reprs(struct nfp_abm *abm, struct nfp_abm_link *alink)
161 {
162 	nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PF);
163 	nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PHYS_PORT);
164 }
165 
166 static void nfp_abm_kill_reprs_all(struct nfp_abm *abm)
167 {
168 	struct nfp_pf *pf = abm->app->pf;
169 	struct nfp_net *nn;
170 
171 	list_for_each_entry(nn, &pf->vnics, vnic_list)
172 		nfp_abm_kill_reprs(abm, (struct nfp_abm_link *)nn->app_priv);
173 }
174 
175 static enum devlink_eswitch_mode nfp_abm_eswitch_mode_get(struct nfp_app *app)
176 {
177 	struct nfp_abm *abm = app->priv;
178 
179 	return abm->eswitch_mode;
180 }
181 
182 static int nfp_abm_eswitch_set_legacy(struct nfp_abm *abm)
183 {
184 	nfp_abm_kill_reprs_all(abm);
185 
186 	abm->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
187 	return 0;
188 }
189 
190 static void nfp_abm_eswitch_clean_up(struct nfp_abm *abm)
191 {
192 	if (abm->eswitch_mode != DEVLINK_ESWITCH_MODE_LEGACY)
193 		WARN_ON(nfp_abm_eswitch_set_legacy(abm));
194 }
195 
196 static int nfp_abm_eswitch_set_switchdev(struct nfp_abm *abm)
197 {
198 	struct nfp_app *app = abm->app;
199 	struct nfp_pf *pf = app->pf;
200 	struct nfp_net *nn;
201 	int err;
202 
203 	list_for_each_entry(nn, &pf->vnics, vnic_list) {
204 		struct nfp_abm_link *alink = nn->app_priv;
205 
206 		err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PHYS_PORT);
207 		if (err)
208 			goto err_kill_all_reprs;
209 
210 		err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PF_PORT);
211 		if (err)
212 			goto err_kill_all_reprs;
213 	}
214 
215 	abm->eswitch_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
216 	return 0;
217 
218 err_kill_all_reprs:
219 	nfp_abm_kill_reprs_all(abm);
220 	return err;
221 }
222 
223 static int nfp_abm_eswitch_mode_set(struct nfp_app *app, u16 mode)
224 {
225 	struct nfp_abm *abm = app->priv;
226 
227 	if (abm->eswitch_mode == mode)
228 		return 0;
229 
230 	switch (mode) {
231 	case DEVLINK_ESWITCH_MODE_LEGACY:
232 		return nfp_abm_eswitch_set_legacy(abm);
233 	case DEVLINK_ESWITCH_MODE_SWITCHDEV:
234 		return nfp_abm_eswitch_set_switchdev(abm);
235 	default:
236 		return -EINVAL;
237 	}
238 }
239 
240 static void
241 nfp_abm_vnic_set_mac(struct nfp_pf *pf, struct nfp_abm *abm, struct nfp_net *nn,
242 		     unsigned int id)
243 {
244 	struct nfp_eth_table_port *eth_port = &pf->eth_tbl->ports[id];
245 	u8 mac_addr[ETH_ALEN];
246 	const char *mac_str;
247 	char name[32];
248 
249 	if (id > pf->eth_tbl->count) {
250 		nfp_warn(pf->cpp, "No entry for persistent MAC address\n");
251 		eth_hw_addr_random(nn->dp.netdev);
252 		return;
253 	}
254 
255 	snprintf(name, sizeof(name), "eth%u.mac.pf%u",
256 		 eth_port->eth_index, abm->pf_id);
257 
258 	mac_str = nfp_hwinfo_lookup(pf->hwinfo, name);
259 	if (!mac_str) {
260 		nfp_warn(pf->cpp, "Can't lookup persistent MAC address (%s)\n",
261 			 name);
262 		eth_hw_addr_random(nn->dp.netdev);
263 		return;
264 	}
265 
266 	if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
267 		   &mac_addr[0], &mac_addr[1], &mac_addr[2],
268 		   &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) {
269 		nfp_warn(pf->cpp, "Can't parse persistent MAC address (%s)\n",
270 			 mac_str);
271 		eth_hw_addr_random(nn->dp.netdev);
272 		return;
273 	}
274 
275 	ether_addr_copy(nn->dp.netdev->dev_addr, mac_addr);
276 	ether_addr_copy(nn->dp.netdev->perm_addr, mac_addr);
277 }
278 
279 static int
280 nfp_abm_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
281 {
282 	struct nfp_eth_table_port *eth_port = &app->pf->eth_tbl->ports[id];
283 	struct nfp_abm *abm = app->priv;
284 	struct nfp_abm_link *alink;
285 	int err;
286 
287 	alink = kzalloc(sizeof(*alink), GFP_KERNEL);
288 	if (!alink)
289 		return -ENOMEM;
290 	nn->app_priv = alink;
291 	alink->abm = abm;
292 	alink->vnic = nn;
293 	alink->id = id;
294 
295 	/* This is a multi-host app, make sure MAC/PHY is up, but don't
296 	 * make the MAC/PHY state follow the state of any of the ports.
297 	 */
298 	err = nfp_eth_set_configured(app->cpp, eth_port->index, true);
299 	if (err < 0)
300 		goto err_free_alink;
301 
302 	netif_keep_dst(nn->dp.netdev);
303 
304 	nfp_abm_vnic_set_mac(app->pf, abm, nn, id);
305 	nfp_abm_ctrl_read_params(alink);
306 
307 	return 0;
308 
309 err_free_alink:
310 	kfree(alink);
311 	return err;
312 }
313 
314 static void nfp_abm_vnic_free(struct nfp_app *app, struct nfp_net *nn)
315 {
316 	struct nfp_abm_link *alink = nn->app_priv;
317 
318 	nfp_abm_kill_reprs(alink->abm, alink);
319 	kfree(alink);
320 }
321 
322 static int nfp_abm_init(struct nfp_app *app)
323 {
324 	struct nfp_pf *pf = app->pf;
325 	struct nfp_reprs *reprs;
326 	struct nfp_abm *abm;
327 	int err;
328 
329 	if (!pf->eth_tbl) {
330 		nfp_err(pf->cpp, "ABM NIC requires ETH table\n");
331 		return -EINVAL;
332 	}
333 	if (pf->max_data_vnics != pf->eth_tbl->count) {
334 		nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n",
335 			pf->max_data_vnics, pf->eth_tbl->count);
336 		return -EINVAL;
337 	}
338 	if (!pf->mac_stats_bar) {
339 		nfp_warn(app->cpp, "ABM NIC requires mac_stats symbol\n");
340 		return -EINVAL;
341 	}
342 
343 	abm = kzalloc(sizeof(*abm), GFP_KERNEL);
344 	if (!abm)
345 		return -ENOMEM;
346 	app->priv = abm;
347 	abm->app = app;
348 
349 	err = nfp_abm_ctrl_find_addrs(abm);
350 	if (err)
351 		goto err_free_abm;
352 
353 	err = -ENOMEM;
354 	reprs = nfp_reprs_alloc(pf->max_data_vnics);
355 	if (!reprs)
356 		goto err_free_abm;
357 	RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PHYS_PORT], reprs);
358 
359 	reprs = nfp_reprs_alloc(pf->max_data_vnics);
360 	if (!reprs)
361 		goto err_free_phys;
362 	RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PF], reprs);
363 
364 	return 0;
365 
366 err_free_phys:
367 	nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT);
368 err_free_abm:
369 	kfree(abm);
370 	app->priv = NULL;
371 	return err;
372 }
373 
374 static void nfp_abm_clean(struct nfp_app *app)
375 {
376 	struct nfp_abm *abm = app->priv;
377 
378 	nfp_abm_eswitch_clean_up(abm);
379 	nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF);
380 	nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT);
381 	kfree(abm);
382 	app->priv = NULL;
383 }
384 
385 const struct nfp_app_type app_abm = {
386 	.id		= NFP_APP_ACTIVE_BUFFER_MGMT_NIC,
387 	.name		= "abm",
388 
389 	.init		= nfp_abm_init,
390 	.clean		= nfp_abm_clean,
391 
392 	.vnic_alloc	= nfp_abm_vnic_alloc,
393 	.vnic_free	= nfp_abm_vnic_free,
394 
395 	.eswitch_mode_get	= nfp_abm_eswitch_mode_get,
396 	.eswitch_mode_set	= nfp_abm_eswitch_mode_set,
397 
398 	.repr_get	= nfp_abm_repr_get,
399 };
400