]> git.droids-corp.org - dpdk.git/commitdiff
net/virtio: fix link update in speed feature
authorIvan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Fri, 22 Oct 2021 13:17:54 +0000 (16:17 +0300)
committerMaxime Coquelin <maxime.coquelin@redhat.com>
Fri, 29 Oct 2021 10:32:30 +0000 (12:32 +0200)
Link update callback reports speed/duplex based on data
filled on device initialization. This is wrong in case of
VIRTIO_NET_F_SPEED_DUPLEX is negotiated since link could
be down at this time. Fix this function to actually
update the HW data in this case with respect to the fact
that specifying speed via devarg is a highest priority.

Fixes: 1357b4b36246 ("net/virtio: support Virtio link speed feature")
Cc: stable@dpdk.org
Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Maxime Coquelin <maxime.coquelin@redhat.com>
drivers/net/virtio/virtio.h
drivers/net/virtio/virtio_ethdev.c

index 9a2ab2caeae4883170a6b377da906ac86a1aa698..5c8f71a44df3ddd4d975a438e03cef71d41063a7 100644 (file)
@@ -203,6 +203,11 @@ struct virtio_hw {
        uint8_t opened;
        uint16_t port_id;
        uint8_t mac_addr[RTE_ETHER_ADDR_LEN];
+       /*
+        * Speed is specified via 'speed' devarg or
+        * negotiated via VIRTIO_NET_F_SPEED_DUPLEX
+        */
+       bool get_speed_via_feat;
        uint32_t speed;  /* link speed in MB */
        uint8_t duplex;
        uint8_t intr_lsc;
index 4570bec057d106d678d71b819844056738596070..c2588369b252494318cc96632cd24b33503b5c74 100644 (file)
@@ -1843,6 +1843,31 @@ virtio_configure_intr(struct rte_eth_dev *dev)
        return 0;
 }
 
+static void
+virtio_get_speed_duplex(struct rte_eth_dev *eth_dev,
+                       struct rte_eth_link *link)
+{
+       struct virtio_hw *hw = eth_dev->data->dev_private;
+       struct virtio_net_config *config;
+       struct virtio_net_config local_config;
+
+       config = &local_config;
+       virtio_read_dev_config(hw,
+               offsetof(struct virtio_net_config, speed),
+               &config->speed, sizeof(config->speed));
+       virtio_read_dev_config(hw,
+               offsetof(struct virtio_net_config, duplex),
+               &config->duplex, sizeof(config->duplex));
+       hw->speed = config->speed;
+       hw->duplex = config->duplex;
+       if (link != NULL) {
+               link->link_duplex = hw->duplex;
+               link->link_speed  = hw->speed;
+       }
+       PMD_INIT_LOG(DEBUG, "link speed = %d, duplex = %d",
+                    hw->speed, hw->duplex);
+}
+
 static uint64_t
 ethdev_to_virtio_rss_offloads(uint64_t ethdev_hash_types)
 {
@@ -2225,19 +2250,10 @@ virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features)
                     hw->mac_addr[0], hw->mac_addr[1], hw->mac_addr[2],
                     hw->mac_addr[3], hw->mac_addr[4], hw->mac_addr[5]);
 
-       if (hw->speed == RTE_ETH_SPEED_NUM_UNKNOWN) {
-               if (virtio_with_feature(hw, VIRTIO_NET_F_SPEED_DUPLEX)) {
-                       config = &local_config;
-                       virtio_read_dev_config(hw,
-                               offsetof(struct virtio_net_config, speed),
-                               &config->speed, sizeof(config->speed));
-                       virtio_read_dev_config(hw,
-                               offsetof(struct virtio_net_config, duplex),
-                               &config->duplex, sizeof(config->duplex));
-                       hw->speed = config->speed;
-                       hw->duplex = config->duplex;
-               }
-       }
+       hw->get_speed_via_feat = hw->speed == RTE_ETH_SPEED_NUM_UNKNOWN &&
+                            virtio_with_feature(hw, VIRTIO_NET_F_SPEED_DUPLEX);
+       if (hw->get_speed_via_feat)
+               virtio_get_speed_duplex(eth_dev, NULL);
        if (hw->duplex == DUPLEX_UNKNOWN)
                hw->duplex = RTE_ETH_LINK_FULL_DUPLEX;
        PMD_INIT_LOG(DEBUG, "link speed = %d, duplex = %d",
@@ -2964,11 +2980,15 @@ virtio_dev_link_update(struct rte_eth_dev *dev, __rte_unused int wait_to_complet
                                     dev->data->port_id);
                } else {
                        link.link_status = RTE_ETH_LINK_UP;
+                       if (hw->get_speed_via_feat)
+                               virtio_get_speed_duplex(dev, &link);
                        PMD_INIT_LOG(DEBUG, "Port %d is up",
                                     dev->data->port_id);
                }
        } else {
                link.link_status = RTE_ETH_LINK_UP;
+               if (hw->get_speed_via_feat)
+                       virtio_get_speed_duplex(dev, &link);
        }
 
        return rte_eth_linkstatus_set(dev, &link);