1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2016 Intel Corporation 3 */ 4 5 #include <stdint.h> 6 #include <string.h> 7 #include <stdio.h> 8 #include <errno.h> 9 #include <unistd.h> 10 11 #include <ethdev_driver.h> 12 #include <ethdev_pci.h> 13 #include <rte_pci.h> 14 #include <bus_pci_driver.h> 15 #include <rte_errno.h> 16 17 #include <rte_memory.h> 18 #include <rte_eal.h> 19 #include <dev_driver.h> 20 #include <rte_kvargs.h> 21 22 #include "virtio.h" 23 #include "virtio_ethdev.h" 24 #include "virtio_pci.h" 25 #include "virtio_logs.h" 26 27 /* 28 * The set of PCI devices this driver supports 29 */ 30 static const struct rte_pci_id pci_id_virtio_map[] = { 31 { RTE_PCI_DEVICE(VIRTIO_PCI_VENDORID, VIRTIO_PCI_LEGACY_DEVICEID_NET) }, 32 { RTE_PCI_DEVICE(VIRTIO_PCI_VENDORID, VIRTIO_PCI_MODERN_DEVICEID_NET) }, 33 { .vendor_id = 0, /* sentinel */ }, 34 }; 35 36 37 /* 38 * Remap the PCI device again (IO port map for legacy device and 39 * memory map for modern device), so that the secondary process 40 * could have the PCI initiated correctly. 41 */ 42 static int 43 virtio_remap_pci(struct rte_pci_device *pci_dev, struct virtio_pci_dev *dev) 44 { 45 struct virtio_hw *hw = &dev->hw; 46 47 if (dev->modern) { 48 /* 49 * We don't have to re-parse the PCI config space, since 50 * rte_pci_map_device() makes sure the mapped address 51 * in secondary process would equal to the one mapped in 52 * the primary process: error will be returned if that 53 * requirement is not met. 54 * 55 * That said, we could simply reuse all cap pointers 56 * (such as dev_cfg, common_cfg, etc.) parsed from the 57 * primary process, which is stored in shared memory. 58 */ 59 if (rte_pci_map_device(pci_dev)) { 60 PMD_INIT_LOG(DEBUG, "failed to map pci device!"); 61 return -1; 62 } 63 } else { 64 if (vtpci_legacy_ioport_map(hw) < 0) 65 return -1; 66 } 67 68 return 0; 69 } 70 71 static int 72 eth_virtio_pci_init(struct rte_eth_dev *eth_dev) 73 { 74 struct virtio_pci_dev *dev = eth_dev->data->dev_private; 75 struct virtio_hw *hw = &dev->hw; 76 struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev); 77 int ret; 78 79 if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 80 hw->port_id = eth_dev->data->port_id; 81 VTPCI_DEV(hw) = pci_dev; 82 ret = vtpci_init(RTE_ETH_DEV_TO_PCI(eth_dev), dev); 83 if (ret) { 84 PMD_INIT_LOG(ERR, "Failed to init PCI device"); 85 return -1; 86 } 87 } else { 88 VTPCI_DEV(hw) = pci_dev; 89 if (dev->modern) 90 VIRTIO_OPS(hw) = &modern_ops; 91 else 92 VIRTIO_OPS(hw) = &legacy_ops; 93 94 ret = virtio_remap_pci(RTE_ETH_DEV_TO_PCI(eth_dev), dev); 95 if (ret < 0) { 96 PMD_INIT_LOG(ERR, "Failed to remap PCI device"); 97 return -1; 98 } 99 } 100 101 ret = eth_virtio_dev_init(eth_dev); 102 if (ret < 0) { 103 PMD_INIT_LOG(ERR, "Failed to init virtio device"); 104 goto err_unmap; 105 } 106 107 PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x", 108 eth_dev->data->port_id, pci_dev->id.vendor_id, 109 pci_dev->id.device_id); 110 111 return 0; 112 113 err_unmap: 114 rte_pci_unmap_device(RTE_ETH_DEV_TO_PCI(eth_dev)); 115 if (!dev->modern) 116 vtpci_legacy_ioport_unmap(hw); 117 118 return ret; 119 } 120 121 static int 122 eth_virtio_pci_uninit(struct rte_eth_dev *eth_dev) 123 { 124 int ret; 125 struct virtio_pci_dev *dev; 126 struct virtio_hw *hw; 127 PMD_INIT_FUNC_TRACE(); 128 129 if (rte_eal_process_type() == RTE_PROC_SECONDARY) { 130 dev = eth_dev->data->dev_private; 131 hw = &dev->hw; 132 133 if (dev->modern) 134 rte_pci_unmap_device(RTE_ETH_DEV_TO_PCI(eth_dev)); 135 else 136 vtpci_legacy_ioport_unmap(hw); 137 return 0; 138 } 139 140 ret = virtio_dev_stop(eth_dev); 141 virtio_dev_close(eth_dev); 142 143 PMD_INIT_LOG(DEBUG, "dev_uninit completed"); 144 145 return ret; 146 } 147 148 static int vdpa_check_handler(__rte_unused const char *key, 149 const char *value, void *ret_val) 150 { 151 if (value == NULL || ret_val == NULL) 152 return -EINVAL; 153 154 if (strcmp(value, "1") == 0) 155 *(int *)ret_val = 1; 156 else 157 *(int *)ret_val = 0; 158 159 return 0; 160 } 161 162 #define VIRTIO_ARG_VDPA "vdpa" 163 164 static int 165 virtio_pci_devargs_parse(struct rte_devargs *devargs, int *vdpa) 166 { 167 struct rte_kvargs *kvlist; 168 int ret = 0; 169 170 if (devargs == NULL) 171 return 0; 172 173 kvlist = rte_kvargs_parse(devargs->args, NULL); 174 if (kvlist == NULL) { 175 PMD_INIT_LOG(ERR, "error when parsing param"); 176 return 0; 177 } 178 179 if (rte_kvargs_count(kvlist, VIRTIO_ARG_VDPA) == 1) { 180 /* vdpa mode selected when there's a key-value pair: 181 * vdpa=1 182 */ 183 ret = rte_kvargs_process(kvlist, VIRTIO_ARG_VDPA, 184 vdpa_check_handler, vdpa); 185 if (ret < 0) 186 PMD_INIT_LOG(ERR, "Failed to parse %s", VIRTIO_ARG_VDPA); 187 } 188 189 rte_kvargs_free(kvlist); 190 191 return ret; 192 } 193 194 static int eth_virtio_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, 195 struct rte_pci_device *pci_dev) 196 { 197 int vdpa = 0; 198 int ret = 0; 199 200 ret = virtio_pci_devargs_parse(pci_dev->device.devargs, &vdpa); 201 if (ret < 0) { 202 PMD_INIT_LOG(ERR, "devargs parsing is failed"); 203 return ret; 204 } 205 /* virtio pmd skips probe if device needs to work in vdpa mode */ 206 if (vdpa == 1) 207 return 1; 208 209 return rte_eth_dev_pci_generic_probe(pci_dev, sizeof(struct virtio_pci_dev), 210 eth_virtio_pci_init); 211 } 212 213 static int eth_virtio_pci_remove(struct rte_pci_device *pci_dev) 214 { 215 int ret; 216 217 ret = rte_eth_dev_pci_generic_remove(pci_dev, eth_virtio_pci_uninit); 218 /* Port has already been released by close. */ 219 if (ret == -ENODEV) 220 ret = 0; 221 return ret; 222 } 223 224 static struct rte_pci_driver rte_virtio_net_pci_pmd = { 225 .driver = { 226 .name = "net_virtio", 227 }, 228 .id_table = pci_id_virtio_map, 229 .drv_flags = 0, 230 .probe = eth_virtio_pci_probe, 231 .remove = eth_virtio_pci_remove, 232 }; 233 234 RTE_INIT(rte_virtio_net_pci_pmd_init) 235 { 236 rte_eal_iopl_init(); 237 rte_pci_register(&rte_virtio_net_pci_pmd); 238 } 239 240 RTE_PMD_REGISTER_PCI_TABLE(net_virtio, pci_id_virtio_map); 241 RTE_PMD_REGISTER_KMOD_DEP(net_virtio, "* igb_uio | uio_pci_generic | vfio-pci"); 242 RTE_PMD_EXPORT_NAME(net_virtio, __COUNTER__); 243