Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2009-2018 Microsoft Corp.
3 : : * Copyright (c) 2010-2012 Citrix Inc.
4 : : * Copyright (c) 2012 NetApp Inc.
5 : : * All rights reserved.
6 : : */
7 : :
8 : : #include <stdint.h>
9 : : #include <string.h>
10 : : #include <stdio.h>
11 : : #include <errno.h>
12 : : #include <unistd.h>
13 : : #include <time.h>
14 : :
15 : : #include <ethdev_driver.h>
16 : : #include <rte_ethdev.h>
17 : : #include <rte_string_fns.h>
18 : : #include <rte_memzone.h>
19 : : #include <rte_malloc.h>
20 : : #include <rte_atomic.h>
21 : : #include <rte_alarm.h>
22 : : #include <rte_branch_prediction.h>
23 : : #include <rte_ether.h>
24 : : #include <rte_common.h>
25 : : #include <rte_errno.h>
26 : : #include <rte_cycles.h>
27 : : #include <rte_memory.h>
28 : : #include <rte_eal.h>
29 : : #include <dev_driver.h>
30 : : #include <bus_vmbus_driver.h>
31 : :
32 : : #include "hn_logs.h"
33 : : #include "hn_var.h"
34 : : #include "hn_nvs.h"
35 : : #include "hn_rndis.h"
36 : : #include "ndis.h"
37 : :
38 : : #define RNDIS_TIMEOUT_SEC 60
39 : : #define RNDIS_DELAY_MS 10
40 : :
41 : : #define HN_RNDIS_XFER_SIZE 0x4000
42 : :
43 : : #define HN_NDIS_TXCSUM_CAP_IP4 \
44 : : (NDIS_TXCSUM_CAP_IP4 | NDIS_TXCSUM_CAP_IP4OPT)
45 : : #define HN_NDIS_TXCSUM_CAP_TCP4 \
46 : : (NDIS_TXCSUM_CAP_TCP4 | NDIS_TXCSUM_CAP_TCP4OPT)
47 : : #define HN_NDIS_TXCSUM_CAP_TCP6 \
48 : : (NDIS_TXCSUM_CAP_TCP6 | NDIS_TXCSUM_CAP_TCP6OPT | \
49 : : NDIS_TXCSUM_CAP_IP6EXT)
50 : : #define HN_NDIS_TXCSUM_CAP_UDP6 \
51 : : (NDIS_TXCSUM_CAP_UDP6 | NDIS_TXCSUM_CAP_IP6EXT)
52 : : #define HN_NDIS_LSOV2_CAP_IP6 \
53 : : (NDIS_LSOV2_CAP_IP6EXT | NDIS_LSOV2_CAP_TCP6OPT)
54 : :
55 : : /* Get unique request id */
56 : : static inline uint32_t
57 : : hn_rndis_rid(struct hn_data *hv)
58 : : {
59 : : uint32_t rid;
60 : :
61 : : do {
62 : 0 : rid = rte_atomic32_add_return(&hv->rndis_req_id, 1);
63 [ # # # # : 0 : } while (rid == 0);
# # # # ]
64 : :
65 : : return rid;
66 : : }
67 : :
68 : : static void *hn_rndis_alloc(size_t size)
69 : : {
70 : 0 : return rte_zmalloc("RNDIS", size, HYPERV_PAGE_SIZE);
71 : : }
72 : :
73 : : #ifdef RTE_LIBRTE_NETVSC_DEBUG_DUMP
74 : : void hn_rndis_dump(const void *buf)
75 : : {
76 : : const union {
77 : : struct rndis_msghdr hdr;
78 : : struct rndis_packet_msg pkt;
79 : : struct rndis_init_req init_request;
80 : : struct rndis_init_comp init_complete;
81 : : struct rndis_halt_req halt;
82 : : struct rndis_query_req query_request;
83 : : struct rndis_query_comp query_complete;
84 : : struct rndis_set_req set_request;
85 : : struct rndis_set_comp set_complete;
86 : : struct rndis_reset_req reset_request;
87 : : struct rndis_reset_comp reset_complete;
88 : : struct rndis_keepalive_req keepalive_request;
89 : : struct rndis_keepalive_comp keepalive_complete;
90 : : struct rndis_status_msg indicate_status;
91 : : } *rndis_msg = buf;
92 : :
93 : : switch (rndis_msg->hdr.type) {
94 : : case RNDIS_PACKET_MSG: {
95 : : const struct rndis_pktinfo *ppi;
96 : : unsigned int ppi_len;
97 : :
98 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
99 : : "RNDIS_MSG_PACKET (len %u, data %u:%u, # oob %u %u:%u, pkt %u:%u)",
100 : : rndis_msg->pkt.len,
101 : : rndis_msg->pkt.dataoffset,
102 : : rndis_msg->pkt.datalen,
103 : : rndis_msg->pkt.oobdataelements,
104 : : rndis_msg->pkt.oobdataoffset,
105 : : rndis_msg->pkt.oobdatalen,
106 : : rndis_msg->pkt.pktinfooffset,
107 : : rndis_msg->pkt.pktinfolen);
108 : :
109 : : ppi = (const struct rndis_pktinfo *)
110 : : ((const char *)buf
111 : : + RNDIS_PACKET_MSG_OFFSET_ABS(rndis_msg->pkt.pktinfooffset));
112 : :
113 : : ppi_len = rndis_msg->pkt.pktinfolen;
114 : : while (ppi_len > 0) {
115 : : const void *ppi_data;
116 : :
117 : : ppi_data = ppi->data;
118 : :
119 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
120 : : " PPI (size %u, type %u, offs %u data %#x)",
121 : : ppi->size, ppi->type, ppi->offset,
122 : : *(const uint32_t *)ppi_data);
123 : : if (ppi->size == 0)
124 : : break;
125 : : ppi_len -= ppi->size;
126 : : ppi = (const struct rndis_pktinfo *)
127 : : ((const char *)ppi + ppi->size);
128 : : }
129 : : break;
130 : : }
131 : : case RNDIS_INITIALIZE_MSG:
132 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
133 : : "RNDIS_MSG_INIT (len %u id %#x, ver %u.%u max xfer %u)",
134 : : rndis_msg->init_request.len,
135 : : rndis_msg->init_request.rid,
136 : : rndis_msg->init_request.ver_major,
137 : : rndis_msg->init_request.ver_minor,
138 : : rndis_msg->init_request.max_xfersz);
139 : : break;
140 : :
141 : : case RNDIS_INITIALIZE_CMPLT:
142 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
143 : : "RNDIS_MSG_INIT_C (len %u, id %#x, status 0x%x, vers %u.%u, "
144 : : "flags %d, max xfer %u, max pkts %u, aligned %u)",
145 : : rndis_msg->init_complete.len,
146 : : rndis_msg->init_complete.rid,
147 : : rndis_msg->init_complete.status,
148 : : rndis_msg->init_complete.ver_major,
149 : : rndis_msg->init_complete.ver_minor,
150 : : rndis_msg->init_complete.devflags,
151 : : rndis_msg->init_complete.pktmaxsz,
152 : : rndis_msg->init_complete.pktmaxcnt,
153 : : rndis_msg->init_complete.align);
154 : : break;
155 : :
156 : : case RNDIS_HALT_MSG:
157 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
158 : : "RNDIS_HALT (len %u id %#x)",
159 : : rndis_msg->halt.len, rndis_msg->halt.rid);
160 : : break;
161 : :
162 : : case RNDIS_QUERY_MSG:
163 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
164 : : "RNDIS_QUERY (len %u, id %#x, oid %#x, info %u:%u)",
165 : : rndis_msg->query_request.len,
166 : : rndis_msg->query_request.rid,
167 : : rndis_msg->query_request.oid,
168 : : rndis_msg->query_request.infobuflen,
169 : : rndis_msg->query_request.infobufoffset);
170 : : break;
171 : :
172 : : case RNDIS_QUERY_CMPLT:
173 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
174 : : "RNDIS_MSG_QUERY_C (len %u, id %#x, status 0x%x, buf %u:%u)",
175 : : rndis_msg->query_complete.len,
176 : : rndis_msg->query_complete.rid,
177 : : rndis_msg->query_complete.status,
178 : : rndis_msg->query_complete.infobuflen,
179 : : rndis_msg->query_complete.infobufoffset);
180 : : break;
181 : :
182 : : case RNDIS_SET_MSG:
183 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
184 : : "RNDIS_SET (len %u, id %#x, oid %#x, info %u:%u)",
185 : : rndis_msg->set_request.len,
186 : : rndis_msg->set_request.rid,
187 : : rndis_msg->set_request.oid,
188 : : rndis_msg->set_request.infobuflen,
189 : : rndis_msg->set_request.infobufoffset);
190 : : break;
191 : :
192 : : case RNDIS_SET_CMPLT:
193 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
194 : : "RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)",
195 : : rndis_msg->set_complete.len,
196 : : rndis_msg->set_complete.rid,
197 : : rndis_msg->set_complete.status);
198 : : break;
199 : :
200 : : case RNDIS_INDICATE_STATUS_MSG:
201 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
202 : : "RNDIS_MSG_INDICATE (len %u, status %#x, buf len %u, buf offset %u)",
203 : : rndis_msg->indicate_status.len,
204 : : rndis_msg->indicate_status.status,
205 : : rndis_msg->indicate_status.stbuflen,
206 : : rndis_msg->indicate_status.stbufoffset);
207 : : break;
208 : :
209 : : case RNDIS_RESET_MSG:
210 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
211 : : "RNDIS_RESET (len %u, id %#x)",
212 : : rndis_msg->reset_request.len,
213 : : rndis_msg->reset_request.rid);
214 : : break;
215 : :
216 : : case RNDIS_RESET_CMPLT:
217 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
218 : : "RNDIS_RESET_C (len %u, status %#x address %#x)",
219 : : rndis_msg->reset_complete.len,
220 : : rndis_msg->reset_complete.status,
221 : : rndis_msg->reset_complete.adrreset);
222 : : break;
223 : :
224 : : case RNDIS_KEEPALIVE_MSG:
225 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
226 : : "RNDIS_KEEPALIVE (len %u, id %#x)",
227 : : rndis_msg->keepalive_request.len,
228 : : rndis_msg->keepalive_request.rid);
229 : : break;
230 : :
231 : : case RNDIS_KEEPALIVE_CMPLT:
232 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
233 : : "RNDIS_KEEPALIVE_C (len %u, id %#x address %#x)",
234 : : rndis_msg->keepalive_complete.len,
235 : : rndis_msg->keepalive_complete.rid,
236 : : rndis_msg->keepalive_complete.status);
237 : : break;
238 : :
239 : : default:
240 : : RTE_LOG_LINE(DEBUG, HN_DRIVER,
241 : : "RNDIS type %#x len %u",
242 : : rndis_msg->hdr.type,
243 : : rndis_msg->hdr.len);
244 : : break;
245 : : }
246 : : }
247 : : #endif
248 : :
249 : 0 : static int hn_nvs_send_rndis_ctrl(struct hn_data *hv,
250 : : struct vmbus_channel *chan, const void *req,
251 : : uint32_t reqlen)
252 : :
253 : : {
254 : 0 : struct hn_nvs_rndis nvs_rndis = {
255 : : .type = NVS_TYPE_RNDIS,
256 : : .rndis_mtype = NVS_RNDIS_MTYPE_CTRL,
257 : : .chim_idx = NVS_CHIM_IDX_INVALID,
258 : : .chim_sz = 0
259 : : };
260 : : struct vmbus_gpa sg;
261 : : rte_iova_t addr;
262 : :
263 : 0 : addr = rte_malloc_virt2iova(req);
264 [ # # ]: 0 : if (unlikely(addr == RTE_BAD_IOVA)) {
265 : 0 : PMD_DRV_LOG(ERR, "RNDIS send request can not get iova");
266 : 0 : return -EINVAL;
267 : : }
268 : :
269 [ # # ]: 0 : if (unlikely(reqlen > HYPERV_PAGE_SIZE)) {
270 : 0 : PMD_DRV_LOG(ERR, "RNDIS request %u greater than page size",
271 : : reqlen);
272 : 0 : return -EINVAL;
273 : : }
274 : :
275 : 0 : sg.page = addr / HYPERV_PAGE_SIZE;
276 : 0 : sg.ofs = addr & HYPERV_PAGE_MASK;
277 : 0 : sg.len = reqlen;
278 : :
279 [ # # ]: 0 : if (sg.ofs + reqlen > HYPERV_PAGE_SIZE) {
280 : 0 : PMD_DRV_LOG(ERR, "RNDIS request crosses page boundary");
281 : 0 : return -EINVAL;
282 : : }
283 : :
284 : : hn_rndis_dump(req);
285 : :
286 : 0 : return hn_nvs_send_sglist(hv, chan, &sg, 1, &nvs_rndis,
287 : : sizeof(nvs_rndis), 0U, NULL);
288 : : }
289 : :
290 : : /*
291 : : * Alarm callback to process link changed notifications.
292 : : * Can not directly since link_status is discovered while reading ring
293 : : */
294 : 0 : static void hn_rndis_link_alarm(void *arg)
295 : : {
296 : 0 : rte_eth_dev_callback_process(arg, RTE_ETH_EVENT_INTR_LSC, NULL);
297 : 0 : }
298 : :
299 : 0 : void hn_rndis_link_status(struct rte_eth_dev *dev, const void *msg)
300 : : {
301 : : const struct rndis_status_msg *indicate = msg;
302 : :
303 : : hn_rndis_dump(msg);
304 : :
305 : 0 : PMD_DRV_LOG(DEBUG, "link status %#x", indicate->status);
306 : :
307 [ # # # ]: 0 : switch (indicate->status) {
308 : : case RNDIS_STATUS_NETWORK_CHANGE:
309 : : case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
310 : : /* ignore not in DPDK API */
311 : : break;
312 : :
313 : 0 : case RNDIS_STATUS_LINK_SPEED_CHANGE:
314 : : case RNDIS_STATUS_MEDIA_CONNECT:
315 : : case RNDIS_STATUS_MEDIA_DISCONNECT:
316 [ # # ]: 0 : if (dev->data->dev_conf.intr_conf.lsc)
317 : 0 : rte_eal_alarm_set(10, hn_rndis_link_alarm, dev);
318 : : break;
319 : 0 : default:
320 : 0 : PMD_DRV_LOG(NOTICE, "unknown RNDIS indication: %#x",
321 : : indicate->status);
322 : : }
323 : 0 : }
324 : :
325 : : /* Callback from hn_process_events when response is visible */
326 : 0 : void hn_rndis_receive_response(struct hn_data *hv,
327 : : const void *data, uint32_t len)
328 : : {
329 : : const struct rndis_init_comp *hdr = data;
330 : :
331 : : hn_rndis_dump(data);
332 : :
333 : : /* Check we can read first three data fields from RNDIS header */
334 [ # # ]: 0 : if (len < 3 * sizeof(uint32_t)) {
335 : 0 : PMD_DRV_LOG(ERR,
336 : : "missing RNDIS header %u", len);
337 : 0 : return;
338 : : }
339 : :
340 [ # # ]: 0 : if (len < hdr->len) {
341 : 0 : PMD_DRV_LOG(ERR,
342 : : "truncated RNDIS response %u", len);
343 : 0 : return;
344 : : }
345 : :
346 [ # # ]: 0 : if (len > sizeof(hv->rndis_resp)) {
347 : 0 : PMD_DRV_LOG(NOTICE,
348 : : "RNDIS response exceeds buffer");
349 : : len = sizeof(hv->rndis_resp);
350 : : }
351 : :
352 [ # # ]: 0 : if (hdr->rid == 0) {
353 : 0 : PMD_DRV_LOG(NOTICE,
354 : : "RNDIS response id zero!");
355 : : }
356 : :
357 : 0 : memcpy(hv->rndis_resp, data, len);
358 : :
359 : : /* make sure response copied before update */
360 : 0 : rte_smp_wmb();
361 : :
362 [ # # ]: 0 : if (rte_atomic32_cmpset(&hv->rndis_pending, hdr->rid, 0) == 0) {
363 : 0 : PMD_DRV_LOG(NOTICE,
364 : : "received id %#x pending id %#x",
365 : : hdr->rid, (uint32_t)hv->rndis_pending);
366 : : }
367 : : }
368 : :
369 : : /* Do request/response transaction */
370 : 0 : static int hn_rndis_exec1(struct hn_data *hv,
371 : : const void *req, uint32_t reqlen,
372 : : void *comp, uint32_t comp_len)
373 : : {
374 : : const struct rndis_halt_req *hdr = req;
375 [ # # ]: 0 : uint32_t rid = hdr->rid;
376 : : struct vmbus_channel *chan = hn_primary_chan(hv);
377 : : int error;
378 : :
379 [ # # ]: 0 : if (comp_len > sizeof(hv->rndis_resp)) {
380 : 0 : PMD_DRV_LOG(ERR,
381 : : "Expected completion size %u exceeds buffer %zu",
382 : : comp_len, sizeof(hv->rndis_resp));
383 : 0 : return -EIO;
384 : : }
385 : :
386 [ # # ]: 0 : if (rid == 0) {
387 : 0 : PMD_DRV_LOG(ERR, "Invalid request id");
388 : 0 : return -EINVAL;
389 : : }
390 : :
391 [ # # # # ]: 0 : if (comp != NULL &&
392 : 0 : rte_atomic32_cmpset(&hv->rndis_pending, 0, rid) == 0) {
393 : 0 : PMD_DRV_LOG(ERR,
394 : : "Request already pending");
395 : 0 : return -EBUSY;
396 : : }
397 : :
398 : 0 : error = hn_nvs_send_rndis_ctrl(hv, chan, req, reqlen);
399 [ # # ]: 0 : if (error) {
400 : 0 : PMD_DRV_LOG(ERR, "RNDIS ctrl send failed: %d", error);
401 : 0 : return error;
402 : : }
403 : :
404 [ # # ]: 0 : if (comp) {
405 : 0 : time_t start = time(NULL);
406 : :
407 : : /* Poll primary channel until response received */
408 [ # # ]: 0 : while (hv->rndis_pending == rid) {
409 [ # # ]: 0 : if (hv->closed)
410 : : return -ENETDOWN;
411 : :
412 [ # # ]: 0 : if (time(NULL) - start > RNDIS_TIMEOUT_SEC) {
413 : 0 : PMD_DRV_LOG(ERR,
414 : : "RNDIS response timed out");
415 : :
416 : 0 : rte_atomic32_cmpset(&hv->rndis_pending, rid, 0);
417 : 0 : return -ETIMEDOUT;
418 : : }
419 : :
420 [ # # ]: 0 : if (rte_vmbus_chan_rx_empty(hv->primary->chan))
421 : : rte_delay_ms(RNDIS_DELAY_MS);
422 : :
423 : 0 : hn_process_events(hv, 0, 1);
424 : : }
425 : :
426 : 0 : memcpy(comp, hv->rndis_resp, comp_len);
427 : : }
428 : :
429 : : return 0;
430 : : }
431 : :
432 : : /* Do transaction and validate response */
433 : 0 : static int hn_rndis_execute(struct hn_data *hv, uint32_t rid,
434 : : const void *req, uint32_t reqlen,
435 : : void *comp, uint32_t comp_len, uint32_t comp_type)
436 : : {
437 : : const struct rndis_comp_hdr *hdr = comp;
438 : : int ret;
439 : :
440 : 0 : memset(comp, 0, comp_len);
441 : :
442 : 0 : ret = hn_rndis_exec1(hv, req, reqlen, comp, comp_len);
443 [ # # ]: 0 : if (ret < 0)
444 : : return ret;
445 : : /*
446 : : * Check this RNDIS complete message.
447 : : */
448 [ # # ]: 0 : if (unlikely(hdr->type != comp_type)) {
449 : 0 : PMD_DRV_LOG(ERR,
450 : : "unexpected RNDIS response complete %#x expect %#x",
451 : : hdr->type, comp_type);
452 : :
453 : 0 : return -ENXIO;
454 : : }
455 [ # # ]: 0 : if (unlikely(hdr->rid != rid)) {
456 : 0 : PMD_DRV_LOG(ERR,
457 : : "RNDIS comp rid mismatch %#x, expect %#x",
458 : : hdr->rid, rid);
459 : 0 : return -EINVAL;
460 : : }
461 : :
462 : : /* All pass! */
463 : : return 0;
464 : : }
465 : :
466 : : static int
467 : 0 : hn_rndis_query(struct hn_data *hv, uint32_t oid,
468 : : const void *idata, uint32_t idlen,
469 : : void *odata, uint32_t odlen)
470 : : {
471 : : struct rndis_query_req *req;
472 : : struct rndis_query_comp *comp;
473 : : uint32_t reqlen, comp_len;
474 : : int error = -EIO;
475 : : unsigned int ofs;
476 : : uint32_t rid;
477 : :
478 : 0 : reqlen = sizeof(*req) + idlen;
479 : 0 : req = hn_rndis_alloc(reqlen);
480 [ # # ]: 0 : if (req == NULL)
481 : : return -ENOMEM;
482 : :
483 : 0 : comp_len = sizeof(*comp) + odlen;
484 : 0 : comp = rte_zmalloc("QUERY", comp_len, HYPERV_PAGE_SIZE);
485 [ # # ]: 0 : if (!comp) {
486 : : error = -ENOMEM;
487 : 0 : goto done;
488 : : }
489 : 0 : comp->status = RNDIS_STATUS_PENDING;
490 : :
491 : : rid = hn_rndis_rid(hv);
492 : :
493 : 0 : req->type = RNDIS_QUERY_MSG;
494 : 0 : req->len = reqlen;
495 : 0 : req->rid = rid;
496 : 0 : req->oid = oid;
497 : 0 : req->infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
498 : 0 : req->infobuflen = idlen;
499 : :
500 : : /* Input data immediately follows RNDIS query. */
501 : 0 : memcpy(req + 1, idata, idlen);
502 : :
503 : 0 : error = hn_rndis_execute(hv, rid, req, reqlen,
504 : : comp, comp_len, RNDIS_QUERY_CMPLT);
505 : :
506 [ # # ]: 0 : if (error)
507 : 0 : goto done;
508 : :
509 [ # # ]: 0 : if (comp->status != RNDIS_STATUS_SUCCESS) {
510 : 0 : PMD_DRV_LOG(ERR, "RNDIS query 0x%08x failed: status 0x%08x",
511 : : oid, comp->status);
512 : : error = -EINVAL;
513 : 0 : goto done;
514 : : }
515 : :
516 [ # # # # ]: 0 : if (comp->infobuflen == 0 || comp->infobufoffset == 0) {
517 : : /* No output data! */
518 : 0 : PMD_DRV_LOG(ERR, "RNDIS query 0x%08x, no data", oid);
519 : : error = 0;
520 : 0 : goto done;
521 : : }
522 : :
523 : : /*
524 : : * Check output data length and offset.
525 : : */
526 : : /* ofs is the offset from the beginning of comp. */
527 : 0 : ofs = RNDIS_QUERY_COMP_INFOBUFOFFSET_ABS(comp->infobufoffset);
528 [ # # # # ]: 0 : if (ofs < sizeof(*comp) || ofs + comp->infobuflen > comp_len) {
529 : 0 : PMD_DRV_LOG(ERR, "RNDIS query invalid comp ib off/len, %u/%u",
530 : : comp->infobufoffset, comp->infobuflen);
531 : : error = -EINVAL;
532 : 0 : goto done;
533 : : }
534 : :
535 : : /* Save output data. */
536 : : if (comp->infobuflen < odlen)
537 : : odlen = comp->infobuflen;
538 : :
539 : : /* ofs is the offset from the beginning of comp. */
540 : 0 : memcpy(odata, (const char *)comp + ofs, odlen);
541 : :
542 : : error = 0;
543 : 0 : done:
544 : 0 : rte_free(comp);
545 : 0 : rte_free(req);
546 : 0 : return error;
547 : : }
548 : :
549 : : static int
550 : 0 : hn_rndis_halt(struct hn_data *hv)
551 : : {
552 : : struct rndis_halt_req *halt;
553 : :
554 : : halt = hn_rndis_alloc(sizeof(*halt));
555 [ # # ]: 0 : if (halt == NULL)
556 : : return -ENOMEM;
557 : :
558 : 0 : halt->type = RNDIS_HALT_MSG;
559 : 0 : halt->len = sizeof(*halt);
560 : 0 : halt->rid = hn_rndis_rid(hv);
561 : :
562 : : /* No RNDIS completion; rely on NVS message send completion */
563 : 0 : hn_rndis_exec1(hv, halt, sizeof(*halt), NULL, 0);
564 : :
565 : 0 : rte_free(halt);
566 : :
567 : 0 : PMD_INIT_LOG(DEBUG, "RNDIS halt done");
568 : 0 : return 0;
569 : : }
570 : :
571 : : static int
572 [ # # ]: 0 : hn_rndis_query_hwcaps(struct hn_data *hv, struct ndis_offload *caps)
573 : : {
574 : : struct ndis_offload in;
575 : : uint32_t caps_len, size;
576 : : int error;
577 : :
578 : : memset(caps, 0, sizeof(*caps));
579 : : memset(&in, 0, sizeof(in));
580 : 0 : in.ndis_hdr.ndis_type = NDIS_OBJTYPE_OFFLOAD;
581 : :
582 [ # # ]: 0 : if (hv->ndis_ver >= NDIS_VERSION_6_30) {
583 : 0 : in.ndis_hdr.ndis_rev = NDIS_OFFLOAD_REV_3;
584 : : size = NDIS_OFFLOAD_SIZE;
585 [ # # ]: 0 : } else if (hv->ndis_ver >= NDIS_VERSION_6_1) {
586 : 0 : in.ndis_hdr.ndis_rev = NDIS_OFFLOAD_REV_2;
587 : : size = NDIS_OFFLOAD_SIZE_6_1;
588 : : } else {
589 : 0 : in.ndis_hdr.ndis_rev = NDIS_OFFLOAD_REV_1;
590 : : size = NDIS_OFFLOAD_SIZE_6_0;
591 : : }
592 : 0 : in.ndis_hdr.ndis_size = size;
593 : :
594 : : caps_len = NDIS_OFFLOAD_SIZE;
595 : 0 : error = hn_rndis_query(hv, OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES,
596 : : &in, size, caps, caps_len);
597 [ # # ]: 0 : if (error)
598 : : return error;
599 : :
600 : : /* Preliminary verification. */
601 [ # # ]: 0 : if (caps->ndis_hdr.ndis_type != NDIS_OBJTYPE_OFFLOAD) {
602 : 0 : PMD_DRV_LOG(NOTICE, "invalid NDIS objtype 0x%02x",
603 : : caps->ndis_hdr.ndis_type);
604 : 0 : return -EINVAL;
605 : : }
606 [ # # ]: 0 : if (caps->ndis_hdr.ndis_rev < NDIS_OFFLOAD_REV_1) {
607 : 0 : PMD_DRV_LOG(NOTICE, "invalid NDIS objrev 0x%02x",
608 : : caps->ndis_hdr.ndis_rev);
609 : 0 : return -EINVAL;
610 : : }
611 [ # # ]: 0 : if (caps->ndis_hdr.ndis_size > caps_len) {
612 : 0 : PMD_DRV_LOG(NOTICE, "invalid NDIS objsize %u, data size %u",
613 : : caps->ndis_hdr.ndis_size, caps_len);
614 : 0 : return -EINVAL;
615 [ # # ]: 0 : } else if (caps->ndis_hdr.ndis_size < NDIS_OFFLOAD_SIZE_6_0) {
616 : 0 : PMD_DRV_LOG(NOTICE, "invalid NDIS objsize %u",
617 : : caps->ndis_hdr.ndis_size);
618 : 0 : return -EINVAL;
619 : : }
620 : :
621 : : return 0;
622 : : }
623 : :
624 : : int
625 : 0 : hn_rndis_query_rsscaps(struct hn_data *hv,
626 : : unsigned int *rxr_cnt0)
627 : : {
628 : : struct ndis_rss_caps in, caps;
629 : : unsigned int indsz, rxr_cnt;
630 : : uint32_t caps_len;
631 : : int error;
632 : :
633 : 0 : *rxr_cnt0 = 0;
634 : :
635 [ # # ]: 0 : if (hv->ndis_ver < NDIS_VERSION_6_20) {
636 : 0 : PMD_DRV_LOG(DEBUG, "RSS not supported on this host");
637 : 0 : return -EOPNOTSUPP;
638 : : }
639 : :
640 : : memset(&in, 0, sizeof(in));
641 : 0 : in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
642 : 0 : in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
643 : 0 : in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
644 : :
645 : : caps_len = NDIS_RSS_CAPS_SIZE;
646 : 0 : error = hn_rndis_query(hv, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
647 : : &in, NDIS_RSS_CAPS_SIZE,
648 : : &caps, caps_len);
649 [ # # ]: 0 : if (error)
650 : : return error;
651 : :
652 : 0 : PMD_INIT_LOG(DEBUG, "RX rings %u indirect %u caps %#x",
653 : : caps.ndis_nrxr, caps.ndis_nind, caps.ndis_caps);
654 : : /*
655 : : * Preliminary verification.
656 : : */
657 [ # # ]: 0 : if (caps.ndis_hdr.ndis_type != NDIS_OBJTYPE_RSS_CAPS) {
658 : 0 : PMD_DRV_LOG(ERR, "invalid NDIS objtype 0x%02x",
659 : : caps.ndis_hdr.ndis_type);
660 : 0 : return -EINVAL;
661 : : }
662 [ # # ]: 0 : if (caps.ndis_hdr.ndis_rev < NDIS_RSS_CAPS_REV_1) {
663 : 0 : PMD_DRV_LOG(ERR, "invalid NDIS objrev 0x%02x",
664 : : caps.ndis_hdr.ndis_rev);
665 : 0 : return -EINVAL;
666 : : }
667 [ # # ]: 0 : if (caps.ndis_hdr.ndis_size > caps_len) {
668 : 0 : PMD_DRV_LOG(ERR,
669 : : "invalid NDIS objsize %u, data size %u",
670 : : caps.ndis_hdr.ndis_size, caps_len);
671 : 0 : return -EINVAL;
672 [ # # ]: 0 : } else if (caps.ndis_hdr.ndis_size < NDIS_RSS_CAPS_SIZE_6_0) {
673 : 0 : PMD_DRV_LOG(ERR, "invalid NDIS objsize %u",
674 : : caps.ndis_hdr.ndis_size);
675 : 0 : return -EINVAL;
676 : : }
677 : :
678 : : /*
679 : : * Save information for later RSS configuration.
680 : : */
681 [ # # ]: 0 : if (caps.ndis_nrxr == 0) {
682 : 0 : PMD_DRV_LOG(ERR, "0 RX rings!?");
683 : 0 : return -EINVAL;
684 : : }
685 : : rxr_cnt = caps.ndis_nrxr;
686 : :
687 [ # # # # ]: 0 : if (caps.ndis_hdr.ndis_size == NDIS_RSS_CAPS_SIZE &&
688 : : caps.ndis_hdr.ndis_rev >= NDIS_RSS_CAPS_REV_2) {
689 [ # # ]: 0 : if (caps.ndis_nind > NDIS_HASH_INDCNT) {
690 : 0 : PMD_DRV_LOG(ERR,
691 : : "too many RSS indirect table entries %u",
692 : : caps.ndis_nind);
693 : 0 : return -EOPNOTSUPP;
694 : : }
695 [ # # ]: 0 : if (!rte_is_power_of_2(caps.ndis_nind)) {
696 : 0 : PMD_DRV_LOG(ERR,
697 : : "RSS indirect table size is not power-of-2 %u",
698 : : caps.ndis_nind);
699 : : }
700 : :
701 : 0 : indsz = caps.ndis_nind;
702 : : } else {
703 : : indsz = NDIS_HASH_INDCNT;
704 : : }
705 : :
706 [ # # ]: 0 : if (indsz < rxr_cnt) {
707 : 0 : PMD_DRV_LOG(NOTICE,
708 : : "# of RX rings (%d) > RSS indirect table size %d",
709 : : rxr_cnt, indsz);
710 : : rxr_cnt = indsz;
711 : : }
712 : :
713 : 0 : hv->rss_offloads = 0;
714 [ # # ]: 0 : if (caps.ndis_caps & NDIS_RSS_CAP_IPV4)
715 : 0 : hv->rss_offloads |= RTE_ETH_RSS_IPV4
716 : : | RTE_ETH_RSS_NONFRAG_IPV4_TCP
717 : : | RTE_ETH_RSS_NONFRAG_IPV4_UDP;
718 [ # # ]: 0 : if (caps.ndis_caps & NDIS_RSS_CAP_IPV6)
719 : 0 : hv->rss_offloads |= RTE_ETH_RSS_IPV6
720 : : | RTE_ETH_RSS_NONFRAG_IPV6_TCP;
721 [ # # ]: 0 : if (caps.ndis_caps & NDIS_RSS_CAP_IPV6_EX)
722 : 0 : hv->rss_offloads |= RTE_ETH_RSS_IPV6_EX
723 : : | RTE_ETH_RSS_IPV6_TCP_EX;
724 : :
725 : : /* Commit! */
726 : 0 : *rxr_cnt0 = rxr_cnt;
727 : :
728 : 0 : return 0;
729 : : }
730 : :
731 : : static int
732 : 0 : hn_rndis_set(struct hn_data *hv, uint32_t oid, const void *data, uint32_t dlen)
733 : : {
734 : : struct rndis_set_req *req;
735 : : struct rndis_set_comp comp;
736 : : uint32_t reqlen, comp_len;
737 : : uint32_t rid;
738 : : int error;
739 : :
740 : 0 : reqlen = sizeof(*req) + dlen;
741 : 0 : req = rte_zmalloc("RNDIS_SET", reqlen, HYPERV_PAGE_SIZE);
742 [ # # ]: 0 : if (!req)
743 : : return -ENOMEM;
744 : :
745 : : rid = hn_rndis_rid(hv);
746 : 0 : req->type = RNDIS_SET_MSG;
747 : 0 : req->len = reqlen;
748 : 0 : req->rid = rid;
749 : 0 : req->oid = oid;
750 : 0 : req->infobuflen = dlen;
751 : 0 : req->infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET;
752 : :
753 : : /* Data immediately follows RNDIS set. */
754 : 0 : memcpy(req + 1, data, dlen);
755 : :
756 : : comp_len = sizeof(comp);
757 : 0 : error = hn_rndis_execute(hv, rid, req, reqlen,
758 : : &comp, comp_len,
759 : : RNDIS_SET_CMPLT);
760 [ # # ]: 0 : if (error) {
761 : 0 : PMD_DRV_LOG(ERR, "exec RNDIS set %#" PRIx32 " failed",
762 : : oid);
763 : : error = EIO;
764 : 0 : goto done;
765 : : }
766 : :
767 [ # # ]: 0 : if (comp.status != RNDIS_STATUS_SUCCESS) {
768 : 0 : PMD_DRV_LOG(ERR,
769 : : "RNDIS set %#" PRIx32 " failed: status %#" PRIx32,
770 : : oid, comp.status);
771 : : error = EIO;
772 : 0 : goto done;
773 : : }
774 : :
775 : 0 : done:
776 : 0 : rte_free(req);
777 : 0 : return error;
778 : : }
779 : :
780 : 0 : int hn_rndis_conf_offload(struct hn_data *hv,
781 : : uint64_t tx_offloads, uint64_t rx_offloads)
782 : : {
783 : : struct ndis_offload_params params;
784 : : struct ndis_offload hwcaps;
785 : : int error;
786 : :
787 : 0 : error = hn_rndis_query_hwcaps(hv, &hwcaps);
788 [ # # ]: 0 : if (error) {
789 : 0 : PMD_DRV_LOG(ERR, "hwcaps query failed: %d", error);
790 : 0 : return error;
791 : : }
792 : :
793 : : /* NOTE: 0 means "no change" */
794 : : memset(¶ms, 0, sizeof(params));
795 : :
796 : 0 : params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
797 [ # # ]: 0 : if (hv->ndis_ver < NDIS_VERSION_6_30) {
798 : 0 : params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
799 : 0 : params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
800 : : } else {
801 : 0 : params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
802 : 0 : params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE;
803 : : }
804 : :
805 [ # # ]: 0 : if (tx_offloads & RTE_ETH_TX_OFFLOAD_TCP_CKSUM) {
806 [ # # ]: 0 : if (hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_TCP4)
807 : 0 : params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TX;
808 : : else
809 : 0 : goto unsupported;
810 : :
811 [ # # ]: 0 : if (hwcaps.ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_TCP6)
812 : 0 : params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TX;
813 : : else
814 : 0 : goto unsupported;
815 : : }
816 : :
817 [ # # ]: 0 : if (rx_offloads & RTE_ETH_RX_OFFLOAD_TCP_CKSUM) {
818 [ # # ]: 0 : if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4)
819 : : == NDIS_RXCSUM_CAP_TCP4)
820 : 0 : params.ndis_tcp4csum |= NDIS_OFFLOAD_PARAM_RX;
821 : : else
822 : 0 : goto unsupported;
823 : :
824 [ # # ]: 0 : if ((hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6)
825 : : == NDIS_RXCSUM_CAP_TCP6)
826 : 0 : params.ndis_tcp6csum |= NDIS_OFFLOAD_PARAM_RX;
827 : : else
828 : 0 : goto unsupported;
829 : : }
830 : :
831 [ # # ]: 0 : if (tx_offloads & RTE_ETH_TX_OFFLOAD_UDP_CKSUM) {
832 [ # # ]: 0 : if (hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_UDP4)
833 : 0 : params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TX;
834 : : else
835 : 0 : goto unsupported;
836 : :
837 [ # # ]: 0 : if ((hwcaps.ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_UDP6)
838 : : == NDIS_TXCSUM_CAP_UDP6)
839 : 0 : params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TX;
840 : : else
841 : 0 : goto unsupported;
842 : : }
843 : :
844 [ # # ]: 0 : if (rx_offloads & RTE_ETH_TX_OFFLOAD_UDP_CKSUM) {
845 [ # # ]: 0 : if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4)
846 : 0 : params.ndis_udp4csum |= NDIS_OFFLOAD_PARAM_RX;
847 : : else
848 : 0 : goto unsupported;
849 : :
850 [ # # ]: 0 : if (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6)
851 : 0 : params.ndis_udp6csum |= NDIS_OFFLOAD_PARAM_RX;
852 : : else
853 : 0 : goto unsupported;
854 : : }
855 : :
856 [ # # ]: 0 : if (tx_offloads & RTE_ETH_TX_OFFLOAD_IPV4_CKSUM) {
857 [ # # ]: 0 : if ((hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_IP4)
858 : : == NDIS_TXCSUM_CAP_IP4)
859 : 0 : params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TX;
860 : : else
861 : 0 : goto unsupported;
862 : : }
863 [ # # ]: 0 : if (rx_offloads & RTE_ETH_RX_OFFLOAD_IPV4_CKSUM) {
864 [ # # ]: 0 : if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)
865 : 0 : params.ndis_ip4csum |= NDIS_OFFLOAD_PARAM_RX;
866 : : else
867 : 0 : goto unsupported;
868 : : }
869 : :
870 [ # # ]: 0 : if (tx_offloads & RTE_ETH_TX_OFFLOAD_TCP_TSO) {
871 [ # # ]: 0 : if (hwcaps.ndis_lsov2.ndis_ip4_encap & NDIS_OFFLOAD_ENCAP_8023)
872 : 0 : params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
873 : : else
874 : 0 : goto unsupported;
875 : :
876 [ # # ]: 0 : if ((hwcaps.ndis_lsov2.ndis_ip6_opts & HN_NDIS_LSOV2_CAP_IP6)
877 : : == HN_NDIS_LSOV2_CAP_IP6)
878 : 0 : params.ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON;
879 : : else
880 : 0 : goto unsupported;
881 : : }
882 : :
883 : 0 : error = hn_rndis_set(hv, OID_TCP_OFFLOAD_PARAMETERS, ¶ms,
884 : 0 : params.ndis_hdr.ndis_size);
885 [ # # ]: 0 : if (error) {
886 : 0 : PMD_DRV_LOG(ERR, "offload config failed");
887 : 0 : return error;
888 : : }
889 : :
890 : : return 0;
891 : 0 : unsupported:
892 : 0 : PMD_DRV_LOG(NOTICE,
893 : : "offload tx:%" PRIx64 " rx:%" PRIx64 " not supported by this version",
894 : : tx_offloads, rx_offloads);
895 : 0 : return -EINVAL;
896 : : }
897 : :
898 : 0 : int hn_rndis_get_offload(struct hn_data *hv,
899 : : struct rte_eth_dev_info *dev_info)
900 : : {
901 : : struct ndis_offload hwcaps;
902 : : int error;
903 : :
904 : : memset(&hwcaps, 0, sizeof(hwcaps));
905 : :
906 : 0 : error = hn_rndis_query_hwcaps(hv, &hwcaps);
907 [ # # ]: 0 : if (error) {
908 : 0 : PMD_DRV_LOG(ERR, "hwcaps query failed: %d", error);
909 : 0 : return error;
910 : : }
911 : :
912 : 0 : dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
913 : : RTE_ETH_TX_OFFLOAD_VLAN_INSERT;
914 : :
915 [ # # ]: 0 : if ((hwcaps.ndis_csum.ndis_ip4_txcsum & HN_NDIS_TXCSUM_CAP_IP4)
916 : : == HN_NDIS_TXCSUM_CAP_IP4)
917 : 0 : dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_IPV4_CKSUM;
918 : :
919 [ # # ]: 0 : if ((hwcaps.ndis_csum.ndis_ip4_txcsum & HN_NDIS_TXCSUM_CAP_TCP4)
920 : 0 : == HN_NDIS_TXCSUM_CAP_TCP4 &&
921 [ # # ]: 0 : (hwcaps.ndis_csum.ndis_ip6_txcsum & HN_NDIS_TXCSUM_CAP_TCP6)
922 : : == HN_NDIS_TXCSUM_CAP_TCP6)
923 : 0 : dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_TCP_CKSUM;
924 : :
925 [ # # ]: 0 : if ((hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_UDP4) &&
926 [ # # ]: 0 : (hwcaps.ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_UDP6))
927 : 0 : dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_UDP_CKSUM;
928 : :
929 [ # # ]: 0 : if ((hwcaps.ndis_lsov2.ndis_ip4_encap & NDIS_OFFLOAD_ENCAP_8023) &&
930 [ # # ]: 0 : (hwcaps.ndis_lsov2.ndis_ip6_opts & HN_NDIS_LSOV2_CAP_IP6)
931 : : == HN_NDIS_LSOV2_CAP_IP6)
932 : 0 : dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_TCP_TSO;
933 : :
934 : 0 : dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
935 : : RTE_ETH_RX_OFFLOAD_RSS_HASH;
936 : :
937 [ # # ]: 0 : if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)
938 : 0 : dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_IPV4_CKSUM;
939 : :
940 [ # # ]: 0 : if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4) &&
941 [ # # ]: 0 : (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6))
942 : 0 : dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TCP_CKSUM;
943 : :
944 [ # # ]: 0 : if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4) &&
945 [ # # ]: 0 : (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6))
946 : 0 : dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_UDP_CKSUM;
947 : :
948 : : return 0;
949 : : }
950 : :
951 : : uint32_t
952 : 0 : hn_rndis_get_ptypes(struct hn_data *hv)
953 : : {
954 : : struct ndis_offload hwcaps;
955 : : uint32_t ptypes;
956 : : int error;
957 : :
958 : : memset(&hwcaps, 0, sizeof(hwcaps));
959 : :
960 : 0 : error = hn_rndis_query_hwcaps(hv, &hwcaps);
961 [ # # ]: 0 : if (error) {
962 : 0 : PMD_DRV_LOG(ERR, "hwcaps query failed: %d", error);
963 : 0 : return RTE_PTYPE_L2_ETHER;
964 : : }
965 : :
966 : : ptypes = RTE_PTYPE_L2_ETHER;
967 : :
968 [ # # ]: 0 : if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)
969 : : ptypes |= RTE_PTYPE_L3_IPV4;
970 : :
971 [ # # ]: 0 : if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4) ||
972 [ # # ]: 0 : (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6))
973 : 0 : ptypes |= RTE_PTYPE_L4_TCP;
974 : :
975 [ # # ]: 0 : if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4) ||
976 [ # # ]: 0 : (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6))
977 : 0 : ptypes |= RTE_PTYPE_L4_UDP;
978 : :
979 : : return ptypes;
980 : : }
981 : :
982 : : int
983 : 0 : hn_rndis_set_rxfilter(struct hn_data *hv, uint32_t filter)
984 : : {
985 : : int error;
986 : :
987 : 0 : error = hn_rndis_set(hv, OID_GEN_CURRENT_PACKET_FILTER,
988 : : &filter, sizeof(filter));
989 [ # # ]: 0 : if (error) {
990 : 0 : PMD_DRV_LOG(ERR, "set RX filter %#" PRIx32 " failed: %d",
991 : : filter, error);
992 : : } else {
993 : 0 : PMD_DRV_LOG(DEBUG, "set RX filter %#" PRIx32 " done", filter);
994 : : }
995 : :
996 : 0 : return error;
997 : : }
998 : :
999 : 0 : int hn_rndis_conf_rss(struct hn_data *hv, uint32_t flags)
1000 : : {
1001 : : struct ndis_rssprm_toeplitz rssp;
1002 : : struct ndis_rss_params *prm = &rssp.rss_params;
1003 : : unsigned int i;
1004 : : int error;
1005 : :
1006 : : memset(&rssp, 0, sizeof(rssp));
1007 : :
1008 : 0 : prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
1009 : 0 : prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
1010 : 0 : prm->ndis_hdr.ndis_size = sizeof(*prm);
1011 : 0 : prm->ndis_flags = flags;
1012 : 0 : prm->ndis_hash = hv->rss_hash;
1013 : 0 : prm->ndis_indsize = sizeof(rssp.rss_ind[0]) * NDIS_HASH_INDCNT;
1014 : 0 : prm->ndis_indoffset = offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
1015 : 0 : prm->ndis_keysize = NDIS_HASH_KEYSIZE_TOEPLITZ;
1016 : 0 : prm->ndis_keyoffset = offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
1017 : :
1018 [ # # ]: 0 : for (i = 0; i < NDIS_HASH_INDCNT; i++)
1019 : 0 : rssp.rss_ind[i] = hv->rss_ind[i];
1020 : :
1021 : : /* Set hask key values */
1022 : : memcpy(&rssp.rss_key, hv->rss_key, NDIS_HASH_KEYSIZE_TOEPLITZ);
1023 : :
1024 : 0 : error = hn_rndis_set(hv, OID_GEN_RECEIVE_SCALE_PARAMETERS,
1025 : : &rssp, sizeof(rssp));
1026 [ # # ]: 0 : if (error != 0) {
1027 : 0 : PMD_DRV_LOG(ERR,
1028 : : "RSS config num queues=%u failed: %d",
1029 : : hv->num_queues, error);
1030 : : }
1031 : 0 : return error;
1032 : : }
1033 : :
1034 : 0 : static int hn_rndis_init(struct hn_data *hv)
1035 : : {
1036 : : struct rndis_init_req *req;
1037 : : struct rndis_init_comp comp;
1038 : : uint32_t comp_len, rid;
1039 : : int error;
1040 : :
1041 : : req = hn_rndis_alloc(sizeof(*req));
1042 [ # # ]: 0 : if (!req) {
1043 : 0 : PMD_DRV_LOG(ERR, "no memory for RNDIS init");
1044 : 0 : return -ENXIO;
1045 : : }
1046 : :
1047 : : rid = hn_rndis_rid(hv);
1048 : 0 : req->type = RNDIS_INITIALIZE_MSG;
1049 : 0 : req->len = sizeof(*req);
1050 : 0 : req->rid = rid;
1051 : 0 : req->ver_major = RNDIS_VERSION_MAJOR;
1052 : 0 : req->ver_minor = RNDIS_VERSION_MINOR;
1053 : 0 : req->max_xfersz = HN_RNDIS_XFER_SIZE;
1054 : :
1055 : : comp_len = RNDIS_INIT_COMP_SIZE_MIN;
1056 : 0 : error = hn_rndis_execute(hv, rid, req, sizeof(*req),
1057 : : &comp, comp_len,
1058 : : RNDIS_INITIALIZE_CMPLT);
1059 [ # # ]: 0 : if (error)
1060 : 0 : goto done;
1061 : :
1062 [ # # ]: 0 : if (comp.status != RNDIS_STATUS_SUCCESS) {
1063 : 0 : PMD_DRV_LOG(ERR, "RNDIS init failed: status 0x%08x",
1064 : : comp.status);
1065 : : error = -EIO;
1066 : 0 : goto done;
1067 : : }
1068 : :
1069 : 0 : hv->rndis_agg_size = comp.pktmaxsz;
1070 : 0 : hv->rndis_agg_pkts = comp.pktmaxcnt;
1071 : 0 : hv->rndis_agg_align = 1U << comp.align;
1072 : :
1073 [ # # ]: 0 : if (hv->rndis_agg_align < sizeof(uint32_t)) {
1074 : : /*
1075 : : * The RNDIS packet message encap assumes that the RNDIS
1076 : : * packet message is at least 4 bytes aligned. Fix up the
1077 : : * alignment here, if the remote side sets the alignment
1078 : : * too low.
1079 : : */
1080 : 0 : PMD_DRV_LOG(NOTICE,
1081 : : "fixup RNDIS aggpkt align: %u -> %zu",
1082 : : hv->rndis_agg_align, sizeof(uint32_t));
1083 : 0 : hv->rndis_agg_align = sizeof(uint32_t);
1084 : : }
1085 : :
1086 : 0 : PMD_INIT_LOG(INFO,
1087 : : "RNDIS ver %u.%u, aggpkt size %u, aggpkt cnt %u, aggpkt align %u",
1088 : : comp.ver_major, comp.ver_minor,
1089 : : hv->rndis_agg_size, hv->rndis_agg_pkts,
1090 : : hv->rndis_agg_align);
1091 : : error = 0;
1092 : 0 : done:
1093 : 0 : rte_free(req);
1094 : 0 : return error;
1095 : : }
1096 : :
1097 : : int
1098 : 0 : hn_rndis_get_eaddr(struct hn_data *hv, uint8_t *eaddr)
1099 : : {
1100 : : uint32_t eaddr_len;
1101 : : int error;
1102 : :
1103 : : eaddr_len = RTE_ETHER_ADDR_LEN;
1104 : 0 : error = hn_rndis_query(hv, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
1105 : : eaddr, eaddr_len);
1106 [ # # ]: 0 : if (error)
1107 : : return error;
1108 : :
1109 : 0 : PMD_DRV_LOG(INFO, "MAC address " RTE_ETHER_ADDR_PRT_FMT,
1110 : : eaddr[0], eaddr[1], eaddr[2],
1111 : : eaddr[3], eaddr[4], eaddr[5]);
1112 : 0 : return 0;
1113 : : }
1114 : :
1115 : : int
1116 : 0 : hn_rndis_get_mtu(struct hn_data *hv, uint32_t *mtu)
1117 : : {
1118 : 0 : return hn_rndis_query(hv, OID_GEN_MAXIMUM_FRAME_SIZE, NULL, 0,
1119 : : mtu, sizeof(uint32_t));
1120 : : }
1121 : :
1122 : : int
1123 : 0 : hn_rndis_get_linkstatus(struct hn_data *hv)
1124 : : {
1125 : 0 : return hn_rndis_query(hv, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,
1126 : 0 : &hv->link_status, sizeof(uint32_t));
1127 : : }
1128 : :
1129 : : int
1130 : 0 : hn_rndis_get_linkspeed(struct hn_data *hv)
1131 : : {
1132 : 0 : return hn_rndis_query(hv, OID_GEN_LINK_SPEED, NULL, 0,
1133 : 0 : &hv->link_speed, sizeof(uint32_t));
1134 : : }
1135 : :
1136 : : int
1137 : 0 : hn_rndis_attach(struct hn_data *hv)
1138 : : {
1139 : : /* Initialize RNDIS. */
1140 : 0 : return hn_rndis_init(hv);
1141 : : }
1142 : :
1143 : : void
1144 : 0 : hn_rndis_detach(struct hn_data *hv)
1145 : : {
1146 : 0 : struct rte_eth_dev *dev = &rte_eth_devices[hv->port_id];
1147 : :
1148 : 0 : rte_eal_alarm_cancel(hn_rndis_link_alarm, dev);
1149 : :
1150 : : /* Halt the RNDIS. */
1151 : 0 : hn_rndis_halt(hv);
1152 : 0 : }
|