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.
14 #include <rte_ethdev.h>
15 #include <rte_string_fns.h>
16 #include <rte_memzone.h>
17 #include <rte_malloc.h>
18 #include <rte_atomic.h>
19 #include <rte_branch_prediction.h>
20 #include <rte_ether.h>
21 #include <rte_common.h>
22 #include <rte_errno.h>
23 #include <rte_cycles.h>
24 #include <rte_memory.h>
27 #include <rte_bus_vmbus.h>
35 #define HN_RNDIS_XFER_SIZE 0x4000
37 #define HN_NDIS_TXCSUM_CAP_IP4 \
38 (NDIS_TXCSUM_CAP_IP4 | NDIS_TXCSUM_CAP_IP4OPT)
39 #define HN_NDIS_TXCSUM_CAP_TCP4 \
40 (NDIS_TXCSUM_CAP_TCP4 | NDIS_TXCSUM_CAP_TCP4OPT)
41 #define HN_NDIS_TXCSUM_CAP_TCP6 \
42 (NDIS_TXCSUM_CAP_TCP6 | NDIS_TXCSUM_CAP_TCP6OPT | \
43 NDIS_TXCSUM_CAP_IP6EXT)
44 #define HN_NDIS_TXCSUM_CAP_UDP6 \
45 (NDIS_TXCSUM_CAP_UDP6 | NDIS_TXCSUM_CAP_IP6EXT)
46 #define HN_NDIS_LSOV2_CAP_IP6 \
47 (NDIS_LSOV2_CAP_IP6EXT | NDIS_LSOV2_CAP_TCP6OPT)
49 /* Get unique request id */
50 static inline uint32_t
51 hn_rndis_rid(struct hn_data *hv)
56 rid = rte_atomic32_add_return(&hv->rndis_req_id, 1);
62 static void *hn_rndis_alloc(struct hn_data *hv, size_t size)
64 return rte_zmalloc_socket("RNDIS", size, PAGE_SIZE,
65 hv->vmbus->device.numa_node);
68 #ifdef RTE_LIBRTE_NETVSC_DEBUG_DUMP
69 void hn_rndis_dump(const void *buf)
72 struct rndis_msghdr hdr;
73 struct rndis_packet_msg pkt;
74 struct rndis_init_req init_request;
75 struct rndis_init_comp init_complete;
76 struct rndis_halt_req halt;
77 struct rndis_query_req query_request;
78 struct rndis_query_comp query_complete;
79 struct rndis_set_req set_request;
80 struct rndis_set_comp set_complete;
81 struct rndis_reset_req reset_request;
82 struct rndis_reset_comp reset_complete;
83 struct rndis_keepalive_req keepalive_request;
84 struct rndis_keepalive_comp keepalive_complete;
85 struct rndis_status_msg indicate_status;
88 switch (rndis_msg->hdr.type) {
89 case RNDIS_PACKET_MSG: {
90 const struct rndis_pktinfo *ppi;
93 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
94 "RNDIS_MSG_PACKET (len %u, data %u:%u, # oob %u %u:%u, pkt %u:%u)\n",
96 rndis_msg->pkt.dataoffset,
97 rndis_msg->pkt.datalen,
98 rndis_msg->pkt.oobdataelements,
99 rndis_msg->pkt.oobdataoffset,
100 rndis_msg->pkt.oobdatalen,
101 rndis_msg->pkt.pktinfooffset,
102 rndis_msg->pkt.pktinfolen);
104 ppi = (const struct rndis_pktinfo *)
106 + RNDIS_PACKET_MSG_OFFSET_ABS(rndis_msg->pkt.pktinfooffset));
108 ppi_len = rndis_msg->pkt.pktinfolen;
109 while (ppi_len > 0) {
110 const void *ppi_data;
112 ppi_data = ppi->data;
114 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
115 " PPI (size %u, type %u, offs %u data %#x)\n",
116 ppi->size, ppi->type, ppi->offset,
117 *(const uint32_t *)ppi_data);
120 ppi_len -= ppi->size;
121 ppi = (const struct rndis_pktinfo *)
122 ((const char *)ppi + ppi->size);
126 case RNDIS_INITIALIZE_MSG:
127 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
128 "RNDIS_MSG_INIT (len %u id %#x, ver %u.%u max xfer %u)\n",
129 rndis_msg->init_request.len,
130 rndis_msg->init_request.rid,
131 rndis_msg->init_request.ver_major,
132 rndis_msg->init_request.ver_minor,
133 rndis_msg->init_request.max_xfersz);
136 case RNDIS_INITIALIZE_CMPLT:
137 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
138 "RNDIS_MSG_INIT_C (len %u, id %#x, status 0x%x, vers %u.%u, "
139 "flags %d, max xfer %u, max pkts %u, aligned %u)\n",
140 rndis_msg->init_complete.len,
141 rndis_msg->init_complete.rid,
142 rndis_msg->init_complete.status,
143 rndis_msg->init_complete.ver_major,
144 rndis_msg->init_complete.ver_minor,
145 rndis_msg->init_complete.devflags,
146 rndis_msg->init_complete.pktmaxsz,
147 rndis_msg->init_complete.pktmaxcnt,
148 rndis_msg->init_complete.align);
152 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
153 "RNDIS_HALT (len %u id %#x)\n",
154 rndis_msg->halt.len, rndis_msg->halt.rid);
157 case RNDIS_QUERY_MSG:
158 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
159 "RNDIS_QUERY (len %u, id %#x, oid %#x, info %u:%u)\n",
160 rndis_msg->query_request.len,
161 rndis_msg->query_request.rid,
162 rndis_msg->query_request.oid,
163 rndis_msg->query_request.infobuflen,
164 rndis_msg->query_request.infobufoffset);
167 case RNDIS_QUERY_CMPLT:
168 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
169 "RNDIS_MSG_QUERY_C (len %u, id %#x, status 0x%x, buf %u:%u)\n",
170 rndis_msg->query_complete.len,
171 rndis_msg->query_complete.rid,
172 rndis_msg->query_complete.status,
173 rndis_msg->query_complete.infobuflen,
174 rndis_msg->query_complete.infobufoffset);
178 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
179 "RNDIS_SET (len %u, id %#x, oid %#x, info %u:%u)\n",
180 rndis_msg->set_request.len,
181 rndis_msg->set_request.rid,
182 rndis_msg->set_request.oid,
183 rndis_msg->set_request.infobuflen,
184 rndis_msg->set_request.infobufoffset);
187 case RNDIS_SET_CMPLT:
188 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
189 "RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)\n",
190 rndis_msg->set_complete.len,
191 rndis_msg->set_complete.rid,
192 rndis_msg->set_complete.status);
195 case RNDIS_INDICATE_STATUS_MSG:
196 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
197 "RNDIS_MSG_INDICATE (len %u, status %#x, buf len %u, buf offset %u)\n",
198 rndis_msg->indicate_status.len,
199 rndis_msg->indicate_status.status,
200 rndis_msg->indicate_status.stbuflen,
201 rndis_msg->indicate_status.stbufoffset);
204 case RNDIS_RESET_MSG:
205 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
206 "RNDIS_RESET (len %u, id %#x)\n",
207 rndis_msg->reset_request.len,
208 rndis_msg->reset_request.rid);
211 case RNDIS_RESET_CMPLT:
212 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
213 "RNDIS_RESET_C (len %u, status %#x address %#x)\n",
214 rndis_msg->reset_complete.len,
215 rndis_msg->reset_complete.status,
216 rndis_msg->reset_complete.adrreset);
219 case RNDIS_KEEPALIVE_MSG:
220 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
221 "RNDIS_KEEPALIVE (len %u, id %#x)\n",
222 rndis_msg->keepalive_request.len,
223 rndis_msg->keepalive_request.rid);
226 case RNDIS_KEEPALIVE_CMPLT:
227 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
228 "RNDIS_KEEPALIVE_C (len %u, id %#x address %#x)\n",
229 rndis_msg->keepalive_complete.len,
230 rndis_msg->keepalive_complete.rid,
231 rndis_msg->keepalive_complete.status);
235 rte_log(RTE_LOG_DEBUG, hn_logtype_driver,
236 "RNDIS type %#x len %u\n",
244 static int hn_nvs_send_rndis_ctrl(struct vmbus_channel *chan,
245 const void *req, uint32_t reqlen)
248 struct hn_nvs_rndis nvs_rndis = {
249 .type = NVS_TYPE_RNDIS,
250 .rndis_mtype = NVS_RNDIS_MTYPE_CTRL,
251 .chim_idx = NVS_CHIM_IDX_INVALID,
257 addr = rte_malloc_virt2iova(req);
258 if (unlikely(addr == RTE_BAD_IOVA)) {
259 PMD_DRV_LOG(ERR, "RNDIS send request can not get iova");
263 if (unlikely(reqlen > PAGE_SIZE)) {
264 PMD_DRV_LOG(ERR, "RNDIS request %u greater than page size",
269 sg.page = addr / PAGE_SIZE;
270 sg.ofs = addr & PAGE_MASK;
273 if (sg.ofs + reqlen > PAGE_SIZE) {
274 PMD_DRV_LOG(ERR, "RNDIS request crosses page bounary");
280 return hn_nvs_send_sglist(chan, &sg, 1,
281 &nvs_rndis, sizeof(nvs_rndis), 0U, NULL);
284 void hn_rndis_link_status(struct hn_data *hv __rte_unused, const void *msg)
286 const struct rndis_status_msg *indicate = msg;
290 PMD_DRV_LOG(DEBUG, "link status %#x", indicate->status);
292 switch (indicate->status) {
293 case RNDIS_STATUS_LINK_SPEED_CHANGE:
294 case RNDIS_STATUS_NETWORK_CHANGE:
295 case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
296 /* ignore not in DPDK API */
299 case RNDIS_STATUS_MEDIA_CONNECT:
300 case RNDIS_STATUS_MEDIA_DISCONNECT:
301 /* TODO handle as LSC interrupt */
304 PMD_DRV_LOG(NOTICE, "unknown RNDIS indication: %#x",
309 /* Callback from hn_process_events when response is visible */
310 void hn_rndis_receive_response(struct hn_data *hv,
311 const void *data, uint32_t len)
313 const struct rndis_init_comp *hdr = data;
317 if (len < sizeof(3 * sizeof(uint32_t))) {
319 "missing RNDIS header %u", len);
323 if (len < hdr->len) {
325 "truncated RNDIS response %u", len);
329 if (len > sizeof(hv->rndis_resp)) {
331 "RNDIS response exceeds buffer");
332 len = sizeof(hv->rndis_resp);
337 "RNDIS response id zero!");
340 memcpy(hv->rndis_resp, data, len);
342 /* make sure response copied before update */
345 if (rte_atomic32_cmpset(&hv->rndis_pending, hdr->rid, 0) == 0) {
347 "received id %#x pending id %#x",
348 hdr->rid, (uint32_t)hv->rndis_pending);
352 /* Do request/response transaction */
353 static int hn_rndis_exec1(struct hn_data *hv,
354 const void *req, uint32_t reqlen,
355 void *comp, uint32_t comp_len)
357 const struct rndis_halt_req *hdr = req;
358 uint32_t rid = hdr->rid;
359 struct vmbus_channel *chan = hn_primary_chan(hv);
362 if (comp_len > sizeof(hv->rndis_resp)) {
364 "Expected completion size %u exceeds buffer %zu",
365 comp_len, sizeof(hv->rndis_resp));
370 rte_atomic32_cmpset(&hv->rndis_pending, 0, rid) == 0) {
372 "Request already pending");
376 error = hn_nvs_send_rndis_ctrl(chan, req, reqlen);
378 PMD_DRV_LOG(ERR, "RNDIS ctrl send failed: %d", error);
383 /* Poll primary channel until response received */
384 while (hv->rndis_pending == rid)
385 hn_process_events(hv, 0);
387 memcpy(comp, hv->rndis_resp, comp_len);
393 /* Do transaction and validate response */
394 static int hn_rndis_execute(struct hn_data *hv, uint32_t rid,
395 const void *req, uint32_t reqlen,
396 void *comp, uint32_t comp_len, uint32_t comp_type)
398 const struct rndis_comp_hdr *hdr = comp;
401 memset(comp, 0, comp_len);
403 ret = hn_rndis_exec1(hv, req, reqlen, comp, comp_len);
407 * Check this RNDIS complete message.
409 if (unlikely(hdr->type != comp_type)) {
411 "unexpected RNDIS response complete %#x expect %#x",
412 hdr->type, comp_type);
416 if (unlikely(hdr->rid != rid)) {
418 "RNDIS comp rid mismatch %#x, expect %#x",
428 hn_rndis_query(struct hn_data *hv, uint32_t oid,
429 const void *idata, uint32_t idlen,
430 void *odata, uint32_t odlen)
432 struct rndis_query_req *req;
433 struct rndis_query_comp *comp;
434 uint32_t reqlen, comp_len;
439 reqlen = sizeof(*req) + idlen;
440 req = hn_rndis_alloc(hv, reqlen);
444 comp_len = sizeof(*comp) + odlen;
445 comp = rte_zmalloc("QUERY", comp_len, PAGE_SIZE);
450 comp->status = RNDIS_STATUS_PENDING;
452 rid = hn_rndis_rid(hv);
454 req->type = RNDIS_QUERY_MSG;
458 req->infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
459 req->infobuflen = idlen;
461 /* Input data immediately follows RNDIS query. */
462 memcpy(req + 1, idata, idlen);
464 error = hn_rndis_execute(hv, rid, req, reqlen,
465 comp, comp_len, RNDIS_QUERY_CMPLT);
470 if (comp->status != RNDIS_STATUS_SUCCESS) {
471 PMD_DRV_LOG(ERR, "RNDIS query 0x%08x failed: status 0x%08x",
477 if (comp->infobuflen == 0 || comp->infobufoffset == 0) {
478 /* No output data! */
479 PMD_DRV_LOG(ERR, "RNDIS query 0x%08x, no data", oid);
485 * Check output data length and offset.
487 /* ofs is the offset from the beginning of comp. */
488 ofs = RNDIS_QUERY_COMP_INFOBUFOFFSET_ABS(comp->infobufoffset);
489 if (ofs < sizeof(*comp) || ofs + comp->infobuflen > comp_len) {
490 PMD_DRV_LOG(ERR, "RNDIS query invalid comp ib off/len, %u/%u",
491 comp->infobufoffset, comp->infobuflen);
496 /* Save output data. */
497 if (comp->infobuflen < odlen)
498 odlen = comp->infobuflen;
500 /* ofs is the offset from the beginning of comp. */
501 memcpy(odata, (const char *)comp + ofs, odlen);
511 hn_rndis_halt(struct hn_data *hv)
513 struct rndis_halt_req *halt;
515 halt = hn_rndis_alloc(hv, sizeof(*halt));
519 halt->type = RNDIS_HALT_MSG;
520 halt->len = sizeof(*halt);
521 halt->rid = hn_rndis_rid(hv);
523 /* No RNDIS completion; rely on NVS message send completion */
524 hn_rndis_exec1(hv, halt, sizeof(*halt), NULL, 0);
528 PMD_INIT_LOG(DEBUG, "RNDIS halt done");
533 hn_rndis_query_hwcaps(struct hn_data *hv, struct ndis_offload *caps)
535 struct ndis_offload in;
536 uint32_t caps_len, size;
539 memset(caps, 0, sizeof(*caps));
540 memset(&in, 0, sizeof(in));
541 in.ndis_hdr.ndis_type = NDIS_OBJTYPE_OFFLOAD;
543 if (hv->ndis_ver >= NDIS_VERSION_6_30) {
544 in.ndis_hdr.ndis_rev = NDIS_OFFLOAD_REV_3;
545 size = NDIS_OFFLOAD_SIZE;
546 } else if (hv->ndis_ver >= NDIS_VERSION_6_1) {
547 in.ndis_hdr.ndis_rev = NDIS_OFFLOAD_REV_2;
548 size = NDIS_OFFLOAD_SIZE_6_1;
550 in.ndis_hdr.ndis_rev = NDIS_OFFLOAD_REV_1;
551 size = NDIS_OFFLOAD_SIZE_6_0;
553 in.ndis_hdr.ndis_size = size;
555 caps_len = NDIS_OFFLOAD_SIZE;
556 error = hn_rndis_query(hv, OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES,
557 &in, size, caps, caps_len);
561 /* Preliminary verification. */
562 if (caps->ndis_hdr.ndis_type != NDIS_OBJTYPE_OFFLOAD) {
563 PMD_DRV_LOG(NOTICE, "invalid NDIS objtype 0x%02x",
564 caps->ndis_hdr.ndis_type);
567 if (caps->ndis_hdr.ndis_rev < NDIS_OFFLOAD_REV_1) {
568 PMD_DRV_LOG(NOTICE, "invalid NDIS objrev 0x%02x",
569 caps->ndis_hdr.ndis_rev);
572 if (caps->ndis_hdr.ndis_size > caps_len) {
573 PMD_DRV_LOG(NOTICE, "invalid NDIS objsize %u, data size %u",
574 caps->ndis_hdr.ndis_size, caps_len);
576 } else if (caps->ndis_hdr.ndis_size < NDIS_OFFLOAD_SIZE_6_0) {
577 PMD_DRV_LOG(NOTICE, "invalid NDIS objsize %u",
578 caps->ndis_hdr.ndis_size);
586 hn_rndis_query_rsscaps(struct hn_data *hv,
587 unsigned int *rxr_cnt0)
589 struct ndis_rss_caps in, caps;
590 unsigned int indsz, rxr_cnt;
596 if (hv->ndis_ver < NDIS_VERSION_6_20) {
597 PMD_DRV_LOG(DEBUG, "RSS not supported on this host");
601 memset(&in, 0, sizeof(in));
602 in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
603 in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
604 in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
606 caps_len = NDIS_RSS_CAPS_SIZE;
607 error = hn_rndis_query(hv, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
608 &in, NDIS_RSS_CAPS_SIZE,
613 PMD_INIT_LOG(DEBUG, "RX rings %u indirect %u caps %#x",
614 caps.ndis_nrxr, caps.ndis_nind, caps.ndis_caps);
616 * Preliminary verification.
618 if (caps.ndis_hdr.ndis_type != NDIS_OBJTYPE_RSS_CAPS) {
619 PMD_DRV_LOG(ERR, "invalid NDIS objtype 0x%02x",
620 caps.ndis_hdr.ndis_type);
623 if (caps.ndis_hdr.ndis_rev < NDIS_RSS_CAPS_REV_1) {
624 PMD_DRV_LOG(ERR, "invalid NDIS objrev 0x%02x",
625 caps.ndis_hdr.ndis_rev);
628 if (caps.ndis_hdr.ndis_size > caps_len) {
630 "invalid NDIS objsize %u, data size %u",
631 caps.ndis_hdr.ndis_size, caps_len);
633 } else if (caps.ndis_hdr.ndis_size < NDIS_RSS_CAPS_SIZE_6_0) {
634 PMD_DRV_LOG(ERR, "invalid NDIS objsize %u",
635 caps.ndis_hdr.ndis_size);
640 * Save information for later RSS configuration.
642 if (caps.ndis_nrxr == 0) {
643 PMD_DRV_LOG(ERR, "0 RX rings!?");
646 rxr_cnt = caps.ndis_nrxr;
648 if (caps.ndis_hdr.ndis_size == NDIS_RSS_CAPS_SIZE &&
649 caps.ndis_hdr.ndis_rev >= NDIS_RSS_CAPS_REV_2) {
650 if (caps.ndis_nind > NDIS_HASH_INDCNT) {
652 "too many RSS indirect table entries %u",
656 if (!rte_is_power_of_2(caps.ndis_nind)) {
658 "RSS indirect table size is not power-of-2 %u",
662 indsz = caps.ndis_nind;
664 indsz = NDIS_HASH_INDCNT;
667 if (indsz < rxr_cnt) {
669 "# of RX rings (%d) > RSS indirect table size %d",
674 hv->rss_offloads = 0;
675 if (caps.ndis_caps & NDIS_RSS_CAP_IPV4)
676 hv->rss_offloads |= ETH_RSS_IPV4
677 | ETH_RSS_NONFRAG_IPV4_TCP
678 | ETH_RSS_NONFRAG_IPV4_UDP;
679 if (caps.ndis_caps & NDIS_RSS_CAP_IPV6)
680 hv->rss_offloads |= ETH_RSS_IPV6
681 | ETH_RSS_NONFRAG_IPV6_TCP;
682 if (caps.ndis_caps & NDIS_RSS_CAP_IPV6_EX)
683 hv->rss_offloads |= ETH_RSS_IPV6_EX
684 | ETH_RSS_IPV6_TCP_EX;
693 hn_rndis_set(struct hn_data *hv, uint32_t oid, const void *data, uint32_t dlen)
695 struct rndis_set_req *req;
696 struct rndis_set_comp comp;
697 uint32_t reqlen, comp_len;
701 reqlen = sizeof(*req) + dlen;
702 req = rte_zmalloc("RNDIS_SET", reqlen, PAGE_SIZE);
706 rid = hn_rndis_rid(hv);
707 req->type = RNDIS_SET_MSG;
711 req->infobuflen = dlen;
712 req->infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET;
714 /* Data immediately follows RNDIS set. */
715 memcpy(req + 1, data, dlen);
717 comp_len = sizeof(comp);
718 error = hn_rndis_execute(hv, rid, req, reqlen,
722 PMD_DRV_LOG(ERR, "exec RNDIS set %#" PRIx32 " failed",
728 if (comp.status != RNDIS_STATUS_SUCCESS) {
730 "RNDIS set %#" PRIx32 " failed: status %#" PRIx32,
741 int hn_rndis_conf_offload(struct hn_data *hv,
742 uint64_t tx_offloads, uint64_t rx_offloads)
744 struct ndis_offload_params params;
745 struct ndis_offload hwcaps;
748 error = hn_rndis_query_hwcaps(hv, &hwcaps);
750 PMD_DRV_LOG(ERR, "hwcaps query failed: %d", error);
754 /* NOTE: 0 means "no change" */
755 memset(¶ms, 0, sizeof(params));
757 params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
758 if (hv->ndis_ver < NDIS_VERSION_6_30) {
759 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
760 params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
762 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
763 params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE;
766 if (tx_offloads & DEV_TX_OFFLOAD_TCP_CKSUM) {
767 if (hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_TCP4)
768 params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TX;
772 if (hwcaps.ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_TCP6)
773 params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TX;
778 if (rx_offloads & DEV_RX_OFFLOAD_TCP_CKSUM) {
779 if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4)
780 == NDIS_RXCSUM_CAP_TCP4)
781 params.ndis_tcp4csum |= NDIS_OFFLOAD_PARAM_RX;
785 if ((hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6)
786 == NDIS_RXCSUM_CAP_TCP6)
787 params.ndis_tcp6csum |= NDIS_OFFLOAD_PARAM_RX;
792 if (tx_offloads & DEV_TX_OFFLOAD_UDP_CKSUM) {
793 if (hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_UDP4)
794 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TX;
798 if ((hwcaps.ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_UDP6)
799 == NDIS_TXCSUM_CAP_UDP6)
800 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TX;
805 if (rx_offloads & DEV_TX_OFFLOAD_UDP_CKSUM) {
806 if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4)
807 params.ndis_udp4csum |= NDIS_OFFLOAD_PARAM_RX;
811 if (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6)
812 params.ndis_udp6csum |= NDIS_OFFLOAD_PARAM_RX;
817 if (tx_offloads & DEV_TX_OFFLOAD_IPV4_CKSUM) {
818 if ((hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_IP4)
819 == NDIS_TXCSUM_CAP_IP4)
820 params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TX;
824 if (rx_offloads & DEV_RX_OFFLOAD_IPV4_CKSUM) {
825 if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)
826 params.ndis_ip4csum |= NDIS_OFFLOAD_PARAM_RX;
831 if (tx_offloads & DEV_TX_OFFLOAD_TCP_TSO) {
832 if (hwcaps.ndis_lsov2.ndis_ip4_encap & NDIS_OFFLOAD_ENCAP_8023)
833 params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
837 if ((hwcaps.ndis_lsov2.ndis_ip6_opts & HN_NDIS_LSOV2_CAP_IP6)
838 == HN_NDIS_LSOV2_CAP_IP6)
839 params.ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON;
844 error = hn_rndis_set(hv, OID_TCP_OFFLOAD_PARAMETERS, ¶ms,
845 params.ndis_hdr.ndis_size);
847 PMD_DRV_LOG(ERR, "offload config failed");
854 "offload tx:%" PRIx64 " rx:%" PRIx64 " not supported by this version",
855 tx_offloads, rx_offloads);
859 int hn_rndis_get_offload(struct hn_data *hv,
860 struct rte_eth_dev_info *dev_info)
862 struct ndis_offload hwcaps;
865 memset(&hwcaps, 0, sizeof(hwcaps));
867 error = hn_rndis_query_hwcaps(hv, &hwcaps);
869 PMD_DRV_LOG(ERR, "hwcaps query failed: %d", error);
873 dev_info->tx_offload_capa = DEV_TX_OFFLOAD_MULTI_SEGS |
874 DEV_TX_OFFLOAD_VLAN_INSERT;
876 if ((hwcaps.ndis_csum.ndis_ip4_txcsum & HN_NDIS_TXCSUM_CAP_IP4)
877 == HN_NDIS_TXCSUM_CAP_IP4)
878 dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_IPV4_CKSUM;
880 if ((hwcaps.ndis_csum.ndis_ip4_txcsum & HN_NDIS_TXCSUM_CAP_TCP4)
881 == HN_NDIS_TXCSUM_CAP_TCP4 &&
882 (hwcaps.ndis_csum.ndis_ip6_txcsum & HN_NDIS_TXCSUM_CAP_TCP6)
883 == HN_NDIS_TXCSUM_CAP_TCP6)
884 dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_TCP_CKSUM;
886 if ((hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_UDP4) &&
887 (hwcaps.ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_UDP6))
888 dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_UDP_CKSUM;
890 if ((hwcaps.ndis_lsov2.ndis_ip4_encap & NDIS_OFFLOAD_ENCAP_8023) &&
891 (hwcaps.ndis_lsov2.ndis_ip6_opts & HN_NDIS_LSOV2_CAP_IP6)
892 == HN_NDIS_LSOV2_CAP_IP6)
893 dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_TCP_TSO;
895 dev_info->rx_offload_capa = DEV_RX_OFFLOAD_VLAN_STRIP |
896 DEV_RX_OFFLOAD_CRC_STRIP;
898 if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)
899 dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_IPV4_CKSUM;
901 if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4) &&
902 (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6))
903 dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_TCP_CKSUM;
905 if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4) &&
906 (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6))
907 dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_UDP_CKSUM;
913 hn_rndis_set_rxfilter(struct hn_data *hv, uint32_t filter)
917 error = hn_rndis_set(hv, OID_GEN_CURRENT_PACKET_FILTER,
918 &filter, sizeof(filter));
920 PMD_DRV_LOG(ERR, "set RX filter %#" PRIx32 " failed: %d",
923 PMD_DRV_LOG(DEBUG, "set RX filter %#" PRIx32 " done", filter);
929 /* The default RSS key.
930 * This value is the same as MLX5 so that flows will be
931 * received on same path for both VF ans synthetic NIC.
933 static const uint8_t rss_default_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
934 0x2c, 0xc6, 0x81, 0xd1, 0x5b, 0xdb, 0xf4, 0xf7,
935 0xfc, 0xa2, 0x83, 0x19, 0xdb, 0x1a, 0x3e, 0x94,
936 0x6b, 0x9e, 0x38, 0xd9, 0x2c, 0x9c, 0x03, 0xd1,
937 0xad, 0x99, 0x44, 0xa7, 0xd9, 0x56, 0x3d, 0x59,
938 0x06, 0x3c, 0x25, 0xf3, 0xfc, 0x1f, 0xdc, 0x2a,
941 int hn_rndis_conf_rss(struct hn_data *hv,
942 const struct rte_eth_rss_conf *rss_conf)
944 struct ndis_rssprm_toeplitz rssp;
945 struct ndis_rss_params *prm = &rssp.rss_params;
946 const uint8_t *rss_key = rss_conf->rss_key ? : rss_default_key;
951 PMD_INIT_FUNC_TRACE();
953 memset(&rssp, 0, sizeof(rssp));
955 prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
956 prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
957 prm->ndis_hdr.ndis_size = sizeof(*prm);
960 rss_hash = NDIS_HASH_FUNCTION_TOEPLITZ;
961 if (rss_conf->rss_hf & ETH_RSS_IPV4)
962 rss_hash |= NDIS_HASH_IPV4;
963 if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_TCP)
964 rss_hash |= NDIS_HASH_TCP_IPV4;
965 if (rss_conf->rss_hf & ETH_RSS_IPV6)
966 rss_hash |= NDIS_HASH_IPV6;
967 if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV6_TCP)
968 rss_hash |= NDIS_HASH_TCP_IPV6;
970 prm->ndis_hash = rss_hash;
971 prm->ndis_indsize = sizeof(rssp.rss_ind[0]) * NDIS_HASH_INDCNT;
972 prm->ndis_indoffset = offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
973 prm->ndis_keysize = NDIS_HASH_KEYSIZE_TOEPLITZ;
974 prm->ndis_keyoffset = offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
976 for (i = 0; i < NDIS_HASH_INDCNT; i++)
977 rssp.rss_ind[i] = i % hv->num_queues;
979 /* Set hask key values */
980 memcpy(&rssp.rss_key, rss_key, NDIS_HASH_KEYSIZE_TOEPLITZ);
982 error = hn_rndis_set(hv, OID_GEN_RECEIVE_SCALE_PARAMETERS,
983 &rssp, sizeof(rssp));
986 "RSS config num queues=%u failed: %d",
987 hv->num_queues, error);
992 static int hn_rndis_init(struct hn_data *hv)
994 struct rndis_init_req *req;
995 struct rndis_init_comp comp;
996 uint32_t comp_len, rid;
999 req = hn_rndis_alloc(hv, sizeof(*req));
1001 PMD_DRV_LOG(ERR, "no memory for RNDIS init");
1005 rid = hn_rndis_rid(hv);
1006 req->type = RNDIS_INITIALIZE_MSG;
1007 req->len = sizeof(*req);
1009 req->ver_major = RNDIS_VERSION_MAJOR;
1010 req->ver_minor = RNDIS_VERSION_MINOR;
1011 req->max_xfersz = HN_RNDIS_XFER_SIZE;
1013 comp_len = RNDIS_INIT_COMP_SIZE_MIN;
1014 error = hn_rndis_execute(hv, rid, req, sizeof(*req),
1016 RNDIS_INITIALIZE_CMPLT);
1020 if (comp.status != RNDIS_STATUS_SUCCESS) {
1021 PMD_DRV_LOG(ERR, "RNDIS init failed: status 0x%08x",
1027 hv->rndis_agg_size = comp.pktmaxsz;
1028 hv->rndis_agg_pkts = comp.pktmaxcnt;
1029 hv->rndis_agg_align = 1U << comp.align;
1031 if (hv->rndis_agg_align < sizeof(uint32_t)) {
1033 * The RNDIS packet message encap assumes that the RNDIS
1034 * packet message is at least 4 bytes aligned. Fix up the
1035 * alignment here, if the remote side sets the alignment
1039 "fixup RNDIS aggpkt align: %u -> %zu",
1040 hv->rndis_agg_align, sizeof(uint32_t));
1041 hv->rndis_agg_align = sizeof(uint32_t);
1045 "RNDIS ver %u.%u, aggpkt size %u, aggpkt cnt %u, aggpkt align %u",
1046 comp.ver_major, comp.ver_minor,
1047 hv->rndis_agg_size, hv->rndis_agg_pkts,
1048 hv->rndis_agg_align);
1056 hn_rndis_get_eaddr(struct hn_data *hv, uint8_t *eaddr)
1061 eaddr_len = ETHER_ADDR_LEN;
1062 error = hn_rndis_query(hv, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
1067 PMD_DRV_LOG(INFO, "MAC address %02x:%02x:%02x:%02x:%02x:%02x",
1068 eaddr[0], eaddr[1], eaddr[2],
1069 eaddr[3], eaddr[4], eaddr[5]);
1074 hn_rndis_get_linkstatus(struct hn_data *hv)
1076 return hn_rndis_query(hv, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,
1077 &hv->link_status, sizeof(uint32_t));
1081 hn_rndis_get_linkspeed(struct hn_data *hv)
1083 return hn_rndis_query(hv, OID_GEN_LINK_SPEED, NULL, 0,
1084 &hv->link_speed, sizeof(uint32_t));
1088 hn_rndis_attach(struct hn_data *hv)
1090 /* Initialize RNDIS. */
1091 return hn_rndis_init(hv);
1095 hn_rndis_detach(struct hn_data *hv)
1097 /* Halt the RNDIS. */