File Index
Files and directories
Sign in
FILE

dev.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/dev.c C
  1/*
  2 * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
  3 *
  4 * This software is available to you under a choice of one of two
  5 * licenses.  You may choose to be licensed under the terms of the GNU
  6 * General Public License (GPL) Version 2, available from the file
  7 * COPYING in the main directory of this source tree, or the
  8 * OpenIB.org BSD license below:
  9 *
 10 *     Redistribution and use in source and binary forms, with or
 11 *     without modification, are permitted provided that the following
 12 *     conditions are met:
 13 *
 14 *      - Redistributions of source code must retain the above
 15 *        copyright notice, this list of conditions and the following
 16 *        disclaimer.
 17 *
 18 *      - Redistributions in binary form must reproduce the above
 19 *        copyright notice, this list of conditions and the following
 20 *        disclaimer in the documentation and/or other materials
 21 *        provided with the distribution.
 22 *
 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 30 * SOFTWARE.
 31 */
 32
 33#include <linux/mlx5/driver.h>
 34#include <linux/mlx5/eswitch.h>
 35#include <linux/mlx5/mlx5_ifc_vdpa.h>
 36#include <linux/mlx5/vport.h>
 37#include "mlx5_core.h"
 38#include "devlink.h"
 39#include "lag/lag.h"
 40
 41static DEFINE_IDA(mlx5_adev_ida);
 42
 43static bool is_eth_rep_supported(struct mlx5_core_dev *dev)
 44{
 45	if (!IS_ENABLED(CONFIG_MLX5_ESWITCH))
 46		return false;
 47
 48	if (!MLX5_ESWITCH_MANAGER(dev))
 49		return false;
 50
 51	if (!is_mdev_switchdev_mode(dev))
 52		return false;
 53
 54	return true;
 55}
 56
 57bool mlx5_eth_supported(struct mlx5_core_dev *dev)
 58{
 59	if (!IS_ENABLED(CONFIG_MLX5_CORE_EN))
 60		return false;
 61
 62	if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
 63		return false;
 64
 65	if (!MLX5_CAP_GEN(dev, eth_net_offloads)) {
 66		mlx5_core_warn(dev, "Missing eth_net_offloads capability\n");
 67		return false;
 68	}
 69
 70	if (!MLX5_CAP_GEN(dev, nic_flow_table)) {
 71		mlx5_core_warn(dev, "Missing nic_flow_table capability\n");
 72		return false;
 73	}
 74
 75	if (!MLX5_CAP_ETH(dev, csum_cap)) {
 76		mlx5_core_warn(dev, "Missing csum_cap capability\n");
 77		return false;
 78	}
 79
 80	if (!MLX5_CAP_ETH(dev, max_lso_cap)) {
 81		mlx5_core_warn(dev, "Missing max_lso_cap capability\n");
 82		return false;
 83	}
 84
 85	if (!MLX5_CAP_ETH(dev, vlan_cap)) {
 86		mlx5_core_warn(dev, "Missing vlan_cap capability\n");
 87		return false;
 88	}
 89
 90	if (!MLX5_CAP_ETH(dev, rss_ind_tbl_cap)) {
 91		mlx5_core_warn(dev, "Missing rss_ind_tbl_cap capability\n");
 92		return false;
 93	}
 94
 95	if (MLX5_CAP_FLOWTABLE(dev,
 96			       flow_table_properties_nic_receive.max_ft_level) < 3) {
 97		mlx5_core_warn(dev, "max_ft_level < 3\n");
 98		return false;
 99	}
100
101	if (!MLX5_CAP_ETH(dev, self_lb_en_modifiable))
102		mlx5_core_warn(dev, "Self loop back prevention is not supported\n");
103	if (!MLX5_CAP_GEN(dev, cq_moderation))
104		mlx5_core_warn(dev, "CQ moderation is not supported\n");
105
106	return true;
107}
108
109bool mlx5_vnet_supported(struct mlx5_core_dev *dev)
110{
111	if (!IS_ENABLED(CONFIG_MLX5_VDPA_NET))
112		return false;
113
114	if (mlx5_core_is_pf(dev))
115		return false;
116
117	if (!(MLX5_CAP_GEN_64(dev, general_obj_types) &
118	      MLX5_GENERAL_OBJ_TYPES_CAP_VIRTIO_NET_Q))
119		return false;
120
121	if (!(MLX5_CAP_DEV_VDPA_EMULATION(dev, event_mode) &
122	      MLX5_VIRTIO_Q_EVENT_MODE_QP_MODE))
123		return false;
124
125	if (!MLX5_CAP_DEV_VDPA_EMULATION(dev, eth_frame_offload_type))
126		return false;
127
128	return true;
129}
130
131static bool is_vnet_enabled(struct mlx5_core_dev *dev)
132{
133	union devlink_param_value val;
134	int err;
135
136	err = devl_param_driverinit_value_get(priv_to_devlink(dev),
137					      DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET,
138					      &val);
139	return err ? false : val.vbool;
140}
141
142static bool is_ib_rep_supported(struct mlx5_core_dev *dev)
143{
144	if (!IS_ENABLED(CONFIG_MLX5_INFINIBAND))
145		return false;
146
147	if (dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_IB_ADEV)
148		return false;
149
150	if (!is_eth_rep_supported(dev))
151		return false;
152
153	if (mlx5_core_mp_enabled(dev))
154		return false;
155
156	return true;
157}
158
159static bool is_mp_supported(struct mlx5_core_dev *dev)
160{
161	if (!IS_ENABLED(CONFIG_MLX5_INFINIBAND))
162		return false;
163
164	if (dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_IB_ADEV)
165		return false;
166
167	if (is_ib_rep_supported(dev))
168		return false;
169
170	if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
171		return false;
172
173	if (!mlx5_core_is_mp_slave(dev))
174		return false;
175
176	return true;
177}
178
179bool mlx5_rdma_supported(struct mlx5_core_dev *dev)
180{
181	if (!IS_ENABLED(CONFIG_MLX5_INFINIBAND))
182		return false;
183
184	if (dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_IB_ADEV)
185		return false;
186
187	if (is_ib_rep_supported(dev))
188		return false;
189
190	if (is_mp_supported(dev))
191		return false;
192
193	return true;
194}
195
196static bool is_ib_enabled(struct mlx5_core_dev *dev)
197{
198	union devlink_param_value val;
199	int err;
200
201	err = devl_param_driverinit_value_get(priv_to_devlink(dev),
202					      DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA,
203					      &val);
204	return err ? false : val.vbool;
205}
206
207static bool is_dpll_supported(struct mlx5_core_dev *dev)
208{
209	if (!IS_ENABLED(CONFIG_MLX5_DPLL))
210		return false;
211
212	if (!MLX5_CAP_MCAM_REG2(dev, synce_registers)) {
213		mlx5_core_dbg(dev, "Missing SyncE capability\n");
214		return false;
215	}
216
217	return true;
218}
219
220enum {
221	MLX5_INTERFACE_PROTOCOL_ETH,
222	MLX5_INTERFACE_PROTOCOL_ETH_REP,
223
224	MLX5_INTERFACE_PROTOCOL_IB,
225	MLX5_INTERFACE_PROTOCOL_IB_REP,
226	MLX5_INTERFACE_PROTOCOL_MPIB,
227
228	MLX5_INTERFACE_PROTOCOL_VNET,
229
230	MLX5_INTERFACE_PROTOCOL_DPLL,
231	MLX5_INTERFACE_PROTOCOL_FWCTL,
232};
233
234static bool is_fwctl_supported(struct mlx5_core_dev *dev)
235{
236	/* fwctl is most useful on PFs, prevent fwctl on SFs for now */
237	return MLX5_CAP_GEN(dev, uctx_cap) && !mlx5_core_is_sf(dev);
238}
239
240static const struct mlx5_adev_device {
241	const char *suffix;
242	bool (*is_supported)(struct mlx5_core_dev *dev);
243	bool (*is_enabled)(struct mlx5_core_dev *dev);
244} mlx5_adev_devices[] = {
245	[MLX5_INTERFACE_PROTOCOL_VNET] = { .suffix = "vnet",
246					   .is_supported = &mlx5_vnet_supported,
247					   .is_enabled = &is_vnet_enabled },
248	[MLX5_INTERFACE_PROTOCOL_IB] = { .suffix = "rdma",
249					 .is_supported = &mlx5_rdma_supported,
250					 .is_enabled = &is_ib_enabled },
251	[MLX5_INTERFACE_PROTOCOL_ETH] = { .suffix = "eth",
252					  .is_supported = &mlx5_eth_supported,
253					  .is_enabled = &mlx5_core_is_eth_enabled },
254	[MLX5_INTERFACE_PROTOCOL_ETH_REP] = { .suffix = "eth-rep",
255					   .is_supported = &is_eth_rep_supported },
256	[MLX5_INTERFACE_PROTOCOL_IB_REP] = { .suffix = "rdma-rep",
257					   .is_supported = &is_ib_rep_supported },
258	[MLX5_INTERFACE_PROTOCOL_MPIB] = { .suffix = "multiport",
259					   .is_supported = &is_mp_supported },
260	[MLX5_INTERFACE_PROTOCOL_DPLL] = { .suffix = "dpll",
261					   .is_supported = &is_dpll_supported },
262	[MLX5_INTERFACE_PROTOCOL_FWCTL] = { .suffix = "fwctl",
263					    .is_supported = &is_fwctl_supported },
264};
265
266int mlx5_adev_idx_alloc(void)
267{
268	return ida_alloc(&mlx5_adev_ida, GFP_KERNEL);
269}
270
271void mlx5_adev_idx_free(int idx)
272{
273	ida_free(&mlx5_adev_ida, idx);
274}
275
276int mlx5_adev_init(struct mlx5_core_dev *dev)
277{
278	struct mlx5_priv *priv = &dev->priv;
279
280	priv->adev = kcalloc(ARRAY_SIZE(mlx5_adev_devices),
281			     sizeof(struct mlx5_adev *), GFP_KERNEL);
282	if (!priv->adev)
283		return -ENOMEM;
284
285	return 0;
286}
287
288void mlx5_adev_cleanup(struct mlx5_core_dev *dev)
289{
290	struct mlx5_priv *priv = &dev->priv;
291
292	kfree(priv->adev);
293}
294
295static void adev_release(struct device *dev)
296{
297	struct mlx5_adev *mlx5_adev =
298		container_of(dev, struct mlx5_adev, adev.dev);
299	struct mlx5_priv *priv = &mlx5_adev->mdev->priv;
300	int idx = mlx5_adev->idx;
301
302	kfree(mlx5_adev);
303	priv->adev[idx] = NULL;
304}
305
306static struct mlx5_adev *add_adev(struct mlx5_core_dev *dev, int idx)
307{
308	const char *suffix = mlx5_adev_devices[idx].suffix;
309	struct auxiliary_device *adev;
310	struct mlx5_adev *madev;
311	int ret;
312
313	madev = kzalloc(sizeof(*madev), GFP_KERNEL);
314	if (!madev)
315		return ERR_PTR(-ENOMEM);
316
317	adev = &madev->adev;
318	adev->id = dev->priv.adev_idx;
319	adev->name = suffix;
320	adev->dev.parent = dev->device;
321	adev->dev.release = adev_release;
322	madev->mdev = dev;
323	madev->idx = idx;
324
325	ret = auxiliary_device_init(adev);
326	if (ret) {
327		kfree(madev);
328		return ERR_PTR(ret);
329	}
330
331	ret = auxiliary_device_add(adev);
332	if (ret) {
333		auxiliary_device_uninit(adev);
334		return ERR_PTR(ret);
335	}
336	return madev;
337}
338
339static void del_adev(struct auxiliary_device *adev)
340{
341	auxiliary_device_delete(adev);
342	auxiliary_device_uninit(adev);
343}
344
345void mlx5_dev_set_lightweight(struct mlx5_core_dev *dev)
346{
347	mlx5_devcom_comp_lock(dev->priv.hca_devcom_comp);
348	dev->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV;
349	mlx5_devcom_comp_unlock(dev->priv.hca_devcom_comp);
350}
351
352bool mlx5_dev_is_lightweight(struct mlx5_core_dev *dev)
353{
354	return dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV;
355}
356
357int mlx5_attach_device(struct mlx5_core_dev *dev)
358{
359	struct mlx5_priv *priv = &dev->priv;
360	struct auxiliary_device *adev;
361	const struct auxiliary_driver *adrv;
362	int ret = 0, i;
363
364	devl_assert_locked(priv_to_devlink(dev));
365	mlx5_devcom_comp_lock(dev->priv.hca_devcom_comp);
366	priv->flags &= ~MLX5_PRIV_FLAGS_DETACH;
367	for (i = 0; i < ARRAY_SIZE(mlx5_adev_devices); i++) {
368		if (!priv->adev[i]) {
369			bool is_supported = false;
370
371			if (mlx5_adev_devices[i].is_enabled) {
372				bool enabled;
373
374				enabled = mlx5_adev_devices[i].is_enabled(dev);
375				if (!enabled)
376					continue;
377			}
378
379			if (mlx5_adev_devices[i].is_supported)
380				is_supported = mlx5_adev_devices[i].is_supported(dev);
381
382			if (!is_supported)
383				continue;
384
385			priv->adev[i] = add_adev(dev, i);
386			if (IS_ERR(priv->adev[i])) {
387				ret = PTR_ERR(priv->adev[i]);
388				priv->adev[i] = NULL;
389			}
390		} else {
391			adev = &priv->adev[i]->adev;
392
393			/* Pay attention that this is not PCI driver that
394			 * mlx5_core_dev is connected, but auxiliary driver.
395			 */
396			if (!adev->dev.driver)
397				continue;
398			adrv = to_auxiliary_drv(adev->dev.driver);
399
400			if (adrv->resume)
401				ret = adrv->resume(adev);
402		}
403		if (ret) {
404			mlx5_core_warn(dev, "Device[%d] (%s) failed to load\n",
405				       i, mlx5_adev_devices[i].suffix);
406
407			break;
408		}
409	}
410	mlx5_devcom_comp_unlock(dev->priv.hca_devcom_comp);
411	return ret;
412}
413
414void mlx5_detach_device(struct mlx5_core_dev *dev, bool suspend)
415{
416	struct mlx5_priv *priv = &dev->priv;
417	struct auxiliary_device *adev;
418	const struct auxiliary_driver *adrv;
419	pm_message_t pm = {};
420	int i;
421
422	devl_assert_locked(priv_to_devlink(dev));
423	mlx5_devcom_comp_lock(dev->priv.hca_devcom_comp);
424	for (i = ARRAY_SIZE(mlx5_adev_devices) - 1; i >= 0; i--) {
425		if (!priv->adev[i])
426			continue;
427
428		if (mlx5_adev_devices[i].is_enabled) {
429			bool enabled;
430
431			enabled = mlx5_adev_devices[i].is_enabled(dev);
432			if (!enabled)
433				goto skip_suspend;
434		}
435
436		adev = &priv->adev[i]->adev;
437		/* Auxiliary driver was unbind manually through sysfs */
438		if (!adev->dev.driver)
439			goto skip_suspend;
440
441		adrv = to_auxiliary_drv(adev->dev.driver);
442
443		if (adrv->suspend && suspend) {
444			adrv->suspend(adev, pm);
445			continue;
446		}
447
448skip_suspend:
449		del_adev(&priv->adev[i]->adev);
450		priv->adev[i] = NULL;
451	}
452	priv->flags |= MLX5_PRIV_FLAGS_DETACH;
453	mlx5_devcom_comp_unlock(dev->priv.hca_devcom_comp);
454}
455
456int mlx5_register_device(struct mlx5_core_dev *dev)
457{
458	int ret;
459
460	devl_assert_locked(priv_to_devlink(dev));
461	mlx5_devcom_comp_lock(dev->priv.hca_devcom_comp);
462	dev->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV;
463	ret = mlx5_rescan_drivers_locked(dev);
464	mlx5_devcom_comp_unlock(dev->priv.hca_devcom_comp);
465	if (ret)
466		mlx5_unregister_device(dev);
467
468	return ret;
469}
470
471void mlx5_unregister_device(struct mlx5_core_dev *dev)
472{
473	devl_assert_locked(priv_to_devlink(dev));
474	mlx5_devcom_comp_lock(dev->priv.hca_devcom_comp);
475	dev->priv.flags = MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV;
476	mlx5_rescan_drivers_locked(dev);
477	mlx5_devcom_comp_unlock(dev->priv.hca_devcom_comp);
478}
479
480static int add_drivers(struct mlx5_core_dev *dev)
481{
482	struct mlx5_priv *priv = &dev->priv;
483	int i, ret = 0;
484
485	for (i = 0; i < ARRAY_SIZE(mlx5_adev_devices); i++) {
486		bool is_supported = false;
487
488		if (priv->adev[i])
489			continue;
490
491		if (mlx5_adev_devices[i].is_enabled &&
492		    !(mlx5_adev_devices[i].is_enabled(dev)))
493			continue;
494
495		if (mlx5_adev_devices[i].is_supported)
496			is_supported = mlx5_adev_devices[i].is_supported(dev);
497
498		if (!is_supported)
499			continue;
500
501		priv->adev[i] = add_adev(dev, i);
502		if (IS_ERR(priv->adev[i])) {
503			mlx5_core_warn(dev, "Device[%d] (%s) failed to load\n",
504				       i, mlx5_adev_devices[i].suffix);
505			/* We continue to rescan drivers and leave to the caller
506			 * to make decision if to release everything or continue.
507			 */
508			ret = PTR_ERR(priv->adev[i]);
509			priv->adev[i] = NULL;
510		}
511	}
512	return ret;
513}
514
515static void delete_drivers(struct mlx5_core_dev *dev)
516{
517	struct mlx5_priv *priv = &dev->priv;
518	bool delete_all;
519	int i;
520
521	delete_all = priv->flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV;
522
523	for (i = ARRAY_SIZE(mlx5_adev_devices) - 1; i >= 0; i--) {
524		bool is_supported = false;
525
526		if (!priv->adev[i])
527			continue;
528
529		if (mlx5_adev_devices[i].is_enabled) {
530			bool enabled;
531
532			enabled = mlx5_adev_devices[i].is_enabled(dev);
533			if (!enabled)
534				goto del_adev;
535		}
536
537		if (mlx5_adev_devices[i].is_supported && !delete_all)
538			is_supported = mlx5_adev_devices[i].is_supported(dev);
539
540		if (is_supported)
541			continue;
542
543del_adev:
544		del_adev(&priv->adev[i]->adev);
545		priv->adev[i] = NULL;
546	}
547}
548
549/* This function is used after mlx5_core_dev is reconfigured.
550 */
551int mlx5_rescan_drivers_locked(struct mlx5_core_dev *dev)
552{
553	struct mlx5_priv *priv = &dev->priv;
554
555	if (priv->flags & MLX5_PRIV_FLAGS_DETACH)
556		return 0;
557
558	delete_drivers(dev);
559	if (priv->flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)
560		return 0;
561
562	return add_drivers(dev);
563}
564
565bool mlx5_same_hw_devs(struct mlx5_core_dev *dev, struct mlx5_core_dev *peer_dev)
566{
567	u8 fsystem_guid[MLX5_SW_IMAGE_GUID_MAX_BYTES];
568	u8 psystem_guid[MLX5_SW_IMAGE_GUID_MAX_BYTES];
569	u8 flen;
570	u8 plen;
571
572	mlx5_query_nic_sw_system_image_guid(dev, fsystem_guid, &flen);
573	mlx5_query_nic_sw_system_image_guid(peer_dev, psystem_guid, &plen);
574
575	return plen && flen && flen == plen &&
576		!memcmp(fsystem_guid, psystem_guid, flen);
577}
578
579void mlx5_core_reps_aux_devs_remove(struct mlx5_core_dev *dev)
580{
581	struct mlx5_priv *priv = &dev->priv;
582
583	if (priv->adev[MLX5_INTERFACE_PROTOCOL_ETH])
584		device_lock_assert(&priv->adev[MLX5_INTERFACE_PROTOCOL_ETH]->adev.dev);
585	else
586		mlx5_core_err(dev, "ETH driver already removed\n");
587	if (priv->adev[MLX5_INTERFACE_PROTOCOL_IB_REP])
588		del_adev(&priv->adev[MLX5_INTERFACE_PROTOCOL_IB_REP]->adev);
589	if (priv->adev[MLX5_INTERFACE_PROTOCOL_ETH_REP])
590		del_adev(&priv->adev[MLX5_INTERFACE_PROTOCOL_ETH_REP]->adev);
591}
~/ Read-only file preview.