X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fvirtio%2Fvirtio_ethdev.c;h=4f20e47cf9d41e0e755f94a6ec40cc028291ca1f;hb=3669a1af893088064778f14fba0c2ca88819e095;hp=b1e4cc152f8d24ff41771396421a9519883e6a17;hpb=b628cb242941170c938dec96dec96b65be4c17f9;p=dpdk.git diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index b1e4cc152f..4f20e47cf9 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #include @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -26,6 +28,7 @@ #include #include #include +#include #include "virtio_ethdev.h" #include "virtio_pci.h" @@ -77,6 +80,12 @@ static int virtio_dev_queue_stats_mapping_set( uint8_t stat_idx, uint8_t is_rx); +int virtio_logtype_init; +int virtio_logtype_driver; + +static void virtio_notify_peers(struct rte_eth_dev *dev); +static void virtio_ack_link_announce(struct rte_eth_dev *dev); + /* * The set of PCI devices this driver supports */ @@ -148,6 +157,8 @@ virtio_send_command(struct virtnet_ctl *cvq, struct virtio_pmd_ctrl *ctrl, PMD_INIT_LOG(ERR, "Control queue is not supported."); return -1; } + + rte_spinlock_lock(&cvq->lock); vq = cvq->vq; head = vq->vq_desc_head_idx; @@ -155,8 +166,10 @@ virtio_send_command(struct virtnet_ctl *cvq, struct virtio_pmd_ctrl *ctrl, "vq->hw->cvq = %p vq = %p", vq->vq_desc_head_idx, status, vq->hw->cvq, vq); - if ((vq->vq_free_cnt < ((uint32_t)pkt_num + 2)) || (pkt_num < 1)) + if (vq->vq_free_cnt < pkt_num + 2 || pkt_num < 1) { + rte_spinlock_unlock(&cvq->lock); return -1; + } memcpy(cvq->virtio_net_hdr_mz->addr, ctrl, sizeof(struct virtio_pmd_ctrl)); @@ -232,6 +245,7 @@ virtio_send_command(struct virtnet_ctl *cvq, struct virtio_pmd_ctrl *ctrl, result = cvq->virtio_net_hdr_mz->addr; + rte_spinlock_unlock(&cvq->lock); return result->status; } @@ -265,17 +279,6 @@ virtio_dev_queue_release(void *queue __rte_unused) /* do nothing */ } -static int -virtio_get_queue_type(struct virtio_hw *hw, uint16_t vtpci_queue_idx) -{ - if (vtpci_queue_idx == hw->max_queue_pairs * 2) - return VTNET_CQ; - else if (vtpci_queue_idx % 2 == 0) - return VTNET_RQ; - else - return VTNET_TQ; -} - static uint16_t virtio_get_nr_vq(struct virtio_hw *hw) { @@ -1215,9 +1218,97 @@ virtio_negotiate_features(struct virtio_hw *hw, uint64_t req_features) return 0; } +int +virtio_dev_pause(struct rte_eth_dev *dev) +{ + struct virtio_hw *hw = dev->data->dev_private; + + rte_spinlock_lock(&hw->state_lock); + + if (hw->started == 0) { + /* Device is just stopped. */ + rte_spinlock_unlock(&hw->state_lock); + return -1; + } + hw->started = 0; + /* + * Prevent the worker threads from touching queues to avoid contention, + * 1 ms should be enough for the ongoing Tx function to finish. + */ + rte_delay_ms(1); + return 0; +} + /* - * Process Virtio Config changed interrupt and call the callback - * if link state changed. + * Recover hw state to let the worker threads continue. + */ +void +virtio_dev_resume(struct rte_eth_dev *dev) +{ + struct virtio_hw *hw = dev->data->dev_private; + + hw->started = 1; + rte_spinlock_unlock(&hw->state_lock); +} + +/* + * Should be called only after device is paused. + */ +int +virtio_inject_pkts(struct rte_eth_dev *dev, struct rte_mbuf **tx_pkts, + int nb_pkts) +{ + struct virtio_hw *hw = dev->data->dev_private; + struct virtnet_tx *txvq = dev->data->tx_queues[0]; + int ret; + + hw->inject_pkts = tx_pkts; + ret = dev->tx_pkt_burst(txvq, tx_pkts, nb_pkts); + hw->inject_pkts = NULL; + + return ret; +} + +static void +virtio_notify_peers(struct rte_eth_dev *dev) +{ + struct virtio_hw *hw = dev->data->dev_private; + struct virtnet_rx *rxvq = dev->data->rx_queues[0]; + struct rte_mbuf *rarp_mbuf; + + rarp_mbuf = rte_net_make_rarp_packet(rxvq->mpool, + (struct ether_addr *)hw->mac_addr); + if (rarp_mbuf == NULL) { + PMD_DRV_LOG(ERR, "failed to make RARP packet."); + return; + } + + /* If virtio port just stopped, no need to send RARP */ + if (virtio_dev_pause(dev) < 0) { + rte_pktmbuf_free(rarp_mbuf); + return; + } + + virtio_inject_pkts(dev, &rarp_mbuf, 1); + virtio_dev_resume(dev); +} + +static void +virtio_ack_link_announce(struct rte_eth_dev *dev) +{ + struct virtio_hw *hw = dev->data->dev_private; + struct virtio_pmd_ctrl ctrl; + + ctrl.hdr.class = VIRTIO_NET_CTRL_ANNOUNCE; + ctrl.hdr.cmd = VIRTIO_NET_CTRL_ANNOUNCE_ACK; + + virtio_send_command(hw->cvq, &ctrl, NULL, 0); +} + +/* + * Process virtio config changed interrupt. Call the callback + * if link state changed, generate gratuitous RARP packet if + * the status indicates an ANNOUNCE. */ void virtio_interrupt_handler(void *param) @@ -1237,9 +1328,13 @@ virtio_interrupt_handler(void *param) if (virtio_dev_link_update(dev, 0) == 0) _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, - NULL, NULL); + NULL); } + if (isr & VIRTIO_NET_S_ANNOUNCE) { + virtio_notify_peers(dev); + virtio_ack_link_announce(dev); + } } /* set rx and tx handlers according to what is supported */ @@ -1376,6 +1471,11 @@ virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features) /* Reset the device although not necessary at startup */ vtpci_reset(hw); + if (hw->vqs) { + virtio_dev_free_mbufs(eth_dev); + virtio_free_queues(hw); + } + /* Tell the host we've noticed this device. */ vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_ACK); @@ -1479,6 +1579,8 @@ virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features) } else { PMD_INIT_LOG(DEBUG, "config->max_virtqueue_pairs=1"); hw->max_queue_pairs = 1; + hw->max_mtu = VIRTIO_MAX_RX_PKTLEN - ETHER_HDR_LEN - + VLAN_TAG_LEN - hw->vtnet_hdr_size; } ret = virtio_alloc_queues(eth_dev); @@ -1752,10 +1854,12 @@ virtio_dev_configure(struct rte_eth_dev *dev) return -EBUSY; } + rte_spinlock_init(&hw->state_lock); + hw->use_simple_rx = 1; hw->use_simple_tx = 1; -#if defined RTE_ARCH_ARM64 || defined CONFIG_RTE_ARCH_ARM +#if defined RTE_ARCH_ARM64 || defined RTE_ARCH_ARM if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON)) { hw->use_simple_rx = 0; hw->use_simple_tx = 0; @@ -1869,6 +1973,9 @@ static void virtio_dev_free_mbufs(struct rte_eth_dev *dev) for (i = 0; i < dev->data->nb_rx_queues; i++) { struct virtnet_rx *rxvq = dev->data->rx_queues[i]; + if (rxvq == NULL || rxvq->vq == NULL) + continue; + PMD_INIT_LOG(DEBUG, "Before freeing rxq[%d] used and unused buf", i); VIRTQUEUE_DUMP(rxvq->vq); @@ -1888,6 +1995,9 @@ static void virtio_dev_free_mbufs(struct rte_eth_dev *dev) for (i = 0; i < dev->data->nb_tx_queues; i++) { struct virtnet_tx *txvq = dev->data->tx_queues[i]; + if (txvq == NULL || txvq->vq == NULL) + continue; + PMD_INIT_LOG(DEBUG, "Before freeing txq[%d] used and unused bufs", i); @@ -1918,12 +2028,14 @@ virtio_dev_stop(struct rte_eth_dev *dev) PMD_INIT_LOG(DEBUG, "stop"); + rte_spinlock_lock(&hw->state_lock); if (intr_conf->lsc || intr_conf->rxq) virtio_intr_disable(dev); hw->started = 0; memset(&link, 0, sizeof(link)); virtio_dev_atomic_write_link_status(dev, &link); + rte_spinlock_unlock(&hw->state_lock); } static int @@ -2043,3 +2155,15 @@ __rte_unused uint8_t is_rx) RTE_PMD_EXPORT_NAME(net_virtio, __COUNTER__); RTE_PMD_REGISTER_PCI_TABLE(net_virtio, pci_id_virtio_map); RTE_PMD_REGISTER_KMOD_DEP(net_virtio, "* igb_uio | uio_pci_generic | vfio-pci"); + +RTE_INIT(virtio_init_log); +static void +virtio_init_log(void) +{ + virtio_logtype_init = rte_log_register("pmd.virtio.init"); + if (virtio_logtype_init >= 0) + rte_log_set_level(virtio_logtype_init, RTE_LOG_NOTICE); + virtio_logtype_driver = rte_log_register("pmd.virtio.driver"); + if (virtio_logtype_driver >= 0) + rte_log_set_level(virtio_logtype_driver, RTE_LOG_NOTICE); +}