drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
Extension
.c
Size
66152 bytes
Lines
2775
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

mlx5_ldev_for_each(i, 0, ldev) {
			for (j  = 0; j < ldev->buckets; j++) {
				idx = i * ldev->buckets + j;
				err = scnprintf(buf + written, 10,
						" port %d:%d", i + 1, ldev->v2p_map[idx]);
				if (err != 9)
					return;
				written += err;
			}
		}
		mlx5_core_info(dev, "lag map:%s\n", buf);
	}
}

static int mlx5_lag_netdev_event(struct notifier_block *this,
				 unsigned long event, void *ptr);
static void mlx5_do_bond_work(struct work_struct *work);

static void mlx5_ldev_free(struct kref *ref)
{
	struct mlx5_lag *ldev = container_of(ref, struct mlx5_lag, ref);
	struct lag_func *pf;
	struct net *net;
	int i;

	if (ldev->nb.notifier_call) {
		net = read_pnet(&ldev->net);
		unregister_netdevice_notifier_net(net, &ldev->nb);
	}

	mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
		pf = mlx5_lag_pf(ldev, i);
		if (pf->port_change_nb.nb.notifier_call) {
			struct mlx5_nb *nb = &pf->port_change_nb;

			mlx5_eq_notifier_unregister(pf->dev, nb);
		}
		xa_erase(&ldev->pfs, i);
		kfree(pf);
	}
	xa_destroy(&ldev->pfs);

	mlx5_lag_mp_cleanup(ldev);
	cancel_delayed_work_sync(&ldev->bond_work);
	cancel_work_sync(&ldev->speed_update_work);
	destroy_workqueue(ldev->wq);
	mutex_destroy(&ldev->lock);
	kfree(ldev);
}

static void mlx5_ldev_put(struct mlx5_lag *ldev)
{
	kref_put(&ldev->ref, mlx5_ldev_free);
}

static void mlx5_ldev_get(struct mlx5_lag *ldev)
{
	kref_get(&ldev->ref);
}

static struct mlx5_lag *mlx5_lag_dev_alloc(struct mlx5_core_dev *dev)
{
	struct mlx5_lag *ldev;
	int err;

	ldev = kzalloc_obj(*ldev);
	if (!ldev)
		return NULL;

	ldev->wq = create_singlethread_workqueue("mlx5_lag");
	if (!ldev->wq) {
		kfree(ldev);
		return NULL;
	}

	kref_init(&ldev->ref);
	mutex_init(&ldev->lock);
	xa_init_flags(&ldev->pfs, XA_FLAGS_ALLOC);
	INIT_DELAYED_WORK(&ldev->bond_work, mlx5_do_bond_work);
	INIT_WORK(&ldev->speed_update_work, mlx5_mpesw_speed_update_work);

	if (!mlx5_sd_is_supported(dev)) {
		ldev->nb.notifier_call = mlx5_lag_netdev_event;
		write_pnet(&ldev->net, mlx5_core_net(dev));
		if (register_netdevice_notifier_net(read_pnet(&ldev->net),
						    &ldev->nb)) {
			ldev->nb.notifier_call = NULL;
			mlx5_core_err(dev, "Failed to register LAG netdev notifier\n");
		}
	}

Annotation

Implementation Notes