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_bus.h> 15 #include <rte_eal.h> 16 #include <rte_tailq.h> 17 #include <rte_devargs.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 } 43 return mapaddr; 44 } 45 46 /* unmap a particular resource */ 47 void 48 vmbus_unmap_resource(void *requested_addr, size_t size) 49 { 50 if (requested_addr == NULL) 51 return; 52 53 /* Unmap the VMBUS memory resource of device */ 54 if (munmap(requested_addr, size)) { 55 VMBUS_LOG(ERR, "munmap(%p, 0x%lx) failed: %s", 56 requested_addr, (unsigned long)size, 57 strerror(errno)); 58 } else 59 VMBUS_LOG(DEBUG, " VMBUS memory unmapped at %p", 60 requested_addr); 61 } 62 63 /** 64 * Match the VMBUS driver and device using UUID table 65 * 66 * @param drv 67 * VMBUS driver from which ID table would be extracted 68 * @param pci_dev 69 * VMBUS device to match against the driver 70 * @return 71 * true for successful match 72 * false for unsuccessful match 73 */ 74 static bool 75 vmbus_match(const struct rte_vmbus_driver *dr, 76 const struct rte_vmbus_device *dev) 77 { 78 const rte_uuid_t *id_table; 79 80 for (id_table = dr->id_table; !rte_uuid_is_null(*id_table); ++id_table) { 81 if (rte_uuid_compare(*id_table, dev->class_id) == 0) 82 return true; 83 } 84 85 return false; 86 } 87 /* 88 * If device ID match, call the devinit() function of the driver. 89 */ 90 static int 91 vmbus_probe_one_driver(struct rte_vmbus_driver *dr, 92 struct rte_vmbus_device *dev) 93 { 94 char guid[RTE_UUID_STRLEN]; 95 int ret; 96 97 if (!vmbus_match(dr, dev)) 98 return 1; /* not supported */ 99 100 rte_uuid_unparse(dev->device_id, guid, sizeof(guid)); 101 VMBUS_LOG(INFO, "VMBUS device %s on NUMA socket %i", 102 guid, dev->device.numa_node); 103 104 /* TODO add block/allow logic */ 105 106 /* map resources for device */ 107 ret = rte_vmbus_map_device(dev); 108 if (ret != 0) 109 return ret; 110 111 /* reference driver structure */ 112 dev->driver = dr; 113 114 if (dev->device.numa_node < 0) { 115 VMBUS_LOG(WARNING, " Invalid NUMA socket, default to 0"); 116 dev->device.numa_node = 0; 117 } 118 119 /* call the driver probe() function */ 120 VMBUS_LOG(INFO, " probe driver: %s", dr->driver.name); 121 ret = dr->probe(dr, dev); 122 if (ret) { 123 dev->driver = NULL; 124 rte_vmbus_unmap_device(dev); 125 } else { 126 dev->device.driver = &dr->driver; 127 } 128 129 return ret; 130 } 131 132 /* 133 * If device class GUID matches, call the probe function of 134 * registere drivers for the vmbus device. 135 * Return -1 if initialization failed, 136 * and 1 if no driver found for this device. 137 */ 138 static int 139 vmbus_probe_all_drivers(struct rte_vmbus_device *dev) 140 { 141 struct rte_vmbus_driver *dr; 142 int rc; 143 144 /* Check if a driver is already loaded */ 145 if (rte_dev_is_probed(&dev->device)) { 146 VMBUS_LOG(DEBUG, "VMBUS driver already loaded"); 147 return 0; 148 } 149 150 FOREACH_DRIVER_ON_VMBUS(dr) { 151 rc = vmbus_probe_one_driver(dr, dev); 152 if (rc < 0) /* negative is an error */ 153 return -1; 154 155 if (rc > 0) /* positive driver doesn't support it */ 156 continue; 157 158 return 0; 159 } 160 return 1; 161 } 162 163 /* 164 * Scan the vmbus, and call the devinit() function for 165 * all registered drivers that have a matching entry in its id_table 166 * for discovered devices. 167 */ 168 int 169 rte_vmbus_probe(void) 170 { 171 struct rte_vmbus_device *dev; 172 size_t probed = 0, failed = 0; 173 char ubuf[RTE_UUID_STRLEN]; 174 175 FOREACH_DEVICE_ON_VMBUS(dev) { 176 probed++; 177 178 rte_uuid_unparse(dev->device_id, ubuf, sizeof(ubuf)); 179 180 /* TODO: add allowlist/blocklist */ 181 182 if (vmbus_probe_all_drivers(dev) < 0) { 183 VMBUS_LOG(NOTICE, 184 "Requested device %s cannot be used", ubuf); 185 rte_errno = errno; 186 failed++; 187 } 188 } 189 190 return (probed && probed == failed) ? -1 : 0; 191 } 192 193 static int 194 vmbus_parse(const char *name, void *addr) 195 { 196 rte_uuid_t guid; 197 int ret; 198 199 ret = rte_uuid_parse(name, guid); 200 if (ret == 0 && addr) 201 memcpy(addr, &guid, sizeof(guid)); 202 203 return ret; 204 } 205 206 /* 207 * scan for matching device args on command line 208 * example: 209 * -a 'vmbus:635a7ae3-091e-4410-ad59-667c4f8c04c3,latency=20' 210 */ 211 struct rte_devargs * 212 vmbus_devargs_lookup(struct rte_vmbus_device *dev) 213 { 214 struct rte_devargs *devargs; 215 rte_uuid_t addr; 216 217 RTE_EAL_DEVARGS_FOREACH("vmbus", devargs) { 218 vmbus_parse(devargs->name, &addr); 219 220 if (rte_uuid_compare(dev->device_id, addr) == 0) 221 return devargs; 222 } 223 return NULL; 224 225 } 226 227 /* register vmbus driver */ 228 void 229 rte_vmbus_register(struct rte_vmbus_driver *driver) 230 { 231 VMBUS_LOG(DEBUG, 232 "Registered driver %s", driver->driver.name); 233 234 TAILQ_INSERT_TAIL(&rte_vmbus_bus.driver_list, driver, next); 235 driver->bus = &rte_vmbus_bus; 236 } 237 238 /* unregister vmbus driver */ 239 void 240 rte_vmbus_unregister(struct rte_vmbus_driver *driver) 241 { 242 TAILQ_REMOVE(&rte_vmbus_bus.driver_list, driver, next); 243 driver->bus = NULL; 244 } 245 246 /* Add a device to VMBUS bus */ 247 void 248 vmbus_add_device(struct rte_vmbus_device *vmbus_dev) 249 { 250 TAILQ_INSERT_TAIL(&rte_vmbus_bus.device_list, vmbus_dev, next); 251 } 252 253 /* Insert a device into a predefined position in VMBUS bus */ 254 void 255 vmbus_insert_device(struct rte_vmbus_device *exist_vmbus_dev, 256 struct rte_vmbus_device *new_vmbus_dev) 257 { 258 TAILQ_INSERT_BEFORE(exist_vmbus_dev, new_vmbus_dev, next); 259 } 260 261 /* Remove a device from VMBUS bus */ 262 void 263 vmbus_remove_device(struct rte_vmbus_device *vmbus_dev) 264 { 265 TAILQ_REMOVE(&rte_vmbus_bus.device_list, vmbus_dev, next); 266 } 267 268 /* VMBUS doesn't support hotplug */ 269 static struct rte_device * 270 vmbus_find_device(const struct rte_device *start, rte_dev_cmp_t cmp, 271 const void *data) 272 { 273 struct rte_vmbus_device *dev; 274 275 FOREACH_DEVICE_ON_VMBUS(dev) { 276 if (start && &dev->device == start) { 277 start = NULL; 278 continue; 279 } 280 if (cmp(&dev->device, data) == 0) 281 return &dev->device; 282 } 283 284 return NULL; 285 } 286 287 288 struct rte_vmbus_bus rte_vmbus_bus = { 289 .bus = { 290 .scan = rte_vmbus_scan, 291 .probe = rte_vmbus_probe, 292 .find_device = vmbus_find_device, 293 .parse = vmbus_parse, 294 }, 295 .device_list = TAILQ_HEAD_INITIALIZER(rte_vmbus_bus.device_list), 296 .driver_list = TAILQ_HEAD_INITIALIZER(rte_vmbus_bus.driver_list), 297 }; 298 299 RTE_REGISTER_BUS(vmbus, rte_vmbus_bus.bus); 300 RTE_LOG_REGISTER(vmbus_logtype_bus, bus.vmbus, NOTICE); 301