X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_pmd_virtio%2Fvirtio_ethdev.c;h=dc0c6b3e92c0ace4fd556f759362e742b21ad539;hb=faf79b7854e82c9312b1e1192b64efae46d2b5f8;hp=b9f552938e8e6b3c2112bc44d91ed0915ac8c376;hpb=ce65e697c67ba1a357d806eed05957b3d43f562c;p=dpdk.git diff --git a/lib/librte_pmd_virtio/virtio_ethdev.c b/lib/librte_pmd_virtio/virtio_ethdev.c index b9f552938e..dc0c6b3e92 100644 --- a/lib/librte_pmd_virtio/virtio_ethdev.c +++ b/lib/librte_pmd_virtio/virtio_ethdev.c @@ -66,6 +66,10 @@ static int eth_virtio_dev_init(struct eth_driver *eth_drv, static int virtio_dev_configure(struct rte_eth_dev *dev); static int virtio_dev_start(struct rte_eth_dev *dev); static void virtio_dev_stop(struct rte_eth_dev *dev); +static void virtio_dev_promiscuous_enable(struct rte_eth_dev *dev); +static void virtio_dev_promiscuous_disable(struct rte_eth_dev *dev); +static void virtio_dev_allmulticast_enable(struct rte_eth_dev *dev); +static void virtio_dev_allmulticast_disable(struct rte_eth_dev *dev); static void virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info); static int virtio_dev_link_update(struct rte_eth_dev *dev, @@ -171,7 +175,7 @@ virtio_send_command(struct virtqueue *vq, struct virtio_pmd_ctrl *ctrl, uint32_t idx, desc_idx, used_idx; struct vring_used_elem *uep; - rmb(); + virtio_rmb(); used_idx = (uint32_t)(vq->vq_used_cons_idx & (vq->vq_nentries - 1)); @@ -270,18 +274,18 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev, snprintf(vq_name, sizeof(vq_name), "port%d_rvq%d", dev->data->port_id, queue_idx); vq = rte_zmalloc(vq_name, sizeof(struct virtqueue) + - vq_size * sizeof(struct vq_desc_extra), CACHE_LINE_SIZE); + vq_size * sizeof(struct vq_desc_extra), RTE_CACHE_LINE_SIZE); } else if (queue_type == VTNET_TQ) { snprintf(vq_name, sizeof(vq_name), "port%d_tvq%d", dev->data->port_id, queue_idx); vq = rte_zmalloc(vq_name, sizeof(struct virtqueue) + - vq_size * sizeof(struct vq_desc_extra), CACHE_LINE_SIZE); + vq_size * sizeof(struct vq_desc_extra), RTE_CACHE_LINE_SIZE); } else if (queue_type == VTNET_CQ) { snprintf(vq_name, sizeof(vq_name), "port%d_cvq", dev->data->port_id); vq = rte_zmalloc(vq_name, sizeof(struct virtqueue) + vq_size * sizeof(struct vq_desc_extra), - CACHE_LINE_SIZE); + RTE_CACHE_LINE_SIZE); } if (vq == NULL) { PMD_INIT_LOG(ERR, "%s: Can not allocate virtqueue", __func__); @@ -337,8 +341,8 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev, snprintf(vq_name, sizeof(vq_name), "port%d_tvq%d_hdrzone", dev->data->port_id, queue_idx); vq->virtio_net_hdr_mz = rte_memzone_reserve_aligned(vq_name, - vq_size * sizeof(struct virtio_net_hdr), - socket_id, 0, CACHE_LINE_SIZE); + vq_size * hw->vtnet_hdr_size, + socket_id, 0, RTE_CACHE_LINE_SIZE); if (vq->virtio_net_hdr_mz == NULL) { rte_free(vq); return -ENOMEM; @@ -346,13 +350,13 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev, vq->virtio_net_hdr_mem = vq->virtio_net_hdr_mz->phys_addr; memset(vq->virtio_net_hdr_mz->addr, 0, - vq_size * sizeof(struct virtio_net_hdr)); + vq_size * hw->vtnet_hdr_size); } else if (queue_type == VTNET_CQ) { /* Allocate a page for control vq command, data and status */ snprintf(vq_name, sizeof(vq_name), "port%d_cvq_hdrzone", dev->data->port_id); vq->virtio_net_hdr_mz = rte_memzone_reserve_aligned(vq_name, - PAGE_SIZE, socket_id, 0, CACHE_LINE_SIZE); + PAGE_SIZE, socket_id, 0, RTE_CACHE_LINE_SIZE); if (vq->virtio_net_hdr_mz == NULL) { rte_free(vq); return -ENOMEM; @@ -403,6 +407,86 @@ virtio_dev_close(struct rte_eth_dev *dev) virtio_dev_stop(dev); } +static void +virtio_dev_promiscuous_enable(struct rte_eth_dev *dev) +{ + struct virtio_hw *hw + = VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct virtio_pmd_ctrl ctrl; + int dlen[1]; + int ret; + + ctrl.hdr.class = VIRTIO_NET_CTRL_RX; + ctrl.hdr.cmd = VIRTIO_NET_CTRL_RX_PROMISC; + ctrl.data[0] = 1; + dlen[0] = 1; + + ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1); + + if (ret) + PMD_INIT_LOG(ERR, "Failed to enable promisc"); +} + +static void +virtio_dev_promiscuous_disable(struct rte_eth_dev *dev) +{ + struct virtio_hw *hw + = VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct virtio_pmd_ctrl ctrl; + int dlen[1]; + int ret; + + ctrl.hdr.class = VIRTIO_NET_CTRL_RX; + ctrl.hdr.cmd = VIRTIO_NET_CTRL_RX_PROMISC; + ctrl.data[0] = 0; + dlen[0] = 1; + + ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1); + + if (ret) + PMD_INIT_LOG(ERR, "Failed to disable promisc"); +} + +static void +virtio_dev_allmulticast_enable(struct rte_eth_dev *dev) +{ + struct virtio_hw *hw + = VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct virtio_pmd_ctrl ctrl; + int dlen[1]; + int ret; + + ctrl.hdr.class = VIRTIO_NET_CTRL_RX; + ctrl.hdr.cmd = VIRTIO_NET_CTRL_RX_ALLMULTI; + ctrl.data[0] = 1; + dlen[0] = 1; + + ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1); + + if (ret) + PMD_INIT_LOG(ERR, "Failed to enable allmulticast"); +} + +static void +virtio_dev_allmulticast_disable(struct rte_eth_dev *dev) +{ + struct virtio_hw *hw + = VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct virtio_pmd_ctrl ctrl; + int dlen[1]; + int ret; + + ctrl.hdr.class = VIRTIO_NET_CTRL_RX; + ctrl.hdr.cmd = VIRTIO_NET_CTRL_RX_ALLMULTI; + ctrl.data[0] = 0; + dlen[0] = 1; + + ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1); + + if (ret) + PMD_INIT_LOG(ERR, "Failed to disable allmulticast"); +} + /* * dev_ops for virtio, bare necessities for basic operation */ @@ -411,6 +495,10 @@ static struct eth_dev_ops virtio_eth_dev_ops = { .dev_start = virtio_dev_start, .dev_stop = virtio_dev_stop, .dev_close = virtio_dev_close, + .promiscuous_enable = virtio_dev_promiscuous_enable, + .promiscuous_disable = virtio_dev_promiscuous_disable, + .allmulticast_enable = virtio_dev_allmulticast_enable, + .allmulticast_disable = virtio_dev_allmulticast_disable, .dev_infos_get = virtio_dev_info_get, .stats_get = virtio_dev_stats_get, @@ -561,7 +649,7 @@ virtio_negotiate_features(struct virtio_hw *hw) { uint32_t host_features, mask; - mask = VIRTIO_NET_F_CTRL_RX | VIRTIO_NET_F_CTRL_VLAN; + mask = VIRTIO_NET_F_CTRL_VLAN; mask |= VIRTIO_NET_F_CSUM | VIRTIO_NET_F_GUEST_CSUM; /* TSO and LRO are only available when their corresponding @@ -571,16 +659,13 @@ virtio_negotiate_features(struct virtio_hw *hw) mask |= VIRTIO_NET_F_GUEST_TSO4 | VIRTIO_NET_F_GUEST_TSO6 | VIRTIO_NET_F_GUEST_ECN; mask |= VTNET_LRO_FEATURES; - /* rx_mbuf should not be in multiple merged segments */ - mask |= VIRTIO_NET_F_MRG_RXBUF; - /* not negotiating INDIRECT descriptor table support */ mask |= VIRTIO_RING_F_INDIRECT_DESC; /* Prepare guest_features: feature that driver wants to support */ hw->guest_features = VTNET_FEATURES & ~mask; PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x", - guest_features); + hw->guest_features); /* Read device(host) feature bits */ host_features = VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES); @@ -709,6 +794,41 @@ virtio_has_msix(const struct rte_pci_addr *loc) return (d != NULL); } + +/* Extract I/O port numbers from sysfs */ +static int virtio_resource_init(struct rte_pci_device *pci_dev) +{ + char dirname[PATH_MAX]; + char filename[PATH_MAX]; + unsigned long start, size; + + if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname)) < 0) + return -1; + + /* get portio size */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/size", dirname); + if (parse_sysfs_value(filename, &size) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse size", + __func__); + return -1; + } + + /* get portio start */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/start", dirname); + if (parse_sysfs_value(filename, &start) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", + __func__); + return -1; + } + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%lx with size=0x%lx", + start, size); + return 0; +} #else static int virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) @@ -716,6 +836,12 @@ virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) /* nic_uio does not enable interrupts, return 0 (false). */ return 0; } + +static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) +{ + /* no setup required */ + return 0; +} #endif /* @@ -733,60 +859,18 @@ eth_virtio_dev_init(__rte_unused struct eth_driver *eth_drv, struct virtio_hw *hw = VIRTIO_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); - if (RTE_PKTMBUF_HEADROOM < sizeof(struct virtio_net_hdr)) { - PMD_INIT_LOG(ERR, - "MBUF HEADROOM should be enough to hold virtio net hdr\n"); - return -1; - } - - if (!(rte_eal_get_configuration()->flags & EAL_FLG_HIGH_IOPL)) { - PMD_INIT_LOG(ERR, - "IOPL call failed in EAL init - cannot use virtio PMD driver\n"); - return -1; - } + RTE_BUILD_BUG_ON(RTE_PKTMBUF_HEADROOM < sizeof(struct virtio_net_hdr)); eth_dev->dev_ops = &virtio_eth_dev_ops; - eth_dev->rx_pkt_burst = &virtio_recv_pkts; eth_dev->tx_pkt_burst = &virtio_xmit_pkts; if (rte_eal_process_type() == RTE_PROC_SECONDARY) return 0; pci_dev = eth_dev->pci_dev; + if (virtio_resource_init(pci_dev) < 0) + return -1; -#ifdef RTE_EXEC_ENV_LINUXAPP - { - char dirname[PATH_MAX]; - char filename[PATH_MAX]; - unsigned long start, size; - - if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname)) < 0) - return -1; - - /* get portio size */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/size", dirname); - if (parse_sysfs_value(filename, &size) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse size", - __func__); - return -1; - } - - /* get portio start */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/start", dirname); - if (parse_sysfs_value(filename, &start) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", - __func__); - return -1; - } - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%lx with size=0x%lx", - start, size); - } -#endif hw->use_msix = virtio_has_msix(&pci_dev->addr); hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr; @@ -801,10 +885,13 @@ eth_virtio_dev_init(__rte_unused struct eth_driver *eth_drv, virtio_negotiate_features(hw); /* Setting up rx_header size for the device */ - if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) + if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) { + eth_dev->rx_pkt_burst = &virtio_recv_mergeable_pkts; hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); - else + } else { + eth_dev->rx_pkt_burst = &virtio_recv_pkts; hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr); + } /* Allocate memory for storing MAC addresses */ eth_dev->data->mac_addrs = rte_zmalloc("virtio", ETHER_ADDR_LEN, 0); @@ -897,8 +984,14 @@ static struct eth_driver rte_virtio_pmd = { * Returns 0 on success. */ static int -rte_virtio_pmd_init(const char *name __rte_unused, const char *param __rte_unused) +rte_virtio_pmd_init(const char *name __rte_unused, + const char *param __rte_unused) { + if (rte_eal_iopl_init() != 0) { + PMD_INIT_LOG(ERR, "IOPL call failed - cannot use virtio PMD"); + return -1; + } + rte_eth_driver_register(&rte_virtio_pmd); return 0; } @@ -1009,7 +1102,7 @@ static void virtio_dev_free_mbufs(struct rte_eth_dev *dev) while ((buf = (struct rte_mbuf *)virtqueue_detatch_unused( dev->data->rx_queues[i])) != NULL) { - rte_pktmbuf_free_seg(buf); + rte_pktmbuf_free(buf); mbuf_num++; } @@ -1028,7 +1121,8 @@ static void virtio_dev_free_mbufs(struct rte_eth_dev *dev) mbuf_num = 0; while ((buf = (struct rte_mbuf *)virtqueue_detatch_unused( dev->data->tx_queues[i])) != NULL) { - rte_pktmbuf_free_seg(buf); + rte_pktmbuf_free(buf); + mbuf_num++; }