X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fvirtio%2Fvirtio_user_ethdev.c;h=4c3f664419e3dafabdd1d87e14c98725787c6e40;hb=727d83ca23115387b6f839d4a351c03afb5d084b;hp=740d7b1599fdea98f99dc884df909b160e4f6eda;hpb=4214a1b493f2a1334c0de2165a34f8634fb07fb2;p=dpdk.git diff --git a/drivers/net/virtio/virtio_user_ethdev.c b/drivers/net/virtio/virtio_user_ethdev.c index 740d7b1599..4c3f664419 100644 --- a/drivers/net/virtio/virtio_user_ethdev.c +++ b/drivers/net/virtio/virtio_user_ethdev.c @@ -34,10 +34,14 @@ #include #include #include +#include +#include +#include #include #include #include +#include #include "virtio_ethdev.h" #include "virtio_logs.h" @@ -49,6 +53,17 @@ #define virtio_user_get_dev(hw) \ ((struct virtio_user_dev *)(hw)->virtio_user_dev) +static void +virtio_user_delayed_handler(void *param) +{ + struct virtio_hw *hw = (struct virtio_hw *)param; + struct rte_eth_dev *dev = &rte_eth_devices[hw->port_id]; + + rte_intr_callback_unregister(dev->intr_handle, + virtio_interrupt_handler, + dev); +} + static void virtio_user_read_dev_config(struct virtio_hw *hw, size_t offset, void *dst, int length) @@ -63,8 +78,37 @@ virtio_user_read_dev_config(struct virtio_hw *hw, size_t offset, return; } - if (offset == offsetof(struct virtio_net_config, status)) + if (offset == offsetof(struct virtio_net_config, status)) { + char buf[128]; + + if (dev->vhostfd >= 0) { + int r; + int flags; + + flags = fcntl(dev->vhostfd, F_GETFL); + fcntl(dev->vhostfd, F_SETFL, flags | O_NONBLOCK); + r = recv(dev->vhostfd, buf, 128, MSG_PEEK); + if (r == 0 || (r < 0 && errno != EAGAIN)) { + dev->status &= (~VIRTIO_NET_S_LINK_UP); + PMD_DRV_LOG(ERR, "virtio-user port %u is down", + hw->port_id); + /* Only client mode is available now. Once the + * connection is broken, it can never be up + * again. Besides, this function could be called + * in the process of interrupt handling, + * callback cannot be unregistered here, set an + * alarm to do it. + */ + rte_eal_alarm_set(1, + virtio_user_delayed_handler, + (void *)hw); + } else { + dev->status |= VIRTIO_NET_S_LINK_UP; + } + fcntl(dev->vhostfd, F_SETFL, flags & (~O_NONBLOCK)); + } *(uint16_t *)dst = dev->status; + } if (offset == offsetof(struct virtio_net_config, max_virtqueue_pairs)) *(uint16_t *)dst = dev->max_queue_pairs; @@ -135,17 +179,26 @@ virtio_user_set_features(struct virtio_hw *hw, uint64_t features) static uint8_t virtio_user_get_isr(struct virtio_hw *hw __rte_unused) { - /* When config interrupt happens, driver calls this function to query - * what kinds of change happen. Interrupt mode not supported for now. + /* rxq interrupts and config interrupt are separated in virtio-user, + * here we only report config change. */ - return 0; + return VIRTIO_PCI_ISR_CONFIG; } static uint16_t virtio_user_set_config_irq(struct virtio_hw *hw __rte_unused, uint16_t vec __rte_unused) { - return VIRTIO_MSI_NO_VECTOR; + return 0; +} + +static uint16_t +virtio_user_set_queue_irq(struct virtio_hw *hw __rte_unused, + struct virtqueue *vq __rte_unused, + uint16_t vec) +{ + /* pretend we have done that */ + return vec; } /* This function is to get the queue size, aka, number of descs, of a specified @@ -226,6 +279,7 @@ const struct virtio_pci_ops virtio_user_ops = { .set_features = virtio_user_set_features, .get_isr = virtio_user_get_isr, .set_config_irq = virtio_user_set_config_irq, + .set_queue_irq = virtio_user_set_queue_irq, .get_queue_num = virtio_user_get_queue_num, .setup_queue = virtio_user_setup_queue, .del_queue = virtio_user_del_queue, @@ -313,8 +367,13 @@ virtio_user_eth_dev_alloc(const char *name) } hw->port_id = data->port_id; + dev->port_id = data->port_id; virtio_hw_internal[hw->port_id].vtpci_ops = &virtio_user_ops; - hw->use_msix = 0; + /* + * MSIX is required to enable LSC (see virtio_init_device). + * Here just pretend that we support msix. + */ + hw->use_msix = 1; hw->modern = 0; hw->use_simple_rxtx = 0; hw->virtio_user_dev = dev; @@ -447,18 +506,24 @@ virtio_user_pmd_probe(const char *name, const char *params) goto end; } - eth_dev = virtio_user_eth_dev_alloc(name); - if (!eth_dev) { - PMD_INIT_LOG(ERR, "virtio_user fails to alloc device"); - goto end; - } + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + eth_dev = virtio_user_eth_dev_alloc(name); + if (!eth_dev) { + PMD_INIT_LOG(ERR, "virtio_user fails to alloc device"); + goto end; + } - hw = eth_dev->data->dev_private; - if (virtio_user_dev_init(hw->virtio_user_dev, path, queues, cq, + hw = eth_dev->data->dev_private; + if (virtio_user_dev_init(hw->virtio_user_dev, path, queues, cq, queue_size, mac_addr, &ifname) < 0) { - PMD_INIT_LOG(ERR, "virtio_user_dev_init fails"); - virtio_user_eth_dev_free(eth_dev); - goto end; + PMD_INIT_LOG(ERR, "virtio_user_dev_init fails"); + virtio_user_eth_dev_free(eth_dev); + goto end; + } + } else { + eth_dev = rte_eth_dev_attach_secondary(name); + if (!eth_dev) + goto end; } /* previously called by rte_eal_pci_probe() for physical dev */