summaryrefslogtreecommitdiff
path: root/drivers/net/mlx5/mlx5_mp.c
blob: 701ee1d260b67743fd2550aa36ac8b301db1a7ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright 2019 6WIND S.A.
 * Copyright 2019 Mellanox Technologies, Ltd
 */

#include <assert.h>
#include <stdio.h>
#include <time.h>

#include <rte_eal.h>
#include <rte_ethdev_driver.h>
#include <rte_string_fns.h>

#include "mlx5.h"
#include "mlx5_utils.h"

/**
 * Initialize IPC message.
 *
 * @param[in] dev
 *   Pointer to Ethernet structure.
 * @param[out] msg
 *   Pointer to message to fill in.
 * @param[in] type
 *   Message type.
 */
static inline void
mp_init_msg(struct rte_eth_dev *dev, struct rte_mp_msg *msg,
	    enum mlx5_mp_req_type type)
{
	struct mlx5_mp_param *param = (struct mlx5_mp_param *)msg->param;

	memset(msg, 0, sizeof(*msg));
	strlcpy(msg->name, MLX5_MP_NAME, sizeof(msg->name));
	msg->len_param = sizeof(*param);
	param->type = type;
	param->port_id = dev->data->port_id;
}

/**
 * IPC message handler of primary process.
 *
 * @param[in] dev
 *   Pointer to Ethernet structure.
 * @param[in] peer
 *   Pointer to the peer socket path.
 *
 * @return
 *   0 on success, a negative errno value otherwise and rte_errno is set.
 */
static int
mp_primary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
{
	struct rte_mp_msg mp_res;
	struct mlx5_mp_param *res = (struct mlx5_mp_param *)mp_res.param;
	const struct mlx5_mp_param *param =
		(const struct mlx5_mp_param *)mp_msg->param;
	struct rte_eth_dev *dev;
	struct mlx5_priv *priv;
	int ret;

	assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
	if (!rte_eth_dev_is_valid_port(param->port_id)) {
		rte_errno = ENODEV;
		DRV_LOG(ERR, "port %u invalid port ID", param->port_id);
		return -rte_errno;
	}
	dev = &rte_eth_devices[param->port_id];
	priv = dev->data->dev_private;
	switch (param->type) {
	case MLX5_MP_REQ_VERBS_CMD_FD:
		mp_init_msg(dev, &mp_res, param->type);
		mp_res.num_fds = 1;
		mp_res.fds[0] = priv->sh->ctx->cmd_fd;
		res->result = 0;
		ret = rte_mp_reply(&mp_res, peer);
		break;
	default:
		rte_errno = EINVAL;
		DRV_LOG(ERR, "port %u invalid mp request type",
			dev->data->port_id);
		return -rte_errno;
	}
	return ret;
}

/**
 * Request Verbs command file descriptor for mmap to the primary process.
 *
 * @param[in] dev
 *   Pointer to Ethernet structure.
 *
 * @return
 *   fd on success, a negative errno value otherwise and rte_errno is set.
 */
int
mlx5_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev)
{
	struct rte_mp_msg mp_req;
	struct rte_mp_msg *mp_res;
	struct rte_mp_reply mp_rep;
	struct mlx5_mp_param *res;
	struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
	int ret;

	assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
	mp_init_msg(dev, &mp_req, MLX5_MP_REQ_VERBS_CMD_FD);
	ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
	if (ret) {
		DRV_LOG(ERR, "port %u request to primary process failed",
			dev->data->port_id);
		return -rte_errno;
	}
	assert(mp_rep.nb_received == 1);
	mp_res = &mp_rep.msgs[0];
	res = (struct mlx5_mp_param *)mp_res->param;
	if (res->result) {
		rte_errno = -res->result;
		DRV_LOG(ERR,
			"port %u failed to get command FD from primary process",
			dev->data->port_id);
		ret = -rte_errno;
		goto exit;
	}
	assert(mp_res->num_fds == 1);
	ret = mp_res->fds[0];
	DRV_LOG(DEBUG, "port %u command FD from primary is %d",
		dev->data->port_id, ret);
exit:
	free(mp_rep.msgs);
	return ret;
}

/**
 * Initialize by primary process.
 */
void
mlx5_mp_init_primary(void)
{
	assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
	rte_mp_action_register(MLX5_MP_NAME, mp_primary_handle);
}

/**
 * Un-initialize by primary process.
 */
void
mlx5_mp_uninit_primary(void)
{
	assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
	rte_mp_action_unregister(MLX5_MP_NAME);
}