Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2024 Cisco Systems, Inc. All rights reserved.
3 : : */
4 : :
5 : : #include <rte_memzone.h>
6 : : #include <ethdev_driver.h>
7 : :
8 : : #include "enic_compat.h"
9 : : #include "enic.h"
10 : : #include "enic_sriov.h"
11 : :
12 : : static int enic_check_chan_capability(struct enic *enic);
13 : : static int enic_register_vf(struct enic *enic);
14 : : static void enic_unregister_vf(struct enic *enic);
15 : :
16 : : const char *msg_type_str[ENIC_MBOX_MAX] = {
17 : : "VF_CAPABILITY_REQUEST",
18 : : "VF_CAPABILITY_REPLY",
19 : : "VF_REGISTER_REQUEST",
20 : : "VF_REGISTER_REPLY",
21 : : "VF_UNREGISTER_REQUEST",
22 : : "VF_UNREGISTER_REPLY",
23 : : "PF_LINK_STATE_NOTIF",
24 : : "PF_LINK_STATE_ACK",
25 : : "PF_GET_STATS_REQUEST",
26 : : "PF_GET_STATS_REPLY",
27 : : "VF_ADD_DEL_MAC_REQUEST",
28 : : "VF_ADD_DEL_MAC_REPLY",
29 : : "PF_SET_ADMIN_MAC_NOTIF",
30 : : "PF_SET_ADMIN_MAC_ACK",
31 : : "VF_SET_PKT_FILTER_FLAGS_REQUEST",
32 : : "VF_SET_PKT_FILTER_FLAGS_REPLY",
33 : : };
34 : :
35 : : static const char *enic_mbox_msg_type_str(enum enic_mbox_msg_type type)
36 : : {
37 [ # # ]: 0 : if (type >= 0 && type < ENIC_MBOX_MAX)
38 : 0 : return msg_type_str[type];
39 : : return "INVALID";
40 : : }
41 : :
42 : : static bool admin_chan_enabled(struct enic *enic)
43 : : {
44 : 0 : return enic->admin_chan_enabled;
45 : : }
46 : :
47 : : static void lock_admin_chan(struct enic *enic)
48 : : {
49 : 0 : pthread_mutex_lock(&enic->admin_chan_lock);
50 : 0 : }
51 : :
52 : : static void unlock_admin_chan(struct enic *enic)
53 : : {
54 : 0 : pthread_mutex_unlock(&enic->admin_chan_lock);
55 : : }
56 : :
57 : 0 : static int enic_enable_admin_rq(struct enic *enic)
58 : : {
59 : : uint32_t rqbuf_size = ENIC_ADMIN_BUF_SIZE;
60 : : uint32_t desc_count = 256;
61 : : struct rq_enet_desc *rqd;
62 : : struct vnic_rq *rq;
63 : : struct vnic_cq *cq;
64 : : rte_iova_t dma;
65 : : uint32_t i;
66 : : int cq_idx;
67 : : int err = 0;
68 : : char name[RTE_MEMZONE_NAMESIZE];
69 : : static int instance;
70 : :
71 : 0 : ENICPMD_FUNC_TRACE();
72 : 0 : rq = &enic->admin_rq;
73 : : cq_idx = ENIC_ADMIN_RQ_CQ;
74 : 0 : cq = &enic->admin_cq[cq_idx];
75 : 0 : err = vnic_admin_rq_alloc(enic->vdev, rq, desc_count,
76 : : sizeof(struct rq_enet_desc));
77 [ # # ]: 0 : if (err) {
78 : 0 : dev_err(enic, "failed to allocate admin RQ\n");
79 : 0 : return err;
80 : : }
81 : 0 : err = vnic_admin_cq_alloc(enic->vdev, cq, cq_idx,
82 : : SOCKET_ID_ANY, desc_count, sizeof(struct cq_enet_rq_desc));
83 [ # # ]: 0 : if (err) {
84 : 0 : dev_err(enic, "failed to allocate CQ for admin RQ\n");
85 : 0 : return err;
86 : : }
87 : :
88 : 0 : vnic_rq_init(rq, cq_idx, 0, 0);
89 : 0 : vnic_cq_clean(cq);
90 : 0 : vnic_cq_init(cq,
91 : : 0 /* flow_control_enable */,
92 : : 1 /* color_enable */,
93 : : 0 /* cq_head */,
94 : : 0 /* cq_tail */,
95 : : 1 /* cq_tail_color */,
96 : : 1 /* interrupt_enable */,
97 : : 1 /* cq_entry_enable */,
98 : : 0 /* cq_message_enable */,
99 : : ENICPMD_LSC_INTR_OFFSET /* interrupt_offset */,
100 : : 0 /* cq_message_addr */);
101 : 0 : vnic_rq_enable(rq);
102 : :
103 : : /*
104 : : * Allocate RQ DMA buffers. The admin chan reuses these
105 : : * buffers and never allocates new ones again
106 : : */
107 : 0 : snprintf((char *)name, sizeof(name), "admin-rq-buf-%d", instance++);
108 : 0 : rq->admin_msg_rz = rte_memzone_reserve_aligned((const char *)name,
109 : : desc_count * rqbuf_size, SOCKET_ID_ANY,
110 : : RTE_MEMZONE_IOVA_CONTIG, ENIC_PAGE_SIZE);
111 [ # # ]: 0 : if (!rq->admin_msg_rz)
112 : : return -ENOMEM;
113 : :
114 : 0 : memset(rq->admin_msg_rz->addr, 0, desc_count * rqbuf_size);
115 : :
116 : 0 : dma = rq->admin_msg_rz->iova;
117 : 0 : rqd = rq->ring.descs;
118 [ # # ]: 0 : for (i = 0; i < desc_count; i++) {
119 : : rq_enet_desc_enc(rqd, dma, RQ_ENET_TYPE_ONLY_SOP,
120 : : rqbuf_size);
121 : 0 : dma += rqbuf_size;
122 : 0 : rqd++;
123 : : }
124 : : rte_rmb();
125 : 0 : rq->posted_index = rq->ring.desc_count - 1;
126 : 0 : rq->admin_next_idx = 0;
127 : 0 : ENICPMD_LOG(DEBUG, "admin rq posted_index %u", rq->posted_index);
128 : 0 : iowrite32(rq->posted_index, &rq->ctrl->posted_index);
129 : : rte_wmb();
130 : 0 : return err;
131 : : }
132 : :
133 : 0 : static int enic_enable_admin_wq(struct enic *enic)
134 : : {
135 : : uint32_t wqbuf_size = ENIC_ADMIN_BUF_SIZE;
136 : : uint32_t desc_count = 256;
137 : : struct vnic_wq *wq;
138 : : struct vnic_cq *cq;
139 : : int cq_idx;
140 : : int err = 0;
141 : : char name[RTE_MEMZONE_NAMESIZE];
142 : : static int instance;
143 : :
144 : 0 : ENICPMD_FUNC_TRACE();
145 : 0 : wq = &enic->admin_wq;
146 : : cq_idx = ENIC_ADMIN_WQ_CQ;
147 : 0 : cq = &enic->admin_cq[cq_idx];
148 : 0 : err = vnic_admin_wq_alloc(enic->vdev, wq, desc_count, sizeof(struct wq_enet_desc));
149 [ # # ]: 0 : if (err) {
150 : 0 : dev_err(enic, "failed to allocate admin WQ\n");
151 : 0 : return err;
152 : : }
153 : 0 : err = vnic_admin_cq_alloc(enic->vdev, cq, cq_idx,
154 : : SOCKET_ID_ANY, desc_count, sizeof(struct cq_enet_wq_desc));
155 [ # # ]: 0 : if (err) {
156 : 0 : vnic_wq_free(wq);
157 : 0 : dev_err(enic, "failed to allocate CQ for admin WQ\n");
158 : 0 : return err;
159 : : }
160 : 0 : snprintf((char *)name, sizeof(name),
161 : 0 : "vnic_cqmsg-%s-admin-wq-%d", enic->bdf_name, instance++);
162 : 0 : wq->cqmsg_rz = rte_memzone_reserve_aligned((const char *)name,
163 : : sizeof(uint32_t), SOCKET_ID_ANY,
164 : : RTE_MEMZONE_IOVA_CONTIG, ENIC_PAGE_SIZE);
165 [ # # ]: 0 : if (!wq->cqmsg_rz)
166 : : return -ENOMEM;
167 : :
168 : 0 : vnic_wq_init(wq, cq_idx, 0, 0);
169 : 0 : vnic_cq_clean(cq);
170 : 0 : vnic_cq_init(cq,
171 : : 0 /* flow_control_enable */,
172 : : 1 /* color_enable */,
173 : : 0 /* cq_head */,
174 : : 0 /* cq_tail */,
175 : : 1 /* cq_tail_color */,
176 : : 0 /* interrupt_enable */,
177 : : 0 /* cq_entry_enable */,
178 : : 1 /* cq_message_enable */,
179 : : 0 /* interrupt offset */,
180 : 0 : (uint64_t)wq->cqmsg_rz->iova);
181 : :
182 : 0 : vnic_wq_enable(wq);
183 : :
184 : 0 : snprintf((char *)name, sizeof(name), "admin-wq-buf-%d", instance++);
185 : 0 : wq->admin_msg_rz = rte_memzone_reserve_aligned((const char *)name,
186 : : desc_count * wqbuf_size, SOCKET_ID_ANY,
187 : : RTE_MEMZONE_IOVA_CONTIG, ENIC_PAGE_SIZE);
188 [ # # ]: 0 : if (!wq->admin_msg_rz)
189 : 0 : return -ENOMEM;
190 : :
191 : : return err;
192 : : }
193 : :
194 : 0 : static void enic_admin_wq_post(struct enic *enic, void *msg)
195 : : {
196 : : struct wq_enet_desc *desc;
197 : : struct enic_mbox_hdr *hdr;
198 : : unsigned int head_idx;
199 : : struct vnic_wq *wq;
200 : : rte_iova_t dma;
201 : : int msg_size;
202 : : void *va;
203 : :
204 : 0 : ENICPMD_FUNC_TRACE();
205 : : wq = &enic->admin_wq;
206 : : hdr = msg;
207 : 0 : msg_size = hdr->msg_len;
208 [ # # ]: 0 : RTE_VERIFY(msg_size < ENIC_ADMIN_BUF_SIZE);
209 : :
210 : 0 : head_idx = wq->head_idx;
211 : 0 : desc = (struct wq_enet_desc *)wq->ring.descs;
212 : 0 : desc = desc + head_idx;
213 : :
214 : : /* Copy message to pre-allocated WQ DMA buffer */
215 : 0 : dma = wq->admin_msg_rz->iova + ENIC_ADMIN_BUF_SIZE * head_idx;
216 : 0 : va = (void *)((char *)wq->admin_msg_rz->addr + ENIC_ADMIN_BUF_SIZE * head_idx);
217 : 0 : memcpy(va, msg, msg_size);
218 : :
219 : 0 : ENICPMD_LOG(DEBUG, "post admin wq msg at %u", head_idx);
220 : :
221 : : /* Send message to PF: loopback=1 */
222 : : wq_enet_desc_enc(desc, dma, msg_size,
223 : : 0 /* mss */,
224 : : 0 /* header_len */,
225 : : 0 /* offload_mode */, 1 /* eop */, 1 /* cq */,
226 : : 0 /* fcoe */,
227 : : 1 /* vlan_tag_insert */,
228 : : 0 /* vlan_id */,
229 : : 1 /* loopback */);
230 [ # # ]: 0 : head_idx = enic_ring_incr(wq->ring.desc_count, head_idx);
231 : : rte_wmb();
232 : 0 : iowrite32_relaxed(head_idx, &wq->ctrl->posted_index);
233 : 0 : wq->head_idx = head_idx;
234 : 0 : }
235 : :
236 : 0 : static void enic_mbox_init_msg_hdr(struct enic *enic, void *msg,
237 : : enum enic_mbox_msg_type type)
238 : : {
239 : : struct enic_mbox_hdr *hdr;
240 : : int len;
241 : :
242 [ # # # # : 0 : switch (type) {
# # # # ]
243 : : case ENIC_MBOX_VF_CAPABILITY_REQUEST:
244 : : len = sizeof(struct enic_mbox_vf_capability_msg);
245 : : break;
246 : 0 : case ENIC_MBOX_VF_REGISTER_REQUEST:
247 : : len = sizeof(struct enic_mbox_vf_register_msg);
248 : 0 : break;
249 : 0 : case ENIC_MBOX_VF_UNREGISTER_REQUEST:
250 : : len = sizeof(struct enic_mbox_vf_unregister_msg);
251 : 0 : break;
252 : 0 : case ENIC_MBOX_VF_SET_PKT_FILTER_FLAGS_REQUEST:
253 : : len = sizeof(struct enic_mbox_vf_set_pkt_filter_flags_msg);
254 : 0 : break;
255 : 0 : case ENIC_MBOX_PF_LINK_STATE_ACK:
256 : : len = sizeof(struct enic_mbox_pf_link_state_ack_msg);
257 : 0 : break;
258 : 0 : case ENIC_MBOX_PF_GET_STATS_REPLY:
259 : : len = sizeof(struct enic_mbox_pf_get_stats_reply_msg);
260 : 0 : break;
261 : 0 : case ENIC_MBOX_VF_ADD_DEL_MAC_REQUEST:
262 : : len = sizeof(struct enic_mbox_vf_add_del_mac_msg);
263 : 0 : break;
264 : : default:
265 : 0 : RTE_VERIFY(false);
266 : : break;
267 : : }
268 : 0 : memset(msg, 0, len);
269 : : hdr = msg;
270 : 0 : hdr->dst_vnic_id = ENIC_MBOX_DST_PF;
271 : 0 : hdr->src_vnic_id = enic->admin_chan_vf_id;
272 : 0 : hdr->msg_type = type;
273 : 0 : hdr->flags = 0;
274 : 0 : hdr->msg_len = len;
275 : 0 : hdr->msg_num = ++enic->admin_chan_msg_num;
276 : 0 : }
277 : :
278 : : /*
279 : : * See if there is a new receive packet. If yes, copy it out.
280 : : */
281 : 0 : static int enic_admin_rq_peek(struct enic *enic, uint8_t *msg, int *msg_len)
282 : : {
283 : : const int desc_size = sizeof(struct cq_enet_rq_desc);
284 : : volatile struct cq_desc *cqd_ptr;
285 : : uint16_t cq_idx, rq_idx, rq_num;
286 : : struct cq_enet_rq_desc *cqrd;
287 : : uint16_t seg_length;
288 : : struct cq_desc cqd;
289 : : struct vnic_rq *rq;
290 : : struct vnic_cq *cq;
291 : : uint8_t tc, color;
292 : : int next_idx;
293 : : void *va;
294 : :
295 : : rq = &enic->admin_rq;
296 : : cq = &enic->admin_cq[ENIC_ADMIN_RQ_CQ];
297 : 0 : cq_idx = cq->to_clean;
298 : 0 : cqd_ptr = (struct cq_desc *)((uintptr_t)(cq->ring.descs) +
299 : 0 : (uintptr_t)cq_idx * desc_size);
300 : 0 : color = cq->last_color;
301 : 0 : tc = *(volatile uint8_t *)((uintptr_t)cqd_ptr + desc_size - 1);
302 : : /* No new packet, return */
303 [ # # ]: 0 : if ((tc & CQ_DESC_COLOR_MASK_NOSHIFT) == color)
304 : : return -EAGAIN;
305 : 0 : ENICPMD_LOG(DEBUG, "admin RQ has a completion cq_idx %u color %u", cq_idx, color);
306 : :
307 : 0 : cqd = *cqd_ptr;
308 : : cqrd = (struct cq_enet_rq_desc *)&cqd;
309 : 0 : seg_length = rte_le_to_cpu_16(cqrd->bytes_written_flags) &
310 : : CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK;
311 : :
312 : 0 : rq_num = cqd.q_number & CQ_DESC_Q_NUM_MASK;
313 : 0 : rq_idx = (cqd.completed_index & CQ_DESC_COMP_NDX_MASK);
314 : 0 : ENICPMD_LOG(DEBUG, "rq_num %u rq_idx %u len %u", rq_num, rq_idx, seg_length);
315 : :
316 [ # # ]: 0 : RTE_VERIFY(rq_num == 0);
317 : 0 : next_idx = rq->admin_next_idx;
318 [ # # ]: 0 : RTE_VERIFY(rq_idx == next_idx);
319 [ # # ]: 0 : rq->admin_next_idx = enic_ring_incr(rq->ring.desc_count, next_idx);
320 : :
321 : : /* Copy out the received message */
322 : 0 : va = (void *)((char *)rq->admin_msg_rz->addr + ENIC_ADMIN_BUF_SIZE * next_idx);
323 [ # # ]: 0 : *msg_len = seg_length;
324 : : memset(msg, 0, ENIC_ADMIN_BUF_SIZE);
325 [ # # ]: 0 : memcpy(msg, va, seg_length);
326 : : memset(va, 0, ENIC_ADMIN_BUF_SIZE);
327 : :
328 : : /* Advance CQ */
329 : 0 : cq_idx++;
330 [ # # ]: 0 : if (unlikely(cq_idx == cq->ring.desc_count)) {
331 : : cq_idx = 0;
332 : 0 : cq->last_color ^= CQ_DESC_COLOR_MASK_NOSHIFT;
333 : : }
334 : 0 : cq->to_clean = cq_idx;
335 : :
336 : : /* Recycle and post RQ buffer */
337 [ # # ]: 0 : rq->posted_index = enic_ring_add(rq->ring.desc_count,
338 : : rq->posted_index,
339 : : 1);
340 : : rte_wmb();
341 : 0 : iowrite32(rq->posted_index, &rq->ctrl->posted_index);
342 : : rte_wmb();
343 : 0 : return 0;
344 : : }
345 : :
346 : 0 : int enic_enable_vf_admin_chan(struct enic *enic)
347 : : {
348 : : struct vnic_sriov_stats *stats;
349 : : int err;
350 : :
351 : 0 : ENICPMD_FUNC_TRACE();
352 : 0 : pthread_mutex_init(&enic->admin_chan_lock, NULL);
353 : 0 : err = vnic_dev_enable_admin_qp(enic->vdev, 1);
354 [ # # ]: 0 : if (err) {
355 : 0 : ENICPMD_LOG(ERR, "failed to enable admin QP type");
356 : 0 : goto out;
357 : : }
358 : 0 : err = vnic_dev_alloc_sriov_stats_mem(enic->vdev);
359 [ # # ]: 0 : if (err) {
360 : 0 : ENICPMD_LOG(ERR, "failed to allocate SR-IOV stats buffer");
361 : 0 : goto out;
362 : : }
363 : 0 : err = vnic_dev_sriov_stats(enic->vdev, &stats);
364 [ # # ]: 0 : if (err) {
365 : 0 : ENICPMD_LOG(ERR, "failed to get SR-IOV stats");
366 : 0 : goto out;
367 : : }
368 : 0 : enic->admin_chan_vf_id = stats->vf_index;
369 : 0 : enic->sriov_vf_soft_rx_stats = !!stats->sriov_host_rx_stats;
370 [ # # ]: 0 : ENICPMD_LOG(INFO, "SR-IOV VF index %u %s stats",
371 : : stats->vf_index, enic->sriov_vf_soft_rx_stats ? "soft" : "HW");
372 : 0 : err = enic_enable_admin_rq(enic);
373 [ # # ]: 0 : if (err) {
374 : 0 : ENICPMD_LOG(ERR, "failed to enable admin RQ");
375 : 0 : goto out;
376 : : }
377 : 0 : err = enic_enable_admin_wq(enic);
378 [ # # ]: 0 : if (err) {
379 : 0 : ENICPMD_LOG(ERR, "failed to enable admin WQ");
380 : 0 : goto out;
381 : : }
382 : 0 : enic->admin_chan_enabled = true;
383 : : /* Now the admin channel is ready. Send CAPABILITY as the first message */
384 : 0 : err = enic_check_chan_capability(enic);
385 [ # # ]: 0 : if (err) {
386 : 0 : ENICPMD_LOG(ERR, "failed to exchange VF_CAPABILITY message");
387 : 0 : goto out;
388 : : }
389 [ # # ]: 0 : if (enic->sriov_vf_compat_mode) {
390 : 0 : enic_disable_vf_admin_chan(enic, false);
391 : 0 : return 0;
392 : : }
393 : : /* Then register.. */
394 : 0 : err = enic_register_vf(enic);
395 [ # # ]: 0 : if (err) {
396 : 0 : ENICPMD_LOG(ERR, "failed to perform VF_REGISTER");
397 : 0 : goto out;
398 : : }
399 : : /*
400 : : * If we have to count RX packets (soft stats), do not use
401 : : * avx2 receive handlers
402 : : */
403 [ # # ]: 0 : if (enic->sriov_vf_soft_rx_stats)
404 : 0 : enic->enable_avx2_rx = 0;
405 : 0 : out:
406 : : return err;
407 : : }
408 : :
409 : 0 : int enic_disable_vf_admin_chan(struct enic *enic, bool unregister)
410 : : {
411 : : struct vnic_rq *rq;
412 : : struct vnic_wq *wq;
413 : : struct vnic_cq *cq;
414 : :
415 : 0 : ENICPMD_FUNC_TRACE();
416 [ # # ]: 0 : if (unregister)
417 : 0 : enic_unregister_vf(enic);
418 : 0 : enic->sriov_vf_soft_rx_stats = false;
419 : :
420 : 0 : rq = &enic->admin_rq;
421 : 0 : vnic_rq_disable(rq);
422 : 0 : rte_memzone_free(rq->admin_msg_rz);
423 : 0 : vnic_rq_free(rq);
424 : :
425 : 0 : cq = &enic->admin_cq[ENIC_ADMIN_RQ_CQ];
426 : 0 : vnic_cq_free(cq);
427 : :
428 : 0 : wq = &enic->admin_wq;
429 : 0 : vnic_wq_disable(wq);
430 : 0 : rte_memzone_free(wq->admin_msg_rz);
431 : 0 : rte_memzone_free(wq->cqmsg_rz);
432 : 0 : vnic_wq_free(wq);
433 : :
434 : 0 : cq = &enic->admin_cq[ENIC_ADMIN_WQ_CQ];
435 : 0 : vnic_cq_free(cq);
436 : :
437 : 0 : enic->admin_chan_enabled = false;
438 : 0 : return 0;
439 : : }
440 : :
441 : 0 : static int common_hdr_check(struct enic *enic, void *msg)
442 : : {
443 : : struct enic_mbox_hdr *hdr;
444 : :
445 : : hdr = (struct enic_mbox_hdr *)msg;
446 [ # # ]: 0 : ENICPMD_LOG(DEBUG, "RX dst %u src %u type %u(%s) flags %u len %u num %" PRIu64,
447 : : hdr->dst_vnic_id, hdr->src_vnic_id, hdr->msg_type,
448 : : enic_mbox_msg_type_str(hdr->msg_type),
449 : : hdr->flags, hdr->msg_len, hdr->msg_num);
450 [ # # ]: 0 : if (hdr->dst_vnic_id != enic->admin_chan_vf_id ||
451 [ # # ]: 0 : hdr->src_vnic_id != ENIC_MBOX_DST_PF) {
452 : 0 : ENICPMD_LOG(ERR, "unexpected dst/src in reply: dst=%u (expected=%u) src=%u",
453 : : hdr->dst_vnic_id, enic->admin_chan_vf_id, hdr->src_vnic_id);
454 : 0 : return -EINVAL;
455 : : }
456 : : return 0;
457 : : }
458 : :
459 : 0 : static int common_reply_check(__rte_unused struct enic *enic, void *msg,
460 : : enum enic_mbox_msg_type type)
461 : : {
462 : : struct enic_mbox_generic_reply_msg *reply;
463 : : struct enic_mbox_hdr *hdr;
464 : :
465 : : hdr = (struct enic_mbox_hdr *)msg;
466 : : reply = (struct enic_mbox_generic_reply_msg *)(hdr + 1);
467 [ # # ]: 0 : if (hdr->msg_type != type) {
468 : 0 : ENICPMD_LOG(ERR, "unexpected reply: expected=%u received=%u",
469 : : type, hdr->msg_type);
470 : 0 : return -EINVAL;
471 : : }
472 [ # # ]: 0 : if (reply->ret_major != 0) {
473 [ # # ]: 0 : ENICPMD_LOG(ERR, "error reply: type=%u(%s) ret_major/minor=%u/%u",
474 : : type, enic_mbox_msg_type_str(type),
475 : : reply->ret_major, reply->ret_minor);
476 : 0 : return -EINVAL;
477 : : }
478 : : return 0;
479 : : }
480 : :
481 : 0 : static void handle_pf_link_state_notif(struct enic *enic, void *msg)
482 : : {
483 : : struct enic_mbox_pf_link_state_notif_msg *notif = msg;
484 : : struct enic_mbox_pf_link_state_ack_msg ack;
485 : : struct rte_eth_link link;
486 : :
487 : 0 : ENICPMD_FUNC_TRACE();
488 : 0 : ENICPMD_LOG(DEBUG, "PF_LINK_STAT_NOTIF: link_state=%u", notif->link_state);
489 : :
490 : : /*
491 : : * Do not use enic_link_update()
492 : : * Linux PF driver disables link-status notify in FW and uses
493 : : * this admin message instead. Notify does not work. Remember
494 : : * the status from PF.
495 : : */
496 : : memset(&link, 0, sizeof(link));
497 : 0 : link.link_status = notif->link_state ? RTE_ETH_LINK_UP : RTE_ETH_LINK_DOWN;
498 : 0 : link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
499 : 0 : link.link_speed = vnic_dev_port_speed(enic->vdev);
500 : 0 : rte_eth_linkstatus_set(enic->rte_dev, &link);
501 : 0 : rte_eth_dev_callback_process(enic->rte_dev, RTE_ETH_EVENT_INTR_LSC, NULL);
502 : 0 : ENICPMD_LOG(DEBUG, "eth_linkstatus: speed=%u duplex=%u autoneg=%u status=%u",
503 : : link.link_speed, link.link_duplex, link.link_autoneg,
504 : : link.link_status);
505 : :
506 : 0 : enic_mbox_init_msg_hdr(enic, &ack, ENIC_MBOX_PF_LINK_STATE_ACK);
507 : 0 : enic_admin_wq_post(enic, &ack);
508 : 0 : ENICPMD_LOG(DEBUG, "sent PF_LINK_STATE_ACK");
509 : 0 : }
510 : :
511 : 0 : static void handle_pf_get_stats(struct enic *enic, void *msg)
512 : : {
513 : : struct enic_mbox_pf_get_stats_reply_msg reply;
514 : : struct enic_mbox_pf_get_stats_msg *req;
515 : : struct vnic_stats *hw_stats;
516 : : struct vnic_stats *vs;
517 : : unsigned int i;
518 : :
519 : 0 : ENICPMD_FUNC_TRACE();
520 : : req = msg;
521 : 0 : ENICPMD_LOG(DEBUG, "flags=0x%x", req->flags);
522 : 0 : enic_mbox_init_msg_hdr(enic, &reply, ENIC_MBOX_PF_GET_STATS_REPLY);
523 : : vs = &reply.stats.vnic_stats;
524 [ # # ]: 0 : if (req->flags & ENIC_MBOX_GET_STATS_RX) {
525 [ # # ]: 0 : for (i = 0; i < enic->rq_count; i++) {
526 : 0 : vs->rx.rx_frames_ok += enic->rq[i].soft_stats_pkts;
527 : 0 : vs->rx.rx_bytes_ok += enic->rq[i].soft_stats_bytes;
528 : : }
529 : 0 : vs->rx.rx_frames_total = vs->rx.rx_frames_ok;
530 : 0 : reply.stats.num_rx_stats = 6;
531 : : }
532 [ # # ]: 0 : if (req->flags & ENIC_MBOX_GET_STATS_TX) {
533 : 0 : vnic_dev_stats_dump(enic->vdev, &hw_stats);
534 : 0 : vs->tx = hw_stats->tx;
535 : 0 : reply.stats.num_tx_stats = 11; /* all fields up to rsvd */
536 : : }
537 : 0 : enic_admin_wq_post(enic, &reply);
538 : 0 : ENICPMD_LOG(DEBUG, "sent PF_GET_STATS_REPLY");
539 : 0 : }
540 : :
541 : 0 : static void handle_pf_request_msg(struct enic *enic, void *msg)
542 : : {
543 : : struct enic_mbox_hdr *hdr = msg;
544 : :
545 [ # # # # ]: 0 : switch (hdr->msg_type) {
546 : 0 : case ENIC_MBOX_PF_LINK_STATE_NOTIF:
547 : 0 : handle_pf_link_state_notif(enic, msg);
548 : 0 : break;
549 : 0 : case ENIC_MBOX_PF_GET_STATS_REQUEST:
550 : 0 : handle_pf_get_stats(enic, msg);
551 : 0 : break;
552 : 0 : case ENIC_MBOX_PF_SET_ADMIN_MAC_NOTIF:
553 : 0 : ENICPMD_LOG(WARNING, "Ignore PF_SET_ADMIN_MAC_NOTIF from PF. The PF driver has changed VF MAC address. Reload the driver to use the new address.");
554 : 0 : break;
555 : 0 : default:
556 [ # # ]: 0 : ENICPMD_LOG(WARNING, "received unexpected non-request message from PF: received=%u(%s)",
557 : : hdr->msg_type, enic_mbox_msg_type_str(hdr->msg_type));
558 : 0 : break;
559 : : }
560 : 0 : }
561 : :
562 : 0 : void enic_poll_vf_admin_chan(struct enic *enic)
563 : : {
564 : : uint8_t msg[ENIC_ADMIN_BUF_SIZE];
565 : : int len;
566 : :
567 : 0 : ENICPMD_FUNC_TRACE();
568 : : lock_admin_chan(enic);
569 [ # # ]: 0 : while (!enic_admin_rq_peek(enic, msg, &len)) {
570 [ # # ]: 0 : if (common_hdr_check(enic, msg))
571 : 0 : continue;
572 : 0 : handle_pf_request_msg(enic, msg);
573 : : }
574 : : unlock_admin_chan(enic);
575 : 0 : }
576 : :
577 : : /*
578 : : * Poll/receive messages until we see the wanted reply message.
579 : : * That is, we wait for the wanted reply.
580 : : */
581 : : #define RECV_REPLY_TIMEOUT 5 /* seconds */
582 : 0 : static int recv_reply(struct enic *enic, void *msg, enum enic_mbox_msg_type type)
583 : : {
584 : : struct enic_mbox_hdr *hdr;
585 : : uint64_t start, end; /* seconds */
586 : : int err, len;
587 : :
588 : 0 : start = rte_rdtsc() / rte_get_tsc_hz();
589 : : again:
590 : 0 : end = rte_rdtsc() / rte_get_tsc_hz();
591 [ # # ]: 0 : if (end - start > RECV_REPLY_TIMEOUT) {
592 : 0 : ENICPMD_LOG(WARNING, "timed out while waiting for reply %u(%s)",
593 : : type, enic_mbox_msg_type_str(type));
594 : 0 : return -ETIMEDOUT;
595 : : }
596 [ # # ]: 0 : if (enic_admin_rq_peek(enic, msg, &len))
597 : 0 : goto again;
598 : 0 : err = common_hdr_check(enic, msg);
599 [ # # ]: 0 : if (err)
600 : 0 : goto out;
601 : :
602 : : /* If not the reply we are looking for, process it and poll again */
603 : : hdr = msg;
604 [ # # ]: 0 : if (hdr->msg_type != type) {
605 : 0 : handle_pf_request_msg(enic, msg);
606 : 0 : goto again;
607 : : }
608 : :
609 : 0 : err = common_reply_check(enic, msg, type);
610 [ # # ]: 0 : if (err)
611 : 0 : goto out;
612 : 0 : out:
613 : : return err;
614 : : }
615 : :
616 : : /*
617 : : * Ask the PF driver its level of the admin channel support. If the
618 : : * answer is ver 0 (minimal) or no channel support (timed-out
619 : : * request), work in the backward compat mode.
620 : : *
621 : : * In the compat mode, trust mode does not work, because the PF driver
622 : : * does not support it. For example, VF cannot enable promisc mode,
623 : : * and cannot change MAC address.
624 : : */
625 : 0 : static int enic_check_chan_capability(struct enic *enic)
626 : : {
627 : : struct enic_mbox_vf_capability_reply_msg *reply;
628 : : struct enic_mbox_vf_capability_msg req;
629 : : uint8_t msg[ENIC_ADMIN_BUF_SIZE];
630 : : int err;
631 : :
632 : 0 : ENICPMD_FUNC_TRACE();
633 : :
634 : 0 : enic_mbox_init_msg_hdr(enic, &req.hdr, ENIC_MBOX_VF_CAPABILITY_REQUEST);
635 : 0 : req.version = ENIC_MBOX_CAP_VERSION_1;
636 : 0 : enic_admin_wq_post(enic, &req);
637 : 0 : ENICPMD_LOG(DEBUG, "sent VF_CAPABILITY");
638 : :
639 : 0 : err = recv_reply(enic, msg, ENIC_MBOX_VF_CAPABILITY_REPLY);
640 [ # # ]: 0 : if (err == -ETIMEDOUT)
641 : 0 : ENICPMD_LOG(WARNING, "PF driver has not responded to CAPABILITY request. Please update the host PF driver");
642 [ # # ]: 0 : else if (err)
643 : 0 : goto out;
644 : 0 : ENICPMD_LOG(DEBUG, "VF_CAPABILITY_REPLY ok");
645 : : reply = (struct enic_mbox_vf_capability_reply_msg *)msg;
646 : 0 : enic->admin_pf_cap_version = reply->version;
647 : 0 : ENICPMD_LOG(DEBUG, "PF admin channel capability version %u",
648 : : enic->admin_pf_cap_version);
649 [ # # # # ]: 0 : if (err == -ETIMEDOUT || enic->admin_pf_cap_version == ENIC_MBOX_CAP_VERSION_0) {
650 : 0 : ENICPMD_LOG(WARNING, "PF driver does not have adequate admin channel support. VF works in backward compatible mode");
651 : : err = 0;
652 : 0 : enic->sriov_vf_compat_mode = true;
653 [ # # ]: 0 : } else if (enic->admin_pf_cap_version == ENIC_MBOX_CAP_VERSION_INVALID) {
654 : 0 : ENICPMD_LOG(WARNING, "Unexpected version in CAPABILITY_REPLY from PF driver. cap_version %u",
655 : : enic->admin_pf_cap_version);
656 : : err = -EINVAL;
657 : : }
658 : 0 : out:
659 : 0 : return err;
660 : : }
661 : :
662 : : /*
663 : : * The VF driver must 'register' with the PF driver first, before
664 : : * sending any devcmd requests. Once registered, the VF driver must be
665 : : * ready to process messages from the PF driver.
666 : : */
667 : 0 : static int enic_register_vf(struct enic *enic)
668 : : {
669 : : struct enic_mbox_vf_register_msg req;
670 : : uint8_t msg[ENIC_ADMIN_BUF_SIZE];
671 : : int err;
672 : :
673 : 0 : ENICPMD_FUNC_TRACE();
674 : 0 : enic_mbox_init_msg_hdr(enic, &req, ENIC_MBOX_VF_REGISTER_REQUEST);
675 : 0 : enic_admin_wq_post(enic, &req);
676 : 0 : ENICPMD_LOG(DEBUG, "sent VF_REGISTER");
677 : 0 : err = recv_reply(enic, msg, ENIC_MBOX_VF_REGISTER_REPLY);
678 [ # # ]: 0 : if (err)
679 : 0 : goto out;
680 : 0 : ENICPMD_LOG(DEBUG, "VF_REGISTER_REPLY ok");
681 : 0 : out:
682 : 0 : return err;
683 : : }
684 : :
685 : : /*
686 : : * The PF driver expects unregister when the VF driver closes. But,
687 : : * it is not mandatory. For example, the VF driver may crash without
688 : : * sending the unregister message. In this case, everything still
689 : : * works fine.
690 : : */
691 : 0 : static void enic_unregister_vf(struct enic *enic)
692 : : {
693 : : struct enic_mbox_vf_unregister_msg req;
694 : : uint8_t msg[ENIC_ADMIN_BUF_SIZE];
695 : :
696 : 0 : ENICPMD_FUNC_TRACE();
697 : 0 : enic_mbox_init_msg_hdr(enic, &req, ENIC_MBOX_VF_UNREGISTER_REQUEST);
698 : 0 : enic_admin_wq_post(enic, &req);
699 : 0 : ENICPMD_LOG(DEBUG, "sent VF_UNREGISTER");
700 [ # # ]: 0 : if (!recv_reply(enic, msg, ENIC_MBOX_VF_UNREGISTER_REPLY))
701 : 0 : ENICPMD_LOG(DEBUG, "VF_UNREGISTER_REPLY ok");
702 : 0 : }
703 : :
704 : 0 : static int vf_set_packet_filter(struct enic *enic, int directed, int multicast,
705 : : int broadcast, int promisc, int allmulti)
706 : : {
707 : : struct enic_mbox_vf_set_pkt_filter_flags_msg req;
708 : : uint8_t msg[ENIC_ADMIN_BUF_SIZE];
709 : : uint16_t flags;
710 : : int err;
711 : :
712 : 0 : ENICPMD_FUNC_TRACE();
713 : 0 : enic_mbox_init_msg_hdr(enic, &req, ENIC_MBOX_VF_SET_PKT_FILTER_FLAGS_REQUEST);
714 : : flags = 0;
715 [ # # ]: 0 : if (directed)
716 : : flags |= ENIC_MBOX_PKT_FILTER_DIRECTED;
717 [ # # ]: 0 : if (multicast)
718 : 0 : flags |= ENIC_MBOX_PKT_FILTER_MULTICAST;
719 [ # # ]: 0 : if (broadcast)
720 : 0 : flags |= ENIC_MBOX_PKT_FILTER_BROADCAST;
721 [ # # ]: 0 : if (promisc)
722 : 0 : flags |= ENIC_MBOX_PKT_FILTER_PROMISC;
723 [ # # ]: 0 : if (allmulti)
724 : 0 : flags |= ENIC_MBOX_PKT_FILTER_ALLMULTI;
725 : 0 : req.flags = flags;
726 : 0 : req.pad = 0;
727 : : /* Lock admin channel while we send and wait for the reply, to prevent
728 : : * enic_poll_vf_admin_chan() (RQ interrupt) from interfering.
729 : : */
730 : : lock_admin_chan(enic);
731 : 0 : enic_admin_wq_post(enic, &req);
732 : 0 : ENICPMD_LOG(DEBUG, "sent VF_SET_PKT_FILTER_FLAGS flags=0x%x", flags);
733 : 0 : err = recv_reply(enic, msg, ENIC_MBOX_VF_SET_PKT_FILTER_FLAGS_REPLY);
734 : : unlock_admin_chan(enic);
735 [ # # ]: 0 : if (err) {
736 : 0 : ENICPMD_LOG(DEBUG, "VF_SET_PKT_FILTER_FLAGS_REPLY failed");
737 : 0 : goto out;
738 : : }
739 : 0 : ENICPMD_LOG(DEBUG, "VF_SET_PKT_FILTER_FLAGS_REPLY ok");
740 : 0 : out:
741 : 0 : return err;
742 : : }
743 : :
744 [ # # ]: 0 : int enic_dev_packet_filter(struct enic *enic, int directed, int multicast,
745 : : int broadcast, int promisc, int allmulti)
746 : : {
747 [ # # ]: 0 : if (enic_is_vf(enic)) {
748 [ # # ]: 0 : RTE_VERIFY(admin_chan_enabled(enic));
749 : 0 : return vf_set_packet_filter(enic, directed, multicast,
750 : : broadcast, promisc, allmulti);
751 : : }
752 : 0 : return vnic_dev_packet_filter(enic->vdev, directed, multicast,
753 : : broadcast, promisc, allmulti);
754 : : }
755 : :
756 : 0 : static int vf_add_del_addr(struct enic *enic, uint8_t *addr, bool delete)
757 : : {
758 : : struct enic_mbox_vf_add_del_mac_msg req;
759 : : uint8_t msg[ENIC_ADMIN_BUF_SIZE];
760 : : int err;
761 : :
762 : 0 : ENICPMD_FUNC_TRACE();
763 : 0 : enic_mbox_init_msg_hdr(enic, &req, ENIC_MBOX_VF_ADD_DEL_MAC_REQUEST);
764 : :
765 : 0 : req.num_addrs = 1;
766 : : memcpy(req.mac_addr.addr, addr, RTE_ETHER_ADDR_LEN);
767 : 0 : req.mac_addr.flags = delete ? 0 : MAC_ADDR_FLAG_ADD;
768 : :
769 : : lock_admin_chan(enic);
770 : 0 : enic_admin_wq_post(enic, &req);
771 : 0 : ENICPMD_LOG(DEBUG, "sent VF_ADD_DEL_MAC");
772 : 0 : err = recv_reply(enic, msg, ENIC_MBOX_VF_ADD_DEL_MAC_REPLY);
773 : : unlock_admin_chan(enic);
774 [ # # ]: 0 : if (err) {
775 : 0 : ENICPMD_LOG(DEBUG, "VF_ADD_DEL_MAC_REPLY failed");
776 : 0 : goto out;
777 : : }
778 : 0 : ENICPMD_LOG(DEBUG, "VF_ADD_DEL_MAC_REPLY ok");
779 : 0 : out:
780 : 0 : return err;
781 : : }
782 : :
783 : 0 : int enic_dev_add_addr(struct enic *enic, uint8_t *addr)
784 : : {
785 : 0 : ENICPMD_FUNC_TRACE();
786 [ # # ]: 0 : if (enic_is_vf(enic)) {
787 [ # # ]: 0 : RTE_VERIFY(admin_chan_enabled(enic));
788 : 0 : return vf_add_del_addr(enic, addr, false);
789 : : }
790 : 0 : return vnic_dev_add_addr(enic->vdev, addr);
791 : : }
792 : :
793 : 0 : int enic_dev_del_addr(struct enic *enic, uint8_t *addr)
794 : : {
795 : 0 : ENICPMD_FUNC_TRACE();
796 [ # # ]: 0 : if (enic_is_vf(enic)) {
797 [ # # ]: 0 : RTE_VERIFY(admin_chan_enabled(enic));
798 : 0 : return vf_add_del_addr(enic, addr, true);
799 : : }
800 : 0 : return vnic_dev_del_addr(enic->vdev, addr);
801 : : }
|