]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/dpdk/drivers/net/netvsc/hn_nvs.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / dpdk / drivers / net / netvsc / hn_nvs.c
CommitLineData
11fdf7f2
TL
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2018 Microsoft Corp.
3 * Copyright (c) 2010-2012 Citrix Inc.
4 * Copyright (c) 2012 NetApp Inc.
5 * All rights reserved.
6 */
7
8/*
9 * Network Virtualization Service.
10 */
11
12
13#include <stdint.h>
14#include <string.h>
15#include <stdio.h>
16#include <errno.h>
17#include <unistd.h>
18
19#include <rte_ethdev.h>
20#include <rte_string_fns.h>
21#include <rte_memzone.h>
22#include <rte_malloc.h>
23#include <rte_atomic.h>
24#include <rte_branch_prediction.h>
25#include <rte_ether.h>
26#include <rte_common.h>
27#include <rte_errno.h>
28#include <rte_cycles.h>
29#include <rte_memory.h>
30#include <rte_eal.h>
31#include <rte_dev.h>
32#include <rte_bus_vmbus.h>
33
34#include "hn_logs.h"
35#include "hn_var.h"
36#include "hn_nvs.h"
37
38static const uint32_t hn_nvs_version[] = {
39 NVS_VERSION_61,
40 NVS_VERSION_6,
41 NVS_VERSION_5,
42 NVS_VERSION_4,
43 NVS_VERSION_2,
44 NVS_VERSION_1
45};
46
47static int hn_nvs_req_send(struct hn_data *hv,
48 void *req, uint32_t reqlen)
49{
50 return rte_vmbus_chan_send(hn_primary_chan(hv),
51 VMBUS_CHANPKT_TYPE_INBAND,
52 req, reqlen, 0,
53 VMBUS_CHANPKT_FLAG_NONE, NULL);
54}
55
56static int
f67539c2 57__hn_nvs_execute(struct hn_data *hv,
11fdf7f2
TL
58 void *req, uint32_t reqlen,
59 void *resp, uint32_t resplen,
60 uint32_t type)
61{
62 struct vmbus_channel *chan = hn_primary_chan(hv);
63 char buffer[NVS_RESPSIZE_MAX];
64 const struct hn_nvs_hdr *hdr;
f67539c2 65 uint64_t xactid;
11fdf7f2
TL
66 uint32_t len;
67 int ret;
68
69 /* Send request to ring buffer */
70 ret = rte_vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND,
71 req, reqlen, 0,
72 VMBUS_CHANPKT_FLAG_RC, NULL);
73
74 if (ret) {
75 PMD_DRV_LOG(ERR, "send request failed: %d", ret);
76 return ret;
77 }
78
79 retry:
80 len = sizeof(buffer);
f67539c2 81 ret = rte_vmbus_chan_recv(chan, buffer, &len, &xactid);
11fdf7f2
TL
82 if (ret == -EAGAIN) {
83 rte_delay_us(HN_CHAN_INTERVAL_US);
84 goto retry;
85 }
86
87 if (ret < 0) {
88 PMD_DRV_LOG(ERR, "recv response failed: %d", ret);
89 return ret;
90 }
91
f67539c2
TL
92 if (len < sizeof(*hdr)) {
93 PMD_DRV_LOG(ERR, "response missing NVS header");
94 return -EINVAL;
95 }
96
11fdf7f2 97 hdr = (struct hn_nvs_hdr *)buffer;
f67539c2
TL
98
99 /* Silently drop received packets while waiting for response */
100 if (hdr->type == NVS_TYPE_RNDIS) {
101 hn_nvs_ack_rxbuf(chan, xactid);
102 --hv->rxbuf_outstanding;
103 goto retry;
104 }
105
11fdf7f2
TL
106 if (hdr->type != type) {
107 PMD_DRV_LOG(ERR, "unexpected NVS resp %#x, expect %#x",
108 hdr->type, type);
109 return -EINVAL;
110 }
111
112 if (len < resplen) {
113 PMD_DRV_LOG(ERR,
114 "invalid NVS resp len %u (expect %u)",
115 len, resplen);
116 return -EINVAL;
117 }
118
119 memcpy(resp, buffer, resplen);
120
121 /* All pass! */
122 return 0;
123}
124
f67539c2
TL
125
126/*
127 * Execute one control command and get the response.
128 * Only one command can be active on a channel at once
129 * Unlike BSD, DPDK does not have an interrupt context
130 * so the polling is required to wait for response.
131 */
132static int
133hn_nvs_execute(struct hn_data *hv,
134 void *req, uint32_t reqlen,
135 void *resp, uint32_t resplen,
136 uint32_t type)
137{
138 struct hn_rx_queue *rxq = hv->primary;
139 int ret;
140
141 rte_spinlock_lock(&rxq->ring_lock);
142 ret = __hn_nvs_execute(hv, req, reqlen, resp, resplen, type);
143 rte_spinlock_unlock(&rxq->ring_lock);
144
145 return ret;
146}
147
11fdf7f2
TL
148static int
149hn_nvs_doinit(struct hn_data *hv, uint32_t nvs_ver)
150{
151 struct hn_nvs_init init;
152 struct hn_nvs_init_resp resp;
153 uint32_t status;
154 int error;
155
156 memset(&init, 0, sizeof(init));
157 init.type = NVS_TYPE_INIT;
158 init.ver_min = nvs_ver;
159 init.ver_max = nvs_ver;
160
161 error = hn_nvs_execute(hv, &init, sizeof(init),
162 &resp, sizeof(resp),
163 NVS_TYPE_INIT_RESP);
164 if (error)
165 return error;
166
167 status = resp.status;
168 if (status != NVS_STATUS_OK) {
169 /* Not fatal, try other versions */
170 PMD_INIT_LOG(DEBUG, "nvs init failed for ver 0x%x",
171 nvs_ver);
172 return -EINVAL;
173 }
174
175 return 0;
176}
177
178static int
179hn_nvs_conn_rxbuf(struct hn_data *hv)
180{
181 struct hn_nvs_rxbuf_conn conn;
182 struct hn_nvs_rxbuf_connresp resp;
183 uint32_t status;
184 int error;
185
186 /* Kernel has already setup RXBUF on primary channel. */
187
188 /*
189 * Connect RXBUF to NVS.
190 */
191 conn.type = NVS_TYPE_RXBUF_CONN;
192 conn.gpadl = hv->rxbuf_res->phys_addr;
193 conn.sig = NVS_RXBUF_SIG;
194 PMD_DRV_LOG(DEBUG, "connect rxbuff va=%p gpad=%#" PRIx64,
195 hv->rxbuf_res->addr,
196 hv->rxbuf_res->phys_addr);
197
198 error = hn_nvs_execute(hv, &conn, sizeof(conn),
199 &resp, sizeof(resp),
200 NVS_TYPE_RXBUF_CONNRESP);
201 if (error) {
202 PMD_DRV_LOG(ERR,
203 "exec nvs rxbuf conn failed: %d",
204 error);
205 return error;
206 }
207
208 status = resp.status;
209 if (status != NVS_STATUS_OK) {
210 PMD_DRV_LOG(ERR,
211 "nvs rxbuf conn failed: %x", status);
212 return -EIO;
213 }
214 if (resp.nsect != 1) {
215 PMD_DRV_LOG(ERR,
216 "nvs rxbuf response num sections %u != 1",
217 resp.nsect);
218 return -EIO;
219 }
220
221 PMD_DRV_LOG(INFO,
222 "receive buffer size %u count %u",
223 resp.nvs_sect[0].slotsz,
224 resp.nvs_sect[0].slotcnt);
225 hv->rxbuf_section_cnt = resp.nvs_sect[0].slotcnt;
226
227 hv->rxbuf_info = rte_calloc("HN_RXBUF_INFO", hv->rxbuf_section_cnt,
228 sizeof(*hv->rxbuf_info), RTE_CACHE_LINE_SIZE);
229 if (!hv->rxbuf_info) {
230 PMD_DRV_LOG(ERR,
231 "could not allocate rxbuf info");
232 return -ENOMEM;
233 }
234
235 return 0;
236}
237
238static void
239hn_nvs_disconn_rxbuf(struct hn_data *hv)
240{
241 struct hn_nvs_rxbuf_disconn disconn;
242 int error;
243
244 /*
245 * Disconnect RXBUF from NVS.
246 */
247 memset(&disconn, 0, sizeof(disconn));
248 disconn.type = NVS_TYPE_RXBUF_DISCONN;
249 disconn.sig = NVS_RXBUF_SIG;
250
251 /* NOTE: No response. */
252 error = hn_nvs_req_send(hv, &disconn, sizeof(disconn));
253 if (error) {
254 PMD_DRV_LOG(ERR,
255 "send nvs rxbuf disconn failed: %d",
256 error);
257 }
258
259 rte_free(hv->rxbuf_info);
260 /*
261 * Linger long enough for NVS to disconnect RXBUF.
262 */
263 rte_delay_ms(200);
264}
265
266static void
267hn_nvs_disconn_chim(struct hn_data *hv)
268{
269 int error;
270
271 if (hv->chim_cnt != 0) {
272 struct hn_nvs_chim_disconn disconn;
273
274 /* Disconnect chimney sending buffer from NVS. */
275 memset(&disconn, 0, sizeof(disconn));
276 disconn.type = NVS_TYPE_CHIM_DISCONN;
277 disconn.sig = NVS_CHIM_SIG;
278
279 /* NOTE: No response. */
280 error = hn_nvs_req_send(hv, &disconn, sizeof(disconn));
281
282 if (error) {
283 PMD_DRV_LOG(ERR,
284 "send nvs chim disconn failed: %d", error);
285 }
286
287 hv->chim_cnt = 0;
288 /*
289 * Linger long enough for NVS to disconnect chimney
290 * sending buffer.
291 */
292 rte_delay_ms(200);
293 }
294}
295
296static int
297hn_nvs_conn_chim(struct hn_data *hv)
298{
299 struct hn_nvs_chim_conn chim;
300 struct hn_nvs_chim_connresp resp;
301 uint32_t sectsz;
302 unsigned long len = hv->chim_res->len;
303 int error;
304
305 /* Connect chimney sending buffer to NVS */
306 memset(&chim, 0, sizeof(chim));
307 chim.type = NVS_TYPE_CHIM_CONN;
308 chim.gpadl = hv->chim_res->phys_addr;
309 chim.sig = NVS_CHIM_SIG;
310 PMD_DRV_LOG(DEBUG, "connect send buf va=%p gpad=%#" PRIx64,
311 hv->chim_res->addr,
312 hv->chim_res->phys_addr);
313
314 error = hn_nvs_execute(hv, &chim, sizeof(chim),
315 &resp, sizeof(resp),
316 NVS_TYPE_CHIM_CONNRESP);
317 if (error) {
318 PMD_DRV_LOG(ERR, "exec nvs chim conn failed");
9f95a23c 319 return error;
11fdf7f2
TL
320 }
321
322 if (resp.status != NVS_STATUS_OK) {
323 PMD_DRV_LOG(ERR, "nvs chim conn failed: %x",
324 resp.status);
9f95a23c 325 return -EIO;
11fdf7f2
TL
326 }
327
328 sectsz = resp.sectsz;
329 if (sectsz == 0 || sectsz & (sizeof(uint32_t) - 1)) {
330 /* Can't use chimney sending buffer; done! */
331 PMD_DRV_LOG(NOTICE,
332 "invalid chimney sending buffer section size: %u",
333 sectsz);
9f95a23c
TL
334 error = -EINVAL;
335 goto cleanup;
11fdf7f2
TL
336 }
337
338 hv->chim_szmax = sectsz;
339 hv->chim_cnt = len / sectsz;
340
341 PMD_DRV_LOG(INFO, "send buffer %lu section size:%u, count:%u",
342 len, hv->chim_szmax, hv->chim_cnt);
343
11fdf7f2
TL
344 /* Done! */
345 return 0;
346
347cleanup:
348 hn_nvs_disconn_chim(hv);
349 return error;
350}
351
352/*
353 * Configure MTU and enable VLAN.
354 */
355static int
356hn_nvs_conf_ndis(struct hn_data *hv, unsigned int mtu)
357{
358 struct hn_nvs_ndis_conf conf;
359 int error;
360
361 memset(&conf, 0, sizeof(conf));
362 conf.type = NVS_TYPE_NDIS_CONF;
f67539c2 363 conf.mtu = mtu + RTE_ETHER_HDR_LEN;
11fdf7f2
TL
364 conf.caps = NVS_NDIS_CONF_VLAN;
365
9f95a23c
TL
366 /* enable SRIOV */
367 if (hv->nvs_ver >= NVS_VERSION_5)
368 conf.caps |= NVS_NDIS_CONF_SRIOV;
11fdf7f2
TL
369
370 /* NOTE: No response. */
371 error = hn_nvs_req_send(hv, &conf, sizeof(conf));
372 if (error) {
373 PMD_DRV_LOG(ERR,
374 "send nvs ndis conf failed: %d", error);
375 return error;
376 }
377
378 return 0;
379}
380
381static int
382hn_nvs_init_ndis(struct hn_data *hv)
383{
384 struct hn_nvs_ndis_init ndis;
385 int error;
386
387 memset(&ndis, 0, sizeof(ndis));
388 ndis.type = NVS_TYPE_NDIS_INIT;
389 ndis.ndis_major = NDIS_VERSION_MAJOR(hv->ndis_ver);
390 ndis.ndis_minor = NDIS_VERSION_MINOR(hv->ndis_ver);
391
392 /* NOTE: No response. */
393 error = hn_nvs_req_send(hv, &ndis, sizeof(ndis));
394 if (error)
395 PMD_DRV_LOG(ERR,
396 "send nvs ndis init failed: %d", error);
397
398 return error;
399}
400
401static int
402hn_nvs_init(struct hn_data *hv)
403{
404 unsigned int i;
405 int error;
406
407 /*
408 * Find the supported NVS version and set NDIS version accordingly.
409 */
410 for (i = 0; i < RTE_DIM(hn_nvs_version); ++i) {
411 error = hn_nvs_doinit(hv, hn_nvs_version[i]);
412 if (error) {
413 PMD_INIT_LOG(DEBUG, "version %#x error %d",
414 hn_nvs_version[i], error);
415 continue;
416 }
417
418 hv->nvs_ver = hn_nvs_version[i];
419
420 /* Set NDIS version according to NVS version. */
421 hv->ndis_ver = NDIS_VERSION_6_30;
422 if (hv->nvs_ver <= NVS_VERSION_4)
423 hv->ndis_ver = NDIS_VERSION_6_1;
424
425 PMD_INIT_LOG(DEBUG,
426 "NVS version %#x, NDIS version %u.%u",
427 hv->nvs_ver, NDIS_VERSION_MAJOR(hv->ndis_ver),
428 NDIS_VERSION_MINOR(hv->ndis_ver));
429 return 0;
430 }
431
432 PMD_DRV_LOG(ERR,
433 "no NVS compatible version available");
434 return -ENXIO;
435}
436
437int
438hn_nvs_attach(struct hn_data *hv, unsigned int mtu)
439{
440 int error;
441
442 /*
443 * Initialize NVS.
444 */
445 error = hn_nvs_init(hv);
446 if (error)
447 return error;
448
449 /** Configure NDIS before initializing it. */
450 if (hv->nvs_ver >= NVS_VERSION_2) {
451 error = hn_nvs_conf_ndis(hv, mtu);
452 if (error)
453 return error;
454 }
455
456 /*
457 * Initialize NDIS.
458 */
459 error = hn_nvs_init_ndis(hv);
460 if (error)
461 return error;
462
463 /*
464 * Connect RXBUF.
465 */
466 error = hn_nvs_conn_rxbuf(hv);
467 if (error)
468 return error;
469
470 /*
471 * Connect chimney sending buffer.
472 */
473 error = hn_nvs_conn_chim(hv);
474 if (error) {
475 hn_nvs_disconn_rxbuf(hv);
476 return error;
477 }
478
479 return 0;
480}
481
482void
483hn_nvs_detach(struct hn_data *hv __rte_unused)
484{
485 PMD_INIT_FUNC_TRACE();
486
487 /* NOTE: there are no requests to stop the NVS. */
488 hn_nvs_disconn_rxbuf(hv);
489 hn_nvs_disconn_chim(hv);
490}
491
492/*
493 * Ack the consumed RXBUF associated w/ this channel packet,
494 * so that this RXBUF can be recycled by the hypervisor.
495 */
496void
497hn_nvs_ack_rxbuf(struct vmbus_channel *chan, uint64_t tid)
498{
499 unsigned int retries = 0;
500 struct hn_nvs_rndis_ack ack = {
501 .type = NVS_TYPE_RNDIS_ACK,
502 .status = NVS_STATUS_OK,
503 };
504 int error;
505
506 PMD_RX_LOG(DEBUG, "ack RX id %" PRIu64, tid);
507
508 again:
509 error = rte_vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
510 &ack, sizeof(ack), tid,
511 VMBUS_CHANPKT_FLAG_NONE, NULL);
512
513 if (error == 0)
514 return;
515
516 if (error == -EAGAIN) {
517 /*
518 * NOTE:
519 * This should _not_ happen in real world, since the
520 * consumption of the TX bufring from the TX path is
521 * controlled.
522 */
523 PMD_RX_LOG(NOTICE, "RXBUF ack retry");
524 if (++retries < 10) {
525 rte_delay_ms(1);
526 goto again;
527 }
528 }
529 /* RXBUF leaks! */
530 PMD_DRV_LOG(ERR, "RXBUF ack failed");
531}
532
533int
534hn_nvs_alloc_subchans(struct hn_data *hv, uint32_t *nsubch)
535{
536 struct hn_nvs_subch_req req;
537 struct hn_nvs_subch_resp resp;
538 int error;
539
540 memset(&req, 0, sizeof(req));
541 req.type = NVS_TYPE_SUBCH_REQ;
542 req.op = NVS_SUBCH_OP_ALLOC;
543 req.nsubch = *nsubch;
544
545 error = hn_nvs_execute(hv, &req, sizeof(req),
546 &resp, sizeof(resp),
547 NVS_TYPE_SUBCH_RESP);
548 if (error)
549 return error;
550
551 if (resp.status != NVS_STATUS_OK) {
552 PMD_INIT_LOG(ERR,
553 "nvs subch alloc failed: %#x",
554 resp.status);
555 return -EIO;
556 }
557
558 if (resp.nsubch > *nsubch) {
559 PMD_INIT_LOG(NOTICE,
560 "%u subchans are allocated, requested %u",
561 resp.nsubch, *nsubch);
562 }
563 *nsubch = resp.nsubch;
564
565 return 0;
566}
567
568void
569hn_nvs_set_datapath(struct hn_data *hv, uint32_t path)
570{
571 struct hn_nvs_datapath dp;
9f95a23c
TL
572 int error;
573
574 PMD_DRV_LOG(DEBUG, "set datapath %s",
575 path ? "VF" : "Synthetic");
11fdf7f2
TL
576
577 memset(&dp, 0, sizeof(dp));
578 dp.type = NVS_TYPE_SET_DATAPATH;
579 dp.active_path = path;
580
9f95a23c
TL
581 error = hn_nvs_req_send(hv, &dp, sizeof(dp));
582 if (error) {
583 PMD_DRV_LOG(ERR,
584 "send set datapath failed: %d",
585 error);
586 }
11fdf7f2 587}