LCOV - code coverage report
Current view: top level - drivers/net/netvsc - hn_rndis.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 382 0.0 %
Date: 2025-10-01 17:51:42 Functions: 0 23 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 225 0.0 %

           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(&params, 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, &params,
     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 : }

Generated by: LCOV version 1.14