1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2018, Microsoft Corporation. 3 * All Rights Reserved. 4 */ 5 6 #include <string.h> 7 #include <unistd.h> 8 #include <dirent.h> 9 #include <fcntl.h> 10 #include <sys/queue.h> 11 #include <sys/mman.h> 12 13 #include <rte_log.h> 14 #include <rte_eal.h> 15 #include <rte_tailq.h> 16 #include <rte_devargs.h> 17 #include <rte_lcore.h> 18 #include <rte_malloc.h> 19 #include <rte_errno.h> 20 #include <rte_memory.h> 21 #include <rte_bus_vmbus.h> 22 23 #include "private.h" 24 25 extern struct rte_vmbus_bus rte_vmbus_bus; 26 27 /* map a particular resource from a file */ 28 void * 29 vmbus_map_resource(void *requested_addr, int fd, off_t offset, size_t size, 30 int flags) 31 { 32 void *mapaddr; 33 34 /* Map the memory resource of device */ 35 mapaddr = mmap(requested_addr, size, PROT_READ | PROT_WRITE, 36 MAP_SHARED | flags, fd, offset); 37 if (mapaddr == MAP_FAILED) { 38 VMBUS_LOG(ERR, 39 "mmap(%d, %p, %zu, %ld) failed: %s", 40 fd, requested_addr, size, (long)offset, 41 strerror(errno)); 42 } else { 43 VMBUS_LOG(DEBUG, " VMBUS memory mapped at %p", 44 mapaddr); 45 } 46 return mapaddr; 47 } 48 49 /* unmap a particular resource */ 50 void 51 vmbus_unmap_resource(void *requested_addr, size_t size) 52 { 53 if (requested_addr == NULL) 54 return; 55 56 /* Unmap the VMBUS memory resource of device */ 57 if (munmap(requested_addr, size)) { 58 VMBUS_LOG(ERR, "munmap(%p, 0x%lx) failed: %s", 59 requested_addr, (unsigned long)size, 60 strerror(errno)); 61 } else { 62 VMBUS_LOG(DEBUG, " VMBUS memory unmapped at %p", 63 requested_addr); 64 } 65 } 66 67 /** 68 * Match the VMBUS driver and device using UUID table 69 * 70 * @param drv 71 * VMBUS driver from which ID table would be extracted 72 * @param pci_dev 73 * VMBUS device to match against the driver 74 * @return 75 * true for successful match 76 * false for unsuccessful match 77 */ 78 static bool 79 vmbus_match(const struct rte_vmbus_driver *dr, 80 const struct rte_vmbus_device *dev) 81 { 82 const rte_uuid_t *id_table; 83 84 for (id_table = dr->id_table; !rte_uuid_is_null(*id_table); ++id_table) { 85 if (rte_uuid_compare(*id_table, dev->class_id) == 0) 86 return true; 87 } 88 89 return false; 90 } 91 /* 92 * If device ID match, call the devinit() function of the driver. 93 */ 94 static int 95 vmbus_probe_one_driver(struct rte_vmbus_driver *dr, 96 struct rte_vmbus_device *dev) 97 { 98 char guid[RTE_UUID_STRLEN]; 99 int ret; 100 101 if (!vmbus_match(dr, dev)) 102 return 1; /* not supported */ 103 104 rte_uuid_unparse(dev->device_id, guid, sizeof(guid)); 105 VMBUS_LOG(INFO, "VMBUS device %s on NUMA socket %i", 106 guid, dev->device.numa_node); 107 108 /* no initialization when marked as blocked, return without error */ 109 if (dev->device.devargs != NULL && 110 dev->device.devargs->policy == RTE_DEV_BLOCKED) { 111 VMBUS_LOG(INFO, " Device is blocked, not initializing"); 112 return 1; 113 } 114 115 /* map resources for device */ 116 ret = rte_vmbus_map_device(dev); 117 if (ret != 0) 118 return ret; 119 120 /* reference driver structure */ 121 dev->driver = dr; 122 123 if (dev->device.numa_node < 0 && rte_socket_count() > 1) 124 VMBUS_LOG(INFO, "Device %s is not NUMA-aware", guid); 125 126 /* call the driver probe() function */ 127 VMBUS_LOG(INFO, " probe driver: %s", dr->driver.name); 128 ret = dr->probe(dr, dev); 129 if (ret) { 130 dev->driver = NULL; 131 rte_vmbus_unmap_device(dev); 132 } else { 133 dev->device.driver = &dr->driver; 134 } 135 136 return ret; 137 } 138 139 /* 140 * If device class GUID matches, call the probe function of 141 * register drivers for the vmbus device. 142 * Return -1 if initialization failed, 143 * and 1 if no driver found for this device. 144 */ 145 static int 146 vmbus_probe_all_drivers(struct rte_vmbus_device *dev) 147 { 148 struct rte_vmbus_driver *dr; 149 int rc; 150 151 /* Check if a driver is already loaded */ 152 if (rte_dev_is_probed(&dev->device)) { 153 VMBUS_LOG(DEBUG, "VMBUS driver already loaded"); 154 return 0; 155 } 156 157 FOREACH_DRIVER_ON_VMBUS(dr) { 158 rc = vmbus_probe_one_driver(dr, dev); 159 if (rc < 0) /* negative is an error */ 160 return -1; 161 162 if (rc > 0) /* positive driver doesn't support it */ 163 continue; 164 165 return 0; 166 } 167 return 1; 168 } 169 170 static bool 171 vmbus_ignore_device(struct rte_vmbus_device *dev) 172 { 173 struct rte_devargs *devargs = vmbus_devargs_lookup(dev); 174 175 switch (rte_vmbus_bus.bus.conf.scan_mode) { 176 case RTE_BUS_SCAN_ALLOWLIST: 177 if (devargs && devargs->policy == RTE_DEV_ALLOWED) 178 return false; 179 break; 180 case RTE_BUS_SCAN_UNDEFINED: 181 case RTE_BUS_SCAN_BLOCKLIST: 182 if (devargs == NULL || devargs->policy != RTE_DEV_BLOCKED) 183 return false; 184 break; 185 } 186 return true; 187 } 188 189 /* 190 * Scan the vmbus, and call the devinit() function for 191 * all registered drivers that have a matching entry in its id_table 192 * for discovered devices. 193 */ 194 int 195 rte_vmbus_probe(void) 196 { 197 struct rte_vmbus_device *dev; 198 size_t probed = 0, failed = 0; 199 char ubuf[RTE_UUID_STRLEN]; 200 201 FOREACH_DEVICE_ON_VMBUS(dev) { 202 probed++; 203 204 rte_uuid_unparse(dev->device_id, ubuf, sizeof(ubuf)); 205 206 if (vmbus_ignore_device(dev)) 207 continue; 208 209 if (vmbus_probe_all_drivers(dev) < 0) { 210 VMBUS_LOG(NOTICE, 211 "Requested device %s cannot be used", ubuf); 212 rte_errno = errno; 213 failed++; 214 } 215 } 216 217 return (probed && probed == failed) ? -1 : 0; 218 } 219 220 static int 221 rte_vmbus_cleanup(void) 222 { 223 struct rte_vmbus_device *dev, *tmp_dev; 224 int error = 0; 225 226 RTE_TAILQ_FOREACH_SAFE(dev, &rte_vmbus_bus.device_list, next, tmp_dev) { 227 const struct rte_vmbus_driver *drv = dev->driver; 228 int ret; 229 230 if (drv == NULL || drv->remove == NULL) 231 continue; 232 233 ret = drv->remove(dev); 234 if (ret < 0) 235 error = -1; 236 237 rte_vmbus_unmap_device(dev); 238 239 dev->driver = NULL; 240 dev->device.driver = NULL; 241 free(dev); 242 } 243 244 return error; 245 } 246 247 static int 248 vmbus_parse(const char *name, void *addr) 249 { 250 rte_uuid_t guid; 251 int ret; 252 253 ret = rte_uuid_parse(name, guid); 254 if (ret == 0 && addr) 255 memcpy(addr, &guid, sizeof(guid)); 256 257 return ret; 258 } 259 260 /* 261 * scan for matching device args on command line 262 * example: 263 * -a 'vmbus:635a7ae3-091e-4410-ad59-667c4f8c04c3,latency=20' 264 */ 265 struct rte_devargs * 266 vmbus_devargs_lookup(struct rte_vmbus_device *dev) 267 { 268 struct rte_devargs *devargs; 269 rte_uuid_t addr; 270 271 RTE_EAL_DEVARGS_FOREACH("vmbus", devargs) { 272 vmbus_parse(devargs->name, &addr); 273 274 if (rte_uuid_compare(dev->device_id, addr) == 0) 275 return devargs; 276 } 277 return NULL; 278 279 } 280 281 /* register vmbus driver */ 282 void 283 rte_vmbus_register(struct rte_vmbus_driver *driver) 284 { 285 VMBUS_LOG(DEBUG, 286 "Registered driver %s", driver->driver.name); 287 288 TAILQ_INSERT_TAIL(&rte_vmbus_bus.driver_list, driver, next); 289 } 290 291 /* unregister vmbus driver */ 292 void 293 rte_vmbus_unregister(struct rte_vmbus_driver *driver) 294 { 295 TAILQ_REMOVE(&rte_vmbus_bus.driver_list, driver, next); 296 } 297 298 /* Add a device to VMBUS bus */ 299 void 300 vmbus_add_device(struct rte_vmbus_device *vmbus_dev) 301 { 302 TAILQ_INSERT_TAIL(&rte_vmbus_bus.device_list, vmbus_dev, next); 303 } 304 305 /* Insert a device into a predefined position in VMBUS bus */ 306 void 307 vmbus_insert_device(struct rte_vmbus_device *exist_vmbus_dev, 308 struct rte_vmbus_device *new_vmbus_dev) 309 { 310 TAILQ_INSERT_BEFORE(exist_vmbus_dev, new_vmbus_dev, next); 311 } 312 313 /* Remove a device from VMBUS bus */ 314 void 315 vmbus_remove_device(struct rte_vmbus_device *vmbus_dev) 316 { 317 TAILQ_REMOVE(&rte_vmbus_bus.device_list, vmbus_dev, next); 318 } 319 320 /* VMBUS doesn't support hotplug */ 321 static struct rte_device * 322 vmbus_find_device(const struct rte_device *start, rte_dev_cmp_t cmp, 323 const void *data) 324 { 325 struct rte_vmbus_device *dev; 326 327 FOREACH_DEVICE_ON_VMBUS(dev) { 328 if (start && &dev->device == start) { 329 start = NULL; 330 continue; 331 } 332 if (cmp(&dev->device, data) == 0) 333 return &dev->device; 334 } 335 336 return NULL; 337 } 338 339 340 struct rte_vmbus_bus rte_vmbus_bus = { 341 .bus = { 342 .scan = rte_vmbus_scan, 343 .probe = rte_vmbus_probe, 344 .cleanup = rte_vmbus_cleanup, 345 .find_device = vmbus_find_device, 346 .parse = vmbus_parse, 347 }, 348 .device_list = TAILQ_HEAD_INITIALIZER(rte_vmbus_bus.device_list), 349 .driver_list = TAILQ_HEAD_INITIALIZER(rte_vmbus_bus.driver_list), 350 }; 351 352 RTE_REGISTER_BUS(vmbus, rte_vmbus_bus.bus); 353 RTE_LOG_REGISTER_DEFAULT(vmbus_logtype_bus, NOTICE); 354