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