net/ice/base: add command to LLDP
[dpdk.git] / drivers / net / netvsc / hn_rndis.c
index bde3396..d186dde 100644 (file)
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
+#include <time.h>
 
+#include <rte_ethdev_driver.h>
 #include <rte_ethdev.h>
 #include <rte_string_fns.h>
 #include <rte_memzone.h>
 #include <rte_malloc.h>
 #include <rte_atomic.h>
+#include <rte_alarm.h>
 #include <rte_branch_prediction.h>
 #include <rte_ether.h>
 #include <rte_common.h>
@@ -32,6 +35,9 @@
 #include "hn_rndis.h"
 #include "ndis.h"
 
+#define RNDIS_TIMEOUT_SEC 5
+#define RNDIS_DELAY_MS    10
+
 #define HN_RNDIS_XFER_SIZE             0x4000
 
 #define HN_NDIS_TXCSUM_CAP_IP4         \
@@ -59,10 +65,9 @@ hn_rndis_rid(struct hn_data *hv)
        return rid;
 }
 
-static void *hn_rndis_alloc(struct hn_data *hv, size_t size)
+static void *hn_rndis_alloc(size_t size)
 {
-       return rte_zmalloc_socket("RNDIS", size, PAGE_SIZE,
-                                hv->vmbus->device.numa_node);
+       return rte_zmalloc("RNDIS", size, PAGE_SIZE);
 }
 
 #ifdef RTE_LIBRTE_NETVSC_DEBUG_DUMP
@@ -281,7 +286,16 @@ static int hn_nvs_send_rndis_ctrl(struct vmbus_channel *chan,
                                  &nvs_rndis, sizeof(nvs_rndis), 0U, NULL);
 }
 
-void hn_rndis_link_status(struct hn_data *hv __rte_unused, const void *msg)
+/*
+ * Alarm callback to process link changed notifications.
+ * Can not directly since link_status is discovered while reading ring
+ */
+static void hn_rndis_link_alarm(void *arg)
+{
+       _rte_eth_dev_callback_process(arg, RTE_ETH_EVENT_INTR_LSC, NULL);
+}
+
+void hn_rndis_link_status(struct rte_eth_dev *dev, const void *msg)
 {
        const struct rndis_status_msg *indicate = msg;
 
@@ -290,15 +304,16 @@ void hn_rndis_link_status(struct hn_data *hv __rte_unused, const void *msg)
        PMD_DRV_LOG(DEBUG, "link status %#x", indicate->status);
 
        switch (indicate->status) {
-       case RNDIS_STATUS_LINK_SPEED_CHANGE:
        case RNDIS_STATUS_NETWORK_CHANGE:
        case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
                /* ignore not in DPDK API */
                break;
 
+       case RNDIS_STATUS_LINK_SPEED_CHANGE:
        case RNDIS_STATUS_MEDIA_CONNECT:
        case RNDIS_STATUS_MEDIA_DISCONNECT:
-               /* TODO handle as LSC interrupt  */
+               if (dev->data->dev_conf.intr_conf.lsc)
+                       rte_eal_alarm_set(10, hn_rndis_link_alarm, dev);
                break;
        default:
                PMD_DRV_LOG(NOTICE, "unknown RNDIS indication: %#x",
@@ -343,7 +358,7 @@ void hn_rndis_receive_response(struct hn_data *hv,
        rte_smp_wmb();
 
        if (rte_atomic32_cmpset(&hv->rndis_pending, hdr->rid, 0) == 0) {
-               PMD_DRV_LOG(ERR,
+               PMD_DRV_LOG(NOTICE,
                            "received id %#x pending id %#x",
                            hdr->rid, (uint32_t)hv->rndis_pending);
        }
@@ -366,6 +381,11 @@ static int hn_rndis_exec1(struct hn_data *hv,
                return -EIO;
        }
 
+       if (rid == 0) {
+               PMD_DRV_LOG(ERR, "Invalid request id");
+               return -EINVAL;
+       }
+
        if (comp != NULL &&
            rte_atomic32_cmpset(&hv->rndis_pending, 0, rid) == 0) {
                PMD_DRV_LOG(ERR,
@@ -380,9 +400,26 @@ static int hn_rndis_exec1(struct hn_data *hv,
        }
 
        if (comp) {
+               time_t start = time(NULL);
+
                /* Poll primary channel until response received */
-               while (hv->rndis_pending == rid)
-                       hn_process_events(hv, 0);
+               while (hv->rndis_pending == rid) {
+                       if (hv->closed)
+                               return -ENETDOWN;
+
+                       if (time(NULL) - start > RNDIS_TIMEOUT_SEC) {
+                               PMD_DRV_LOG(ERR,
+                                           "RNDIS response timed out");
+
+                               rte_atomic32_cmpset(&hv->rndis_pending, rid, 0);
+                               return -ETIMEDOUT;
+                       }
+
+                       if (rte_vmbus_chan_rx_empty(hv->primary->chan))
+                               rte_delay_ms(RNDIS_DELAY_MS);
+
+                       hn_process_events(hv, 0, 1);
+               }
 
                memcpy(comp, hv->rndis_resp, comp_len);
        }
@@ -437,7 +474,7 @@ hn_rndis_query(struct hn_data *hv, uint32_t oid,
        uint32_t rid;
 
        reqlen = sizeof(*req) + idlen;
-       req = hn_rndis_alloc(hv, reqlen);
+       req = hn_rndis_alloc(reqlen);
        if (req == NULL)
                return -ENOMEM;
 
@@ -512,7 +549,7 @@ hn_rndis_halt(struct hn_data *hv)
 {
        struct rndis_halt_req *halt;
 
-       halt = hn_rndis_alloc(hv, sizeof(*halt));
+       halt = hn_rndis_alloc(sizeof(*halt));
        if (halt == NULL)
                return -ENOMEM;
 
@@ -893,7 +930,7 @@ int hn_rndis_get_offload(struct hn_data *hv,
                dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_TCP_TSO;
 
        dev_info->rx_offload_capa = DEV_RX_OFFLOAD_VLAN_STRIP |
-                                   DEV_RX_OFFLOAD_CRC_STRIP;
+                                   DEV_RX_OFFLOAD_RSS_HASH;
 
        if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)
                dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_IPV4_CKSUM;
@@ -909,6 +946,37 @@ int hn_rndis_get_offload(struct hn_data *hv,
        return 0;
 }
 
+uint32_t
+hn_rndis_get_ptypes(struct hn_data *hv)
+{
+       struct ndis_offload hwcaps;
+       uint32_t ptypes;
+       int error;
+
+       memset(&hwcaps, 0, sizeof(hwcaps));
+
+       error = hn_rndis_query_hwcaps(hv, &hwcaps);
+       if (error) {
+               PMD_DRV_LOG(ERR, "hwcaps query failed: %d", error);
+               return RTE_PTYPE_L2_ETHER;
+       }
+
+       ptypes = RTE_PTYPE_L2_ETHER;
+
+       if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)
+               ptypes |= RTE_PTYPE_L3_IPV4;
+
+       if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4) ||
+           (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6))
+               ptypes |= RTE_PTYPE_L4_TCP;
+
+       if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4) ||
+           (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6))
+               ptypes |= RTE_PTYPE_L4_UDP;
+
+       return ptypes;
+}
+
 int
 hn_rndis_set_rxfilter(struct hn_data *hv, uint32_t filter)
 {
@@ -926,62 +994,34 @@ hn_rndis_set_rxfilter(struct hn_data *hv, uint32_t filter)
        return error;
 }
 
-/* The default RSS key.
- * This value is the same as MLX5 so that flows will be
- * received on same path for both VF ans synthetic NIC.
- */
-static const uint8_t rss_default_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
-       0x2c, 0xc6, 0x81, 0xd1, 0x5b, 0xdb, 0xf4, 0xf7,
-       0xfc, 0xa2, 0x83, 0x19, 0xdb, 0x1a, 0x3e, 0x94,
-       0x6b, 0x9e, 0x38, 0xd9, 0x2c, 0x9c, 0x03, 0xd1,
-       0xad, 0x99, 0x44, 0xa7, 0xd9, 0x56, 0x3d, 0x59,
-       0x06, 0x3c, 0x25, 0xf3, 0xfc, 0x1f, 0xdc, 0x2a,
-};
-
-int hn_rndis_conf_rss(struct hn_data *hv,
-                     const struct rte_eth_rss_conf *rss_conf)
+int hn_rndis_conf_rss(struct hn_data *hv, uint32_t flags)
 {
        struct ndis_rssprm_toeplitz rssp;
        struct ndis_rss_params *prm = &rssp.rss_params;
-       const uint8_t *rss_key = rss_conf->rss_key ? : rss_default_key;
-       uint32_t rss_hash;
        unsigned int i;
        int error;
 
-       PMD_INIT_FUNC_TRACE();
-
        memset(&rssp, 0, sizeof(rssp));
 
        prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
        prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
        prm->ndis_hdr.ndis_size = sizeof(*prm);
-       prm->ndis_flags = 0;
-
-       rss_hash = NDIS_HASH_FUNCTION_TOEPLITZ;
-       if (rss_conf->rss_hf & ETH_RSS_IPV4)
-               rss_hash |= NDIS_HASH_IPV4;
-       if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_TCP)
-               rss_hash |= NDIS_HASH_TCP_IPV4;
-       if (rss_conf->rss_hf & ETH_RSS_IPV6)
-               rss_hash |=  NDIS_HASH_IPV6;
-       if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV6_TCP)
-               rss_hash |= NDIS_HASH_TCP_IPV6;
-
-       prm->ndis_hash = rss_hash;
+       prm->ndis_flags = flags;
+       prm->ndis_hash = hv->rss_hash;
        prm->ndis_indsize = sizeof(rssp.rss_ind[0]) * NDIS_HASH_INDCNT;
        prm->ndis_indoffset = offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
        prm->ndis_keysize = NDIS_HASH_KEYSIZE_TOEPLITZ;
        prm->ndis_keyoffset = offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
 
        for (i = 0; i < NDIS_HASH_INDCNT; i++)
-               rssp.rss_ind[i] = i % hv->num_queues;
+               rssp.rss_ind[i] = hv->rss_ind[i];
 
        /* Set hask key values */
-       memcpy(&rssp.rss_key, rss_key, NDIS_HASH_KEYSIZE_TOEPLITZ);
+       memcpy(&rssp.rss_key, hv->rss_key, NDIS_HASH_KEYSIZE_TOEPLITZ);
 
        error = hn_rndis_set(hv, OID_GEN_RECEIVE_SCALE_PARAMETERS,
                             &rssp, sizeof(rssp));
-       if (error) {
+       if (error != 0) {
                PMD_DRV_LOG(ERR,
                            "RSS config num queues=%u failed: %d",
                            hv->num_queues, error);
@@ -996,7 +1036,7 @@ static int hn_rndis_init(struct hn_data *hv)
        uint32_t comp_len, rid;
        int error;
 
-       req = hn_rndis_alloc(hv, sizeof(*req));
+       req = hn_rndis_alloc(sizeof(*req));
        if (!req) {
                PMD_DRV_LOG(ERR, "no memory for RNDIS init");
                return -ENXIO;
@@ -1058,7 +1098,7 @@ hn_rndis_get_eaddr(struct hn_data *hv, uint8_t *eaddr)
        uint32_t eaddr_len;
        int error;
 
-       eaddr_len = ETHER_ADDR_LEN;
+       eaddr_len = RTE_ETHER_ADDR_LEN;
        error = hn_rndis_query(hv, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
                               eaddr, eaddr_len);
        if (error)
@@ -1094,6 +1134,10 @@ hn_rndis_attach(struct hn_data *hv)
 void
 hn_rndis_detach(struct hn_data *hv)
 {
+       struct rte_eth_dev *dev = &rte_eth_devices[hv->port_id];
+
+       rte_eal_alarm_cancel(hn_rndis_link_alarm, dev);
+
        /* Halt the RNDIS. */
        hn_rndis_halt(hv);
 }