136a7a2e7SMaxime Coquelin /* SPDX-License-Identifier: BSD-3-Clause 236a7a2e7SMaxime Coquelin * Copyright(c) 2010-2016 Intel Corporation 336a7a2e7SMaxime Coquelin */ 436a7a2e7SMaxime Coquelin 536a7a2e7SMaxime Coquelin #include <stdint.h> 636a7a2e7SMaxime Coquelin #include <string.h> 736a7a2e7SMaxime Coquelin #include <stdio.h> 836a7a2e7SMaxime Coquelin #include <errno.h> 936a7a2e7SMaxime Coquelin #include <unistd.h> 1036a7a2e7SMaxime Coquelin 1136a7a2e7SMaxime Coquelin #include <ethdev_driver.h> 1236a7a2e7SMaxime Coquelin #include <ethdev_pci.h> 1336a7a2e7SMaxime Coquelin #include <rte_pci.h> 1436a7a2e7SMaxime Coquelin #include <rte_bus_pci.h> 1536a7a2e7SMaxime Coquelin #include <rte_errno.h> 1636a7a2e7SMaxime Coquelin 1736a7a2e7SMaxime Coquelin #include <rte_memory.h> 1836a7a2e7SMaxime Coquelin #include <rte_eal.h> 1936a7a2e7SMaxime Coquelin #include <rte_dev.h> 2036a7a2e7SMaxime Coquelin #include <rte_kvargs.h> 2136a7a2e7SMaxime Coquelin 22f8b60756SMaxime Coquelin #include "virtio.h" 2336a7a2e7SMaxime Coquelin #include "virtio_ethdev.h" 2436a7a2e7SMaxime Coquelin #include "virtio_pci.h" 2536a7a2e7SMaxime Coquelin #include "virtio_logs.h" 2636a7a2e7SMaxime Coquelin 2736a7a2e7SMaxime Coquelin /* 2836a7a2e7SMaxime Coquelin * The set of PCI devices this driver supports 2936a7a2e7SMaxime Coquelin */ 3036a7a2e7SMaxime Coquelin static const struct rte_pci_id pci_id_virtio_map[] = { 3136a7a2e7SMaxime Coquelin { RTE_PCI_DEVICE(VIRTIO_PCI_VENDORID, VIRTIO_PCI_LEGACY_DEVICEID_NET) }, 3236a7a2e7SMaxime Coquelin { RTE_PCI_DEVICE(VIRTIO_PCI_VENDORID, VIRTIO_PCI_MODERN_DEVICEID_NET) }, 3336a7a2e7SMaxime Coquelin { .vendor_id = 0, /* sentinel */ }, 3436a7a2e7SMaxime Coquelin }; 3536a7a2e7SMaxime Coquelin 36512e27eeSMaxime Coquelin 37512e27eeSMaxime Coquelin /* 38512e27eeSMaxime Coquelin * Remap the PCI device again (IO port map for legacy device and 39512e27eeSMaxime Coquelin * memory map for modern device), so that the secondary process 40512e27eeSMaxime Coquelin * could have the PCI initiated correctly. 41512e27eeSMaxime Coquelin */ 42512e27eeSMaxime Coquelin static int 431ac79346SMaxime Coquelin virtio_remap_pci(struct rte_pci_device *pci_dev, struct virtio_pci_dev *dev) 44512e27eeSMaxime Coquelin { 451ac79346SMaxime Coquelin struct virtio_hw *hw = &dev->hw; 461ac79346SMaxime Coquelin 471ac79346SMaxime Coquelin if (dev->modern) { 48512e27eeSMaxime Coquelin /* 49512e27eeSMaxime Coquelin * We don't have to re-parse the PCI config space, since 50512e27eeSMaxime Coquelin * rte_pci_map_device() makes sure the mapped address 51512e27eeSMaxime Coquelin * in secondary process would equal to the one mapped in 52512e27eeSMaxime Coquelin * the primary process: error will be returned if that 53512e27eeSMaxime Coquelin * requirement is not met. 54512e27eeSMaxime Coquelin * 55512e27eeSMaxime Coquelin * That said, we could simply reuse all cap pointers 56512e27eeSMaxime Coquelin * (such as dev_cfg, common_cfg, etc.) parsed from the 57512e27eeSMaxime Coquelin * primary process, which is stored in shared memory. 58512e27eeSMaxime Coquelin */ 59512e27eeSMaxime Coquelin if (rte_pci_map_device(pci_dev)) { 60512e27eeSMaxime Coquelin PMD_INIT_LOG(DEBUG, "failed to map pci device!"); 61512e27eeSMaxime Coquelin return -1; 62512e27eeSMaxime Coquelin } 631ac79346SMaxime Coquelin } else { 64c8d4b02fSMaxime Coquelin if (vtpci_legacy_ioport_map(hw) < 0) 65512e27eeSMaxime Coquelin return -1; 66512e27eeSMaxime Coquelin } 67512e27eeSMaxime Coquelin 68512e27eeSMaxime Coquelin return 0; 69512e27eeSMaxime Coquelin } 70512e27eeSMaxime Coquelin 7136a7a2e7SMaxime Coquelin static int 7236a7a2e7SMaxime Coquelin eth_virtio_pci_init(struct rte_eth_dev *eth_dev) 7336a7a2e7SMaxime Coquelin { 74512e27eeSMaxime Coquelin struct virtio_pci_dev *dev = eth_dev->data->dev_private; 75512e27eeSMaxime Coquelin struct virtio_hw *hw = &dev->hw; 76512e27eeSMaxime Coquelin struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev); 77512e27eeSMaxime Coquelin int ret; 78512e27eeSMaxime Coquelin 79512e27eeSMaxime Coquelin if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 80b93c3530SMaxime Coquelin hw->port_id = eth_dev->data->port_id; 81*aa0d4b8aSMaxime Coquelin VTPCI_DEV(hw) = pci_dev; 821ac79346SMaxime Coquelin ret = vtpci_init(RTE_ETH_DEV_TO_PCI(eth_dev), dev); 83512e27eeSMaxime Coquelin if (ret) { 84512e27eeSMaxime Coquelin PMD_INIT_LOG(ERR, "Failed to init PCI device\n"); 85512e27eeSMaxime Coquelin return -1; 86512e27eeSMaxime Coquelin } 87512e27eeSMaxime Coquelin } else { 88*aa0d4b8aSMaxime Coquelin VTPCI_DEV(hw) = pci_dev; 89c4fa9cc7SMaxime Coquelin if (dev->modern) 90f8b60756SMaxime Coquelin VIRTIO_OPS(hw) = &modern_ops; 91c4fa9cc7SMaxime Coquelin else 92f8b60756SMaxime Coquelin VIRTIO_OPS(hw) = &legacy_ops; 93c4fa9cc7SMaxime Coquelin 941ac79346SMaxime Coquelin ret = virtio_remap_pci(RTE_ETH_DEV_TO_PCI(eth_dev), dev); 95512e27eeSMaxime Coquelin if (ret < 0) { 96512e27eeSMaxime Coquelin PMD_INIT_LOG(ERR, "Failed to remap PCI device\n"); 97512e27eeSMaxime Coquelin return -1; 98512e27eeSMaxime Coquelin } 99512e27eeSMaxime Coquelin } 100512e27eeSMaxime Coquelin 101512e27eeSMaxime Coquelin ret = eth_virtio_dev_init(eth_dev); 102512e27eeSMaxime Coquelin if (ret < 0) { 103512e27eeSMaxime Coquelin PMD_INIT_LOG(ERR, "Failed to init virtio device\n"); 104512e27eeSMaxime Coquelin goto err_unmap; 105512e27eeSMaxime Coquelin } 106512e27eeSMaxime Coquelin 107512e27eeSMaxime Coquelin PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x", 108512e27eeSMaxime Coquelin eth_dev->data->port_id, pci_dev->id.vendor_id, 109512e27eeSMaxime Coquelin pci_dev->id.device_id); 110512e27eeSMaxime Coquelin 111512e27eeSMaxime Coquelin return 0; 112512e27eeSMaxime Coquelin 113512e27eeSMaxime Coquelin err_unmap: 114512e27eeSMaxime Coquelin rte_pci_unmap_device(RTE_ETH_DEV_TO_PCI(eth_dev)); 115c4fa9cc7SMaxime Coquelin if (!dev->modern) 116c8d4b02fSMaxime Coquelin vtpci_legacy_ioport_unmap(hw); 117512e27eeSMaxime Coquelin 118512e27eeSMaxime Coquelin return ret; 11936a7a2e7SMaxime Coquelin } 12036a7a2e7SMaxime Coquelin 12136a7a2e7SMaxime Coquelin static int 12236a7a2e7SMaxime Coquelin eth_virtio_pci_uninit(struct rte_eth_dev *eth_dev) 12336a7a2e7SMaxime Coquelin { 12436a7a2e7SMaxime Coquelin int ret; 12536a7a2e7SMaxime Coquelin PMD_INIT_FUNC_TRACE(); 12636a7a2e7SMaxime Coquelin 12736a7a2e7SMaxime Coquelin if (rte_eal_process_type() == RTE_PROC_SECONDARY) 12836a7a2e7SMaxime Coquelin return 0; 12936a7a2e7SMaxime Coquelin 13036a7a2e7SMaxime Coquelin ret = virtio_dev_stop(eth_dev); 13136a7a2e7SMaxime Coquelin virtio_dev_close(eth_dev); 13236a7a2e7SMaxime Coquelin 13336a7a2e7SMaxime Coquelin PMD_INIT_LOG(DEBUG, "dev_uninit completed"); 13436a7a2e7SMaxime Coquelin 13536a7a2e7SMaxime Coquelin return ret; 13636a7a2e7SMaxime Coquelin } 13736a7a2e7SMaxime Coquelin 13836a7a2e7SMaxime Coquelin static int vdpa_check_handler(__rte_unused const char *key, 13936a7a2e7SMaxime Coquelin const char *value, void *ret_val) 14036a7a2e7SMaxime Coquelin { 14136a7a2e7SMaxime Coquelin if (strcmp(value, "1") == 0) 14236a7a2e7SMaxime Coquelin *(int *)ret_val = 1; 14336a7a2e7SMaxime Coquelin else 14436a7a2e7SMaxime Coquelin *(int *)ret_val = 0; 14536a7a2e7SMaxime Coquelin 14636a7a2e7SMaxime Coquelin return 0; 14736a7a2e7SMaxime Coquelin } 14836a7a2e7SMaxime Coquelin 14936a7a2e7SMaxime Coquelin #define VIRTIO_ARG_VDPA "vdpa" 15036a7a2e7SMaxime Coquelin 15136a7a2e7SMaxime Coquelin static int 15236a7a2e7SMaxime Coquelin virtio_pci_devargs_parse(struct rte_devargs *devargs, int *vdpa) 15336a7a2e7SMaxime Coquelin { 15436a7a2e7SMaxime Coquelin struct rte_kvargs *kvlist; 15536a7a2e7SMaxime Coquelin int ret = 0; 15636a7a2e7SMaxime Coquelin 15736a7a2e7SMaxime Coquelin if (devargs == NULL) 15836a7a2e7SMaxime Coquelin return 0; 15936a7a2e7SMaxime Coquelin 16036a7a2e7SMaxime Coquelin kvlist = rte_kvargs_parse(devargs->args, NULL); 16136a7a2e7SMaxime Coquelin if (kvlist == NULL) { 16236a7a2e7SMaxime Coquelin PMD_INIT_LOG(ERR, "error when parsing param"); 16336a7a2e7SMaxime Coquelin return 0; 16436a7a2e7SMaxime Coquelin } 16536a7a2e7SMaxime Coquelin 16636a7a2e7SMaxime Coquelin if (rte_kvargs_count(kvlist, VIRTIO_ARG_VDPA) == 1) { 16736a7a2e7SMaxime Coquelin /* vdpa mode selected when there's a key-value pair: 16836a7a2e7SMaxime Coquelin * vdpa=1 16936a7a2e7SMaxime Coquelin */ 17036a7a2e7SMaxime Coquelin ret = rte_kvargs_process(kvlist, VIRTIO_ARG_VDPA, 17136a7a2e7SMaxime Coquelin vdpa_check_handler, vdpa); 17236a7a2e7SMaxime Coquelin if (ret < 0) 17336a7a2e7SMaxime Coquelin PMD_INIT_LOG(ERR, "Failed to parse %s", VIRTIO_ARG_VDPA); 17436a7a2e7SMaxime Coquelin } 17536a7a2e7SMaxime Coquelin 17636a7a2e7SMaxime Coquelin rte_kvargs_free(kvlist); 17736a7a2e7SMaxime Coquelin 17836a7a2e7SMaxime Coquelin return ret; 17936a7a2e7SMaxime Coquelin } 18036a7a2e7SMaxime Coquelin 18136a7a2e7SMaxime Coquelin static int eth_virtio_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, 18236a7a2e7SMaxime Coquelin struct rte_pci_device *pci_dev) 18336a7a2e7SMaxime Coquelin { 18436a7a2e7SMaxime Coquelin int vdpa = 0; 18536a7a2e7SMaxime Coquelin int ret = 0; 18636a7a2e7SMaxime Coquelin 18736a7a2e7SMaxime Coquelin ret = virtio_pci_devargs_parse(pci_dev->device.devargs, &vdpa); 18836a7a2e7SMaxime Coquelin if (ret < 0) { 18936a7a2e7SMaxime Coquelin PMD_INIT_LOG(ERR, "devargs parsing is failed"); 19036a7a2e7SMaxime Coquelin return ret; 19136a7a2e7SMaxime Coquelin } 19236a7a2e7SMaxime Coquelin /* virtio pmd skips probe if device needs to work in vdpa mode */ 19336a7a2e7SMaxime Coquelin if (vdpa == 1) 19436a7a2e7SMaxime Coquelin return 1; 19536a7a2e7SMaxime Coquelin 19636a7a2e7SMaxime Coquelin return rte_eth_dev_pci_generic_probe(pci_dev, sizeof(struct virtio_pci_dev), 19736a7a2e7SMaxime Coquelin eth_virtio_pci_init); 19836a7a2e7SMaxime Coquelin } 19936a7a2e7SMaxime Coquelin 20036a7a2e7SMaxime Coquelin static int eth_virtio_pci_remove(struct rte_pci_device *pci_dev) 20136a7a2e7SMaxime Coquelin { 20236a7a2e7SMaxime Coquelin int ret; 20336a7a2e7SMaxime Coquelin 20436a7a2e7SMaxime Coquelin ret = rte_eth_dev_pci_generic_remove(pci_dev, eth_virtio_pci_uninit); 20536a7a2e7SMaxime Coquelin /* Port has already been released by close. */ 20636a7a2e7SMaxime Coquelin if (ret == -ENODEV) 20736a7a2e7SMaxime Coquelin ret = 0; 20836a7a2e7SMaxime Coquelin return ret; 20936a7a2e7SMaxime Coquelin } 21036a7a2e7SMaxime Coquelin 21136a7a2e7SMaxime Coquelin static struct rte_pci_driver rte_virtio_net_pci_pmd = { 21236a7a2e7SMaxime Coquelin .driver = { 21336a7a2e7SMaxime Coquelin .name = "net_virtio", 21436a7a2e7SMaxime Coquelin }, 21536a7a2e7SMaxime Coquelin .id_table = pci_id_virtio_map, 21636a7a2e7SMaxime Coquelin .drv_flags = 0, 21736a7a2e7SMaxime Coquelin .probe = eth_virtio_pci_probe, 21836a7a2e7SMaxime Coquelin .remove = eth_virtio_pci_remove, 21936a7a2e7SMaxime Coquelin }; 22036a7a2e7SMaxime Coquelin 22136a7a2e7SMaxime Coquelin RTE_INIT(rte_virtio_net_pci_pmd_init) 22236a7a2e7SMaxime Coquelin { 22336a7a2e7SMaxime Coquelin rte_eal_iopl_init(); 22436a7a2e7SMaxime Coquelin rte_pci_register(&rte_virtio_net_pci_pmd); 22536a7a2e7SMaxime Coquelin } 22636a7a2e7SMaxime Coquelin 22736a7a2e7SMaxime Coquelin RTE_PMD_REGISTER_PCI_TABLE(net_virtio, pci_id_virtio_map); 22836a7a2e7SMaxime Coquelin RTE_PMD_REGISTER_KMOD_DEP(net_virtio, "* igb_uio | uio_pci_generic | vfio-pci"); 22936a7a2e7SMaxime Coquelin RTE_PMD_EXPORT_NAME(net_virtio, __COUNTER__); 230