15566a3e3SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 25566a3e3SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation 3c752998bSGaetan Rivet */ 4c752998bSGaetan Rivet 5c752998bSGaetan Rivet #include <string.h> 6c752998bSGaetan Rivet #include <dirent.h> 7c752998bSGaetan Rivet 8c752998bSGaetan Rivet #include <rte_log.h> 9c752998bSGaetan Rivet #include <rte_bus.h> 10c752998bSGaetan Rivet #include <rte_pci.h> 11c752998bSGaetan Rivet #include <rte_bus_pci.h> 12c752998bSGaetan Rivet #include <rte_malloc.h> 13c752998bSGaetan Rivet #include <rte_devargs.h> 14c752998bSGaetan Rivet #include <rte_memcpy.h> 15c752998bSGaetan Rivet #include <rte_vfio.h> 16c752998bSGaetan Rivet 17c752998bSGaetan Rivet #include "eal_filesystem.h" 18c752998bSGaetan Rivet 19c752998bSGaetan Rivet #include "private.h" 20c752998bSGaetan Rivet #include "pci_init.h" 21c752998bSGaetan Rivet 22c752998bSGaetan Rivet /** 23c752998bSGaetan Rivet * @file 24c752998bSGaetan Rivet * PCI probing under linux 25c752998bSGaetan Rivet * 26c752998bSGaetan Rivet * This code is used to simulate a PCI probe by parsing information in sysfs. 27c752998bSGaetan Rivet * When a registered device matches a driver, it is then initialized with 28c752998bSGaetan Rivet * IGB_UIO driver (or doesn't initialize, if the device wasn't bound to it). 29c752998bSGaetan Rivet */ 30c752998bSGaetan Rivet 31c752998bSGaetan Rivet extern struct rte_pci_bus rte_pci_bus; 32c752998bSGaetan Rivet 33c752998bSGaetan Rivet static int 3452f711f7SAndy Green pci_get_kernel_driver_by_path(const char *filename, char *dri_name, 3552f711f7SAndy Green size_t len) 36c752998bSGaetan Rivet { 37c752998bSGaetan Rivet int count; 38c752998bSGaetan Rivet char path[PATH_MAX]; 39c752998bSGaetan Rivet char *name; 40c752998bSGaetan Rivet 41c752998bSGaetan Rivet if (!filename || !dri_name) 42c752998bSGaetan Rivet return -1; 43c752998bSGaetan Rivet 44c752998bSGaetan Rivet count = readlink(filename, path, PATH_MAX); 45c752998bSGaetan Rivet if (count >= PATH_MAX) 46c752998bSGaetan Rivet return -1; 47c752998bSGaetan Rivet 48c752998bSGaetan Rivet /* For device does not have a driver */ 49c752998bSGaetan Rivet if (count < 0) 50c752998bSGaetan Rivet return 1; 51c752998bSGaetan Rivet 52c752998bSGaetan Rivet path[count] = '\0'; 53c752998bSGaetan Rivet 54c752998bSGaetan Rivet name = strrchr(path, '/'); 55c752998bSGaetan Rivet if (name) { 5652f711f7SAndy Green strlcpy(dri_name, name + 1, len); 57c752998bSGaetan Rivet return 0; 58c752998bSGaetan Rivet } 59c752998bSGaetan Rivet 60c752998bSGaetan Rivet return -1; 61c752998bSGaetan Rivet } 62c752998bSGaetan Rivet 63c752998bSGaetan Rivet /* Map pci device */ 64c752998bSGaetan Rivet int 65c752998bSGaetan Rivet rte_pci_map_device(struct rte_pci_device *dev) 66c752998bSGaetan Rivet { 67c752998bSGaetan Rivet int ret = -1; 68c752998bSGaetan Rivet 69c752998bSGaetan Rivet /* try mapping the NIC resources using VFIO if it exists */ 70c752998bSGaetan Rivet switch (dev->kdrv) { 717c0d798aSDavid Marchand case RTE_PCI_KDRV_VFIO: 72c752998bSGaetan Rivet #ifdef VFIO_PRESENT 73c752998bSGaetan Rivet if (pci_vfio_is_enabled()) 74c752998bSGaetan Rivet ret = pci_vfio_map_resource(dev); 75c752998bSGaetan Rivet #endif 76c752998bSGaetan Rivet break; 777c0d798aSDavid Marchand case RTE_PCI_KDRV_IGB_UIO: 787c0d798aSDavid Marchand case RTE_PCI_KDRV_UIO_GENERIC: 79c752998bSGaetan Rivet if (rte_eal_using_phys_addrs()) { 80c752998bSGaetan Rivet /* map resources for devices that use uio */ 81c752998bSGaetan Rivet ret = pci_uio_map_resource(dev); 82c752998bSGaetan Rivet } 83c752998bSGaetan Rivet break; 84c752998bSGaetan Rivet default: 85c752998bSGaetan Rivet RTE_LOG(DEBUG, EAL, 86c752998bSGaetan Rivet " Not managed by a supported kernel driver, skipped\n"); 87c752998bSGaetan Rivet ret = 1; 88c752998bSGaetan Rivet break; 89c752998bSGaetan Rivet } 90c752998bSGaetan Rivet 91c752998bSGaetan Rivet return ret; 92c752998bSGaetan Rivet } 93c752998bSGaetan Rivet 94c752998bSGaetan Rivet /* Unmap pci device */ 95c752998bSGaetan Rivet void 96c752998bSGaetan Rivet rte_pci_unmap_device(struct rte_pci_device *dev) 97c752998bSGaetan Rivet { 98c752998bSGaetan Rivet /* try unmapping the NIC resources using VFIO if it exists */ 99c752998bSGaetan Rivet switch (dev->kdrv) { 1007c0d798aSDavid Marchand case RTE_PCI_KDRV_VFIO: 101c752998bSGaetan Rivet #ifdef VFIO_PRESENT 102c752998bSGaetan Rivet if (pci_vfio_is_enabled()) 103c752998bSGaetan Rivet pci_vfio_unmap_resource(dev); 104c752998bSGaetan Rivet #endif 105c752998bSGaetan Rivet break; 1067c0d798aSDavid Marchand case RTE_PCI_KDRV_IGB_UIO: 1077c0d798aSDavid Marchand case RTE_PCI_KDRV_UIO_GENERIC: 108c752998bSGaetan Rivet /* unmap resources for devices that use uio */ 109c752998bSGaetan Rivet pci_uio_unmap_resource(dev); 110c752998bSGaetan Rivet break; 111c752998bSGaetan Rivet default: 112c752998bSGaetan Rivet RTE_LOG(DEBUG, EAL, 113c752998bSGaetan Rivet " Not managed by a supported kernel driver, skipped\n"); 114c752998bSGaetan Rivet break; 115c752998bSGaetan Rivet } 116c752998bSGaetan Rivet } 117c752998bSGaetan Rivet 1187411d032SAnatoly Burakov static int 11966cc45e2SAnatoly Burakov find_max_end_va(const struct rte_memseg_list *msl, void *arg) 1207411d032SAnatoly Burakov { 1214104b2a4SAnatoly Burakov size_t sz = msl->len; 12266cc45e2SAnatoly Burakov void *end_va = RTE_PTR_ADD(msl->base_va, sz); 1237411d032SAnatoly Burakov void **max_va = arg; 1247411d032SAnatoly Burakov 1257411d032SAnatoly Burakov if (*max_va < end_va) 1267411d032SAnatoly Burakov *max_va = end_va; 1277411d032SAnatoly Burakov return 0; 1287411d032SAnatoly Burakov } 1297411d032SAnatoly Burakov 130c752998bSGaetan Rivet void * 131c752998bSGaetan Rivet pci_find_max_end_va(void) 132c752998bSGaetan Rivet { 1337411d032SAnatoly Burakov void *va = NULL; 134c752998bSGaetan Rivet 13566cc45e2SAnatoly Burakov rte_memseg_list_walk(find_max_end_va, &va); 1367411d032SAnatoly Burakov return va; 137c752998bSGaetan Rivet } 138c752998bSGaetan Rivet 13966cc45e2SAnatoly Burakov 140c752998bSGaetan Rivet /* parse one line of the "resource" sysfs file (note that the 'line' 141c752998bSGaetan Rivet * string is modified) 142c752998bSGaetan Rivet */ 143c752998bSGaetan Rivet int 144c752998bSGaetan Rivet pci_parse_one_sysfs_resource(char *line, size_t len, uint64_t *phys_addr, 145c752998bSGaetan Rivet uint64_t *end_addr, uint64_t *flags) 146c752998bSGaetan Rivet { 147c752998bSGaetan Rivet union pci_resource_info { 148c752998bSGaetan Rivet struct { 149c752998bSGaetan Rivet char *phys_addr; 150c752998bSGaetan Rivet char *end_addr; 151c752998bSGaetan Rivet char *flags; 152c752998bSGaetan Rivet }; 153c752998bSGaetan Rivet char *ptrs[PCI_RESOURCE_FMT_NVAL]; 154c752998bSGaetan Rivet } res_info; 155c752998bSGaetan Rivet 156c752998bSGaetan Rivet if (rte_strsplit(line, len, res_info.ptrs, 3, ' ') != 3) { 157c752998bSGaetan Rivet RTE_LOG(ERR, EAL, 158c752998bSGaetan Rivet "%s(): bad resource format\n", __func__); 159c752998bSGaetan Rivet return -1; 160c752998bSGaetan Rivet } 161c752998bSGaetan Rivet errno = 0; 162c752998bSGaetan Rivet *phys_addr = strtoull(res_info.phys_addr, NULL, 16); 163c752998bSGaetan Rivet *end_addr = strtoull(res_info.end_addr, NULL, 16); 164c752998bSGaetan Rivet *flags = strtoull(res_info.flags, NULL, 16); 165c752998bSGaetan Rivet if (errno != 0) { 166c752998bSGaetan Rivet RTE_LOG(ERR, EAL, 167c752998bSGaetan Rivet "%s(): bad resource format\n", __func__); 168c752998bSGaetan Rivet return -1; 169c752998bSGaetan Rivet } 170c752998bSGaetan Rivet 171c752998bSGaetan Rivet return 0; 172c752998bSGaetan Rivet } 173c752998bSGaetan Rivet 174c752998bSGaetan Rivet /* parse the "resource" sysfs file */ 175c752998bSGaetan Rivet static int 176c752998bSGaetan Rivet pci_parse_sysfs_resource(const char *filename, struct rte_pci_device *dev) 177c752998bSGaetan Rivet { 178c752998bSGaetan Rivet FILE *f; 179c752998bSGaetan Rivet char buf[BUFSIZ]; 180c752998bSGaetan Rivet int i; 181c752998bSGaetan Rivet uint64_t phys_addr, end_addr, flags; 182c752998bSGaetan Rivet 183c752998bSGaetan Rivet f = fopen(filename, "r"); 184c752998bSGaetan Rivet if (f == NULL) { 185c752998bSGaetan Rivet RTE_LOG(ERR, EAL, "Cannot open sysfs resource\n"); 186c752998bSGaetan Rivet return -1; 187c752998bSGaetan Rivet } 188c752998bSGaetan Rivet 189c752998bSGaetan Rivet for (i = 0; i<PCI_MAX_RESOURCE; i++) { 190c752998bSGaetan Rivet 191c752998bSGaetan Rivet if (fgets(buf, sizeof(buf), f) == NULL) { 192c752998bSGaetan Rivet RTE_LOG(ERR, EAL, 193c752998bSGaetan Rivet "%s(): cannot read resource\n", __func__); 194c752998bSGaetan Rivet goto error; 195c752998bSGaetan Rivet } 196c752998bSGaetan Rivet if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr, 197c752998bSGaetan Rivet &end_addr, &flags) < 0) 198c752998bSGaetan Rivet goto error; 199c752998bSGaetan Rivet 200c752998bSGaetan Rivet if (flags & IORESOURCE_MEM) { 201c752998bSGaetan Rivet dev->mem_resource[i].phys_addr = phys_addr; 202c752998bSGaetan Rivet dev->mem_resource[i].len = end_addr - phys_addr + 1; 203c752998bSGaetan Rivet /* not mapped for now */ 204c752998bSGaetan Rivet dev->mem_resource[i].addr = NULL; 205c752998bSGaetan Rivet } 206c752998bSGaetan Rivet } 207c752998bSGaetan Rivet fclose(f); 208c752998bSGaetan Rivet return 0; 209c752998bSGaetan Rivet 210c752998bSGaetan Rivet error: 211c752998bSGaetan Rivet fclose(f); 212c752998bSGaetan Rivet return -1; 213c752998bSGaetan Rivet } 214c752998bSGaetan Rivet 215c752998bSGaetan Rivet /* Scan one pci sysfs entry, and fill the devices list from it. */ 216c752998bSGaetan Rivet static int 217c752998bSGaetan Rivet pci_scan_one(const char *dirname, const struct rte_pci_addr *addr) 218c752998bSGaetan Rivet { 219c752998bSGaetan Rivet char filename[PATH_MAX]; 220c752998bSGaetan Rivet unsigned long tmp; 221c752998bSGaetan Rivet struct rte_pci_device *dev; 222c752998bSGaetan Rivet char driver[PATH_MAX]; 223c752998bSGaetan Rivet int ret; 224c752998bSGaetan Rivet 225c752998bSGaetan Rivet dev = malloc(sizeof(*dev)); 226c752998bSGaetan Rivet if (dev == NULL) 227c752998bSGaetan Rivet return -1; 228c752998bSGaetan Rivet 229c752998bSGaetan Rivet memset(dev, 0, sizeof(*dev)); 2306844d146SThomas Monjalon dev->device.bus = &rte_pci_bus.bus; 231c752998bSGaetan Rivet dev->addr = *addr; 232c752998bSGaetan Rivet 233c752998bSGaetan Rivet /* get vendor id */ 234c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "%s/vendor", dirname); 235c752998bSGaetan Rivet if (eal_parse_sysfs_value(filename, &tmp) < 0) { 236c752998bSGaetan Rivet free(dev); 237c752998bSGaetan Rivet return -1; 238c752998bSGaetan Rivet } 239c752998bSGaetan Rivet dev->id.vendor_id = (uint16_t)tmp; 240c752998bSGaetan Rivet 241c752998bSGaetan Rivet /* get device id */ 242c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "%s/device", dirname); 243c752998bSGaetan Rivet if (eal_parse_sysfs_value(filename, &tmp) < 0) { 244c752998bSGaetan Rivet free(dev); 245c752998bSGaetan Rivet return -1; 246c752998bSGaetan Rivet } 247c752998bSGaetan Rivet dev->id.device_id = (uint16_t)tmp; 248c752998bSGaetan Rivet 249c752998bSGaetan Rivet /* get subsystem_vendor id */ 250c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "%s/subsystem_vendor", 251c752998bSGaetan Rivet dirname); 252c752998bSGaetan Rivet if (eal_parse_sysfs_value(filename, &tmp) < 0) { 253c752998bSGaetan Rivet free(dev); 254c752998bSGaetan Rivet return -1; 255c752998bSGaetan Rivet } 256c752998bSGaetan Rivet dev->id.subsystem_vendor_id = (uint16_t)tmp; 257c752998bSGaetan Rivet 258c752998bSGaetan Rivet /* get subsystem_device id */ 259c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "%s/subsystem_device", 260c752998bSGaetan Rivet dirname); 261c752998bSGaetan Rivet if (eal_parse_sysfs_value(filename, &tmp) < 0) { 262c752998bSGaetan Rivet free(dev); 263c752998bSGaetan Rivet return -1; 264c752998bSGaetan Rivet } 265c752998bSGaetan Rivet dev->id.subsystem_device_id = (uint16_t)tmp; 266c752998bSGaetan Rivet 267c752998bSGaetan Rivet /* get class_id */ 268c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "%s/class", 269c752998bSGaetan Rivet dirname); 270c752998bSGaetan Rivet if (eal_parse_sysfs_value(filename, &tmp) < 0) { 271c752998bSGaetan Rivet free(dev); 272c752998bSGaetan Rivet return -1; 273c752998bSGaetan Rivet } 274c752998bSGaetan Rivet /* the least 24 bits are valid: class, subclass, program interface */ 275c752998bSGaetan Rivet dev->id.class_id = (uint32_t)tmp & RTE_CLASS_ANY_ID; 276c752998bSGaetan Rivet 277c752998bSGaetan Rivet /* get max_vfs */ 278c752998bSGaetan Rivet dev->max_vfs = 0; 279c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "%s/max_vfs", dirname); 280c752998bSGaetan Rivet if (!access(filename, F_OK) && 281c752998bSGaetan Rivet eal_parse_sysfs_value(filename, &tmp) == 0) 282c752998bSGaetan Rivet dev->max_vfs = (uint16_t)tmp; 283c752998bSGaetan Rivet else { 284c752998bSGaetan Rivet /* for non igb_uio driver, need kernel version >= 3.8 */ 285c752998bSGaetan Rivet snprintf(filename, sizeof(filename), 286c752998bSGaetan Rivet "%s/sriov_numvfs", dirname); 287c752998bSGaetan Rivet if (!access(filename, F_OK) && 288c752998bSGaetan Rivet eal_parse_sysfs_value(filename, &tmp) == 0) 289c752998bSGaetan Rivet dev->max_vfs = (uint16_t)tmp; 290c752998bSGaetan Rivet } 291c752998bSGaetan Rivet 292c752998bSGaetan Rivet /* get numa node, default to 0 if not present */ 293c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "%s/numa_node", 294c752998bSGaetan Rivet dirname); 295c752998bSGaetan Rivet 296c752998bSGaetan Rivet if (access(filename, F_OK) != -1) { 297c752998bSGaetan Rivet if (eal_parse_sysfs_value(filename, &tmp) == 0) 298c752998bSGaetan Rivet dev->device.numa_node = tmp; 299c752998bSGaetan Rivet else 300c752998bSGaetan Rivet dev->device.numa_node = -1; 301c752998bSGaetan Rivet } else { 302c752998bSGaetan Rivet dev->device.numa_node = 0; 303c752998bSGaetan Rivet } 304c752998bSGaetan Rivet 305c752998bSGaetan Rivet pci_name_set(dev); 306c752998bSGaetan Rivet 307c752998bSGaetan Rivet /* parse resources */ 308c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "%s/resource", dirname); 309c752998bSGaetan Rivet if (pci_parse_sysfs_resource(filename, dev) < 0) { 310c752998bSGaetan Rivet RTE_LOG(ERR, EAL, "%s(): cannot parse resource\n", __func__); 311c752998bSGaetan Rivet free(dev); 312c752998bSGaetan Rivet return -1; 313c752998bSGaetan Rivet } 314c752998bSGaetan Rivet 315c752998bSGaetan Rivet /* parse driver */ 316c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "%s/driver", dirname); 31752f711f7SAndy Green ret = pci_get_kernel_driver_by_path(filename, driver, sizeof(driver)); 318c752998bSGaetan Rivet if (ret < 0) { 319c752998bSGaetan Rivet RTE_LOG(ERR, EAL, "Fail to get kernel driver\n"); 320c752998bSGaetan Rivet free(dev); 321c752998bSGaetan Rivet return -1; 322c752998bSGaetan Rivet } 323c752998bSGaetan Rivet 324c752998bSGaetan Rivet if (!ret) { 325c752998bSGaetan Rivet if (!strcmp(driver, "vfio-pci")) 3267c0d798aSDavid Marchand dev->kdrv = RTE_PCI_KDRV_VFIO; 327c752998bSGaetan Rivet else if (!strcmp(driver, "igb_uio")) 3287c0d798aSDavid Marchand dev->kdrv = RTE_PCI_KDRV_IGB_UIO; 329c752998bSGaetan Rivet else if (!strcmp(driver, "uio_pci_generic")) 3307c0d798aSDavid Marchand dev->kdrv = RTE_PCI_KDRV_UIO_GENERIC; 331c752998bSGaetan Rivet else 3327c0d798aSDavid Marchand dev->kdrv = RTE_PCI_KDRV_UNKNOWN; 333c79a1c67SJerin Jacob } else { 3347c0d798aSDavid Marchand dev->kdrv = RTE_PCI_KDRV_NONE; 335c79a1c67SJerin Jacob return 0; 336c79a1c67SJerin Jacob } 337c752998bSGaetan Rivet /* device is valid, add in list (sorted) */ 338c752998bSGaetan Rivet if (TAILQ_EMPTY(&rte_pci_bus.device_list)) { 339c752998bSGaetan Rivet rte_pci_add_device(dev); 340c752998bSGaetan Rivet } else { 341c752998bSGaetan Rivet struct rte_pci_device *dev2; 342c752998bSGaetan Rivet int ret; 343c752998bSGaetan Rivet 344c752998bSGaetan Rivet TAILQ_FOREACH(dev2, &rte_pci_bus.device_list, next) { 3450e3ef055SGaetan Rivet ret = rte_pci_addr_cmp(&dev->addr, &dev2->addr); 346c752998bSGaetan Rivet if (ret > 0) 347c752998bSGaetan Rivet continue; 348c752998bSGaetan Rivet 349c752998bSGaetan Rivet if (ret < 0) { 350c752998bSGaetan Rivet rte_pci_insert_device(dev2, dev); 351c752998bSGaetan Rivet } else { /* already registered */ 35255e411b3SQi Zhang if (!rte_dev_is_probed(&dev2->device)) { 353c752998bSGaetan Rivet dev2->kdrv = dev->kdrv; 354c752998bSGaetan Rivet dev2->max_vfs = dev->max_vfs; 3559d3ad80aSJim Harris dev2->id = dev->id; 356c752998bSGaetan Rivet pci_name_set(dev2); 35755e411b3SQi Zhang memmove(dev2->mem_resource, 35855e411b3SQi Zhang dev->mem_resource, 359c752998bSGaetan Rivet sizeof(dev->mem_resource)); 36055e411b3SQi Zhang } else { 36155e411b3SQi Zhang /** 36255e411b3SQi Zhang * If device is plugged and driver is 36355e411b3SQi Zhang * probed already, (This happens when 36455e411b3SQi Zhang * we call rte_dev_probe which will 36555e411b3SQi Zhang * scan all device on the bus) we don't 36655e411b3SQi Zhang * need to do anything here unless... 36755e411b3SQi Zhang **/ 36855e411b3SQi Zhang if (dev2->kdrv != dev->kdrv || 3699d3ad80aSJim Harris dev2->max_vfs != dev->max_vfs || 3709d3ad80aSJim Harris memcmp(&dev2->id, &dev->id, sizeof(dev2->id))) 37155e411b3SQi Zhang /* 37255e411b3SQi Zhang * This should not happens. 37355e411b3SQi Zhang * But it is still possible if 37455e411b3SQi Zhang * we unbind a device from 37555e411b3SQi Zhang * vfio or uio before hotplug 37655e411b3SQi Zhang * remove and rebind it with 37755e411b3SQi Zhang * a different configure. 37855e411b3SQi Zhang * So we just print out the 37955e411b3SQi Zhang * error as an alarm. 38055e411b3SQi Zhang */ 38155e411b3SQi Zhang RTE_LOG(ERR, EAL, "Unexpected device scan at %s!\n", 38255e411b3SQi Zhang filename); 383fc67ae91SSomnath Kotur else if (dev2->device.devargs != 384fc67ae91SSomnath Kotur dev->device.devargs) { 385fc67ae91SSomnath Kotur rte_devargs_remove(dev2->device.devargs); 386fc67ae91SSomnath Kotur pci_name_set(dev2); 387fc67ae91SSomnath Kotur } 38855e411b3SQi Zhang } 389c752998bSGaetan Rivet free(dev); 390c752998bSGaetan Rivet } 391c752998bSGaetan Rivet return 0; 392c752998bSGaetan Rivet } 393c752998bSGaetan Rivet 394c752998bSGaetan Rivet rte_pci_add_device(dev); 395c752998bSGaetan Rivet } 396c752998bSGaetan Rivet 397c752998bSGaetan Rivet return 0; 398c752998bSGaetan Rivet } 399c752998bSGaetan Rivet 400c752998bSGaetan Rivet /* 401c752998bSGaetan Rivet * split up a pci address into its constituent parts. 402c752998bSGaetan Rivet */ 403c752998bSGaetan Rivet static int 404c752998bSGaetan Rivet parse_pci_addr_format(const char *buf, int bufsize, struct rte_pci_addr *addr) 405c752998bSGaetan Rivet { 406c752998bSGaetan Rivet /* first split on ':' */ 407c752998bSGaetan Rivet union splitaddr { 408c752998bSGaetan Rivet struct { 409c752998bSGaetan Rivet char *domain; 410c752998bSGaetan Rivet char *bus; 411c752998bSGaetan Rivet char *devid; 412c752998bSGaetan Rivet char *function; 413c752998bSGaetan Rivet }; 414c752998bSGaetan Rivet char *str[PCI_FMT_NVAL]; /* last element-separator is "." not ":" */ 415c752998bSGaetan Rivet } splitaddr; 416c752998bSGaetan Rivet 417c752998bSGaetan Rivet char *buf_copy = strndup(buf, bufsize); 418c752998bSGaetan Rivet if (buf_copy == NULL) 419c752998bSGaetan Rivet return -1; 420c752998bSGaetan Rivet 421c752998bSGaetan Rivet if (rte_strsplit(buf_copy, bufsize, splitaddr.str, PCI_FMT_NVAL, ':') 422c752998bSGaetan Rivet != PCI_FMT_NVAL - 1) 423c752998bSGaetan Rivet goto error; 424c752998bSGaetan Rivet /* final split is on '.' between devid and function */ 425c752998bSGaetan Rivet splitaddr.function = strchr(splitaddr.devid,'.'); 426c752998bSGaetan Rivet if (splitaddr.function == NULL) 427c752998bSGaetan Rivet goto error; 428c752998bSGaetan Rivet *splitaddr.function++ = '\0'; 429c752998bSGaetan Rivet 430c752998bSGaetan Rivet /* now convert to int values */ 431c752998bSGaetan Rivet errno = 0; 432c752998bSGaetan Rivet addr->domain = strtoul(splitaddr.domain, NULL, 16); 433c752998bSGaetan Rivet addr->bus = strtoul(splitaddr.bus, NULL, 16); 434c752998bSGaetan Rivet addr->devid = strtoul(splitaddr.devid, NULL, 16); 435c752998bSGaetan Rivet addr->function = strtoul(splitaddr.function, NULL, 10); 436c752998bSGaetan Rivet if (errno != 0) 437c752998bSGaetan Rivet goto error; 438c752998bSGaetan Rivet 439c752998bSGaetan Rivet free(buf_copy); /* free the copy made with strdup */ 440c752998bSGaetan Rivet return 0; 441c752998bSGaetan Rivet error: 442c752998bSGaetan Rivet free(buf_copy); 443c752998bSGaetan Rivet return -1; 444c752998bSGaetan Rivet } 445c752998bSGaetan Rivet 446c752998bSGaetan Rivet /* 447c752998bSGaetan Rivet * Scan the content of the PCI bus, and the devices in the devices 448c752998bSGaetan Rivet * list 449c752998bSGaetan Rivet */ 450c752998bSGaetan Rivet int 451c752998bSGaetan Rivet rte_pci_scan(void) 452c752998bSGaetan Rivet { 453c752998bSGaetan Rivet struct dirent *e; 454c752998bSGaetan Rivet DIR *dir; 455c752998bSGaetan Rivet char dirname[PATH_MAX]; 456c752998bSGaetan Rivet struct rte_pci_addr addr; 457c752998bSGaetan Rivet 458c752998bSGaetan Rivet /* for debug purposes, PCI can be disabled */ 459c752998bSGaetan Rivet if (!rte_eal_has_pci()) 460c752998bSGaetan Rivet return 0; 461c752998bSGaetan Rivet 462c752998bSGaetan Rivet #ifdef VFIO_PRESENT 463c752998bSGaetan Rivet if (!pci_vfio_is_enabled()) 464c752998bSGaetan Rivet RTE_LOG(DEBUG, EAL, "VFIO PCI modules not loaded\n"); 465c752998bSGaetan Rivet #endif 466c752998bSGaetan Rivet 467c52dd394SThomas Monjalon dir = opendir(rte_pci_get_sysfs_path()); 468c752998bSGaetan Rivet if (dir == NULL) { 469c752998bSGaetan Rivet RTE_LOG(ERR, EAL, "%s(): opendir failed: %s\n", 470c752998bSGaetan Rivet __func__, strerror(errno)); 471c752998bSGaetan Rivet return -1; 472c752998bSGaetan Rivet } 473c752998bSGaetan Rivet 474c752998bSGaetan Rivet while ((e = readdir(dir)) != NULL) { 475c752998bSGaetan Rivet if (e->d_name[0] == '.') 476c752998bSGaetan Rivet continue; 477c752998bSGaetan Rivet 478c752998bSGaetan Rivet if (parse_pci_addr_format(e->d_name, sizeof(e->d_name), &addr) != 0) 479c752998bSGaetan Rivet continue; 480c752998bSGaetan Rivet 481463a5245SSunil Kumar Kori if (rte_pci_ignore_device(&addr)) 482463a5245SSunil Kumar Kori continue; 483463a5245SSunil Kumar Kori 484c752998bSGaetan Rivet snprintf(dirname, sizeof(dirname), "%s/%s", 485c52dd394SThomas Monjalon rte_pci_get_sysfs_path(), e->d_name); 486c752998bSGaetan Rivet 487c752998bSGaetan Rivet if (pci_scan_one(dirname, &addr) < 0) 488c752998bSGaetan Rivet goto error; 489c752998bSGaetan Rivet } 490c752998bSGaetan Rivet closedir(dir); 491c752998bSGaetan Rivet return 0; 492c752998bSGaetan Rivet 493c752998bSGaetan Rivet error: 494c752998bSGaetan Rivet closedir(dir); 495c752998bSGaetan Rivet return -1; 496c752998bSGaetan Rivet } 497c752998bSGaetan Rivet 49854a328f5SMaxime Coquelin #if defined(RTE_ARCH_X86) 49966d3724bSDavid Marchand bool 50066d3724bSDavid Marchand pci_device_iommu_support_va(const struct rte_pci_device *dev) 50154a328f5SMaxime Coquelin { 50254a328f5SMaxime Coquelin #define VTD_CAP_MGAW_SHIFT 16 50354a328f5SMaxime Coquelin #define VTD_CAP_MGAW_MASK (0x3fULL << VTD_CAP_MGAW_SHIFT) 504703458e1SBen Walker const struct rte_pci_addr *addr = &dev->addr; 50554a328f5SMaxime Coquelin char filename[PATH_MAX]; 50654a328f5SMaxime Coquelin FILE *fp; 50754a328f5SMaxime Coquelin uint64_t mgaw, vtd_cap_reg = 0; 50854a328f5SMaxime Coquelin 50954a328f5SMaxime Coquelin snprintf(filename, sizeof(filename), 51054a328f5SMaxime Coquelin "%s/" PCI_PRI_FMT "/iommu/intel-iommu/cap", 51154a328f5SMaxime Coquelin rte_pci_get_sysfs_path(), addr->domain, addr->bus, addr->devid, 51254a328f5SMaxime Coquelin addr->function); 51354a328f5SMaxime Coquelin 51454a328f5SMaxime Coquelin fp = fopen(filename, "r"); 51554a328f5SMaxime Coquelin if (fp == NULL) { 5162e8d5cf7SStephen Hemminger /* We don't have an Intel IOMMU, assume VA supported */ 5172e8d5cf7SStephen Hemminger if (errno == ENOENT) 5182e8d5cf7SStephen Hemminger return true; 5192e8d5cf7SStephen Hemminger 5202e8d5cf7SStephen Hemminger RTE_LOG(ERR, EAL, "%s(): can't open %s: %s\n", 5212e8d5cf7SStephen Hemminger __func__, filename, strerror(errno)); 52254a328f5SMaxime Coquelin return false; 52354a328f5SMaxime Coquelin } 52454a328f5SMaxime Coquelin 5252e8d5cf7SStephen Hemminger /* We have an Intel IOMMU */ 52654a328f5SMaxime Coquelin if (fscanf(fp, "%" PRIx64, &vtd_cap_reg) != 1) { 52754a328f5SMaxime Coquelin RTE_LOG(ERR, EAL, "%s(): can't read %s\n", __func__, filename); 52854a328f5SMaxime Coquelin fclose(fp); 52954a328f5SMaxime Coquelin return false; 53054a328f5SMaxime Coquelin } 53154a328f5SMaxime Coquelin 53254a328f5SMaxime Coquelin fclose(fp); 53354a328f5SMaxime Coquelin 53454a328f5SMaxime Coquelin mgaw = ((vtd_cap_reg & VTD_CAP_MGAW_MASK) >> VTD_CAP_MGAW_SHIFT) + 1; 53554a328f5SMaxime Coquelin 536ec200687SAlejandro Lucero /* 537ec200687SAlejandro Lucero * Assuming there is no limitation by now. We can not know at this point 538ec200687SAlejandro Lucero * because the memory has not been initialized yet. Setting the dma mask 539ec200687SAlejandro Lucero * will force a check once memory initialization is done. We can not do 540ec200687SAlejandro Lucero * a fallback to IOVA PA now, but if the dma check fails, the error 541ec200687SAlejandro Lucero * message should advice for using '--iova-mode pa' if IOVA VA is the 542ec200687SAlejandro Lucero * current mode. 543ec200687SAlejandro Lucero */ 544ec200687SAlejandro Lucero rte_mem_set_dma_mask(mgaw); 545ec200687SAlejandro Lucero return true; 54654a328f5SMaxime Coquelin } 54754a328f5SMaxime Coquelin #elif defined(RTE_ARCH_PPC_64) 54866d3724bSDavid Marchand bool 54966d3724bSDavid Marchand pci_device_iommu_support_va(__rte_unused const struct rte_pci_device *dev) 55054a328f5SMaxime Coquelin { 55190521573SDavid Christensen /* 552*fc5bffb8SDavid Christensen * All POWER systems support an IOMMU, but only IOMMUv2 supports 553*fc5bffb8SDavid Christensen * IOVA = VA in DPDK. Check contents of /proc/cpuinfo to find the 554*fc5bffb8SDavid Christensen * system. 555*fc5bffb8SDavid Christensen * 556*fc5bffb8SDavid Christensen * Platform | Model | IOMMU | VA? | Comment 557*fc5bffb8SDavid Christensen * ---------+-------+---------+-----+--------------------------------- 558*fc5bffb8SDavid Christensen * PowerNV | N/A | IOMMUv2 | Yes | OpenPOWER (Bare Metal) 559*fc5bffb8SDavid Christensen * pSeries | ~qemu | IOMMUv2 | Yes | PowerVM Logical Partition (LPAR) 560*fc5bffb8SDavid Christensen * pSeries | qemu | IOMMUv1 | No | QEMU Virtual Machine 56190521573SDavid Christensen */ 56290521573SDavid Christensen 56390521573SDavid Christensen char *line = NULL; 56490521573SDavid Christensen size_t len = 0; 56590521573SDavid Christensen char filename[PATH_MAX] = "/proc/cpuinfo"; 56690521573SDavid Christensen FILE *fp = fopen(filename, "r"); 567*fc5bffb8SDavid Christensen bool pseries = false, powernv = false, qemu = false; 56890521573SDavid Christensen bool ret = false; 56990521573SDavid Christensen 57090521573SDavid Christensen if (fp == NULL) { 57190521573SDavid Christensen RTE_LOG(ERR, EAL, "%s(): can't open %s: %s\n", 57290521573SDavid Christensen __func__, filename, strerror(errno)); 57390521573SDavid Christensen return ret; 57490521573SDavid Christensen } 57590521573SDavid Christensen 576*fc5bffb8SDavid Christensen /* Check the "platform" and "model" fields */ 57790521573SDavid Christensen while (getline(&line, &len, fp) != -1) { 578*fc5bffb8SDavid Christensen if (strstr(line, "platform") != NULL) { 57990521573SDavid Christensen if (strstr(line, "PowerNV") != NULL) { 580*fc5bffb8SDavid Christensen RTE_LOG(DEBUG, EAL, "Running on a PowerNV platform\n"); 581*fc5bffb8SDavid Christensen powernv = true; 582*fc5bffb8SDavid Christensen } else if (strstr(line, "pSeries") != NULL) { 583*fc5bffb8SDavid Christensen RTE_LOG(DEBUG, EAL, "Running on a pSeries platform\n"); 584*fc5bffb8SDavid Christensen pseries = true; 585*fc5bffb8SDavid Christensen } 586*fc5bffb8SDavid Christensen } else if (strstr(line, "model") != NULL) { 587*fc5bffb8SDavid Christensen if (strstr(line, "qemu") != NULL) { 588*fc5bffb8SDavid Christensen RTE_LOG(DEBUG, EAL, "Found qemu emulation\n"); 589*fc5bffb8SDavid Christensen qemu = true; 590*fc5bffb8SDavid Christensen } 59190521573SDavid Christensen } 59290521573SDavid Christensen } 59390521573SDavid Christensen 59490521573SDavid Christensen free(line); 59590521573SDavid Christensen fclose(fp); 596*fc5bffb8SDavid Christensen 597*fc5bffb8SDavid Christensen if (powernv || (pseries && !qemu)) 598*fc5bffb8SDavid Christensen ret = true; 59990521573SDavid Christensen return ret; 60054a328f5SMaxime Coquelin } 60154a328f5SMaxime Coquelin #else 60266d3724bSDavid Marchand bool 60366d3724bSDavid Marchand pci_device_iommu_support_va(__rte_unused const struct rte_pci_device *dev) 60454a328f5SMaxime Coquelin { 60554a328f5SMaxime Coquelin return true; 60654a328f5SMaxime Coquelin } 60754a328f5SMaxime Coquelin #endif 60854a328f5SMaxime Coquelin 609c752998bSGaetan Rivet enum rte_iova_mode 610703458e1SBen Walker pci_device_iova_mode(const struct rte_pci_driver *pdrv, 611703458e1SBen Walker const struct rte_pci_device *pdev) 612c752998bSGaetan Rivet { 613703458e1SBen Walker enum rte_iova_mode iova_mode = RTE_IOVA_DC; 614c752998bSGaetan Rivet 615703458e1SBen Walker switch (pdev->kdrv) { 6167c0d798aSDavid Marchand case RTE_PCI_KDRV_VFIO: { 617c752998bSGaetan Rivet #ifdef VFIO_PRESENT 618703458e1SBen Walker static int is_vfio_noiommu_enabled = -1; 619703458e1SBen Walker 620703458e1SBen Walker if (is_vfio_noiommu_enabled == -1) { 621703458e1SBen Walker if (rte_vfio_noiommu_is_enabled() == 1) 622703458e1SBen Walker is_vfio_noiommu_enabled = 1; 623703458e1SBen Walker else 624703458e1SBen Walker is_vfio_noiommu_enabled = 0; 625703458e1SBen Walker } 626b76fafb1SDavid Marchand if (is_vfio_noiommu_enabled != 0) 627703458e1SBen Walker iova_mode = RTE_IOVA_PA; 628d622cad8SJerin Jacob else if ((pdrv->drv_flags & RTE_PCI_DRV_NEED_IOVA_AS_VA) != 0) 629b76fafb1SDavid Marchand iova_mode = RTE_IOVA_VA; 630c752998bSGaetan Rivet #endif 631703458e1SBen Walker break; 632c752998bSGaetan Rivet } 633c752998bSGaetan Rivet 6347c0d798aSDavid Marchand case RTE_PCI_KDRV_IGB_UIO: 6357c0d798aSDavid Marchand case RTE_PCI_KDRV_UIO_GENERIC: 636703458e1SBen Walker iova_mode = RTE_IOVA_PA; 637703458e1SBen Walker break; 638703458e1SBen Walker 639703458e1SBen Walker default: 640d622cad8SJerin Jacob if ((pdrv->drv_flags & RTE_PCI_DRV_NEED_IOVA_AS_VA) != 0) 641b76fafb1SDavid Marchand iova_mode = RTE_IOVA_VA; 642703458e1SBen Walker break; 643703458e1SBen Walker } 644703458e1SBen Walker return iova_mode; 645c752998bSGaetan Rivet } 646c752998bSGaetan Rivet 647c752998bSGaetan Rivet /* Read PCI config space. */ 648c752998bSGaetan Rivet int rte_pci_read_config(const struct rte_pci_device *device, 649c752998bSGaetan Rivet void *buf, size_t len, off_t offset) 650c752998bSGaetan Rivet { 651630deed6SAlejandro Lucero char devname[RTE_DEV_NAME_MAX_LEN] = ""; 652c752998bSGaetan Rivet const struct rte_intr_handle *intr_handle = &device->intr_handle; 653c752998bSGaetan Rivet 654630deed6SAlejandro Lucero switch (device->kdrv) { 6557c0d798aSDavid Marchand case RTE_PCI_KDRV_IGB_UIO: 6567c0d798aSDavid Marchand case RTE_PCI_KDRV_UIO_GENERIC: 657c752998bSGaetan Rivet return pci_uio_read_config(intr_handle, buf, len, offset); 658c752998bSGaetan Rivet #ifdef VFIO_PRESENT 6597c0d798aSDavid Marchand case RTE_PCI_KDRV_VFIO: 660c752998bSGaetan Rivet return pci_vfio_read_config(intr_handle, buf, len, offset); 661c752998bSGaetan Rivet #endif 662c752998bSGaetan Rivet default: 663630deed6SAlejandro Lucero rte_pci_device_name(&device->addr, devname, 664630deed6SAlejandro Lucero RTE_DEV_NAME_MAX_LEN); 665c752998bSGaetan Rivet RTE_LOG(ERR, EAL, 666630deed6SAlejandro Lucero "Unknown driver type for %s\n", devname); 667c752998bSGaetan Rivet return -1; 668c752998bSGaetan Rivet } 669c752998bSGaetan Rivet } 670c752998bSGaetan Rivet 671c752998bSGaetan Rivet /* Write PCI config space. */ 672c752998bSGaetan Rivet int rte_pci_write_config(const struct rte_pci_device *device, 673c752998bSGaetan Rivet const void *buf, size_t len, off_t offset) 674c752998bSGaetan Rivet { 675630deed6SAlejandro Lucero char devname[RTE_DEV_NAME_MAX_LEN] = ""; 676c752998bSGaetan Rivet const struct rte_intr_handle *intr_handle = &device->intr_handle; 677c752998bSGaetan Rivet 678630deed6SAlejandro Lucero switch (device->kdrv) { 6797c0d798aSDavid Marchand case RTE_PCI_KDRV_IGB_UIO: 6807c0d798aSDavid Marchand case RTE_PCI_KDRV_UIO_GENERIC: 681c752998bSGaetan Rivet return pci_uio_write_config(intr_handle, buf, len, offset); 682c752998bSGaetan Rivet #ifdef VFIO_PRESENT 6837c0d798aSDavid Marchand case RTE_PCI_KDRV_VFIO: 684c752998bSGaetan Rivet return pci_vfio_write_config(intr_handle, buf, len, offset); 685c752998bSGaetan Rivet #endif 686c752998bSGaetan Rivet default: 687630deed6SAlejandro Lucero rte_pci_device_name(&device->addr, devname, 688630deed6SAlejandro Lucero RTE_DEV_NAME_MAX_LEN); 689c752998bSGaetan Rivet RTE_LOG(ERR, EAL, 690630deed6SAlejandro Lucero "Unknown driver type for %s\n", devname); 691c752998bSGaetan Rivet return -1; 692c752998bSGaetan Rivet } 693c752998bSGaetan Rivet } 694c752998bSGaetan Rivet 695c752998bSGaetan Rivet int 696c752998bSGaetan Rivet rte_pci_ioport_map(struct rte_pci_device *dev, int bar, 697c752998bSGaetan Rivet struct rte_pci_ioport *p) 698c752998bSGaetan Rivet { 699c752998bSGaetan Rivet int ret = -1; 700c752998bSGaetan Rivet 701c752998bSGaetan Rivet switch (dev->kdrv) { 702c752998bSGaetan Rivet #ifdef VFIO_PRESENT 7037c0d798aSDavid Marchand case RTE_PCI_KDRV_VFIO: 704c752998bSGaetan Rivet if (pci_vfio_is_enabled()) 705c752998bSGaetan Rivet ret = pci_vfio_ioport_map(dev, bar, p); 706c752998bSGaetan Rivet break; 707c752998bSGaetan Rivet #endif 7087c0d798aSDavid Marchand case RTE_PCI_KDRV_IGB_UIO: 7097c0d798aSDavid Marchand case RTE_PCI_KDRV_UIO_GENERIC: 710c752998bSGaetan Rivet ret = pci_uio_ioport_map(dev, bar, p); 711c752998bSGaetan Rivet break; 712c752998bSGaetan Rivet default: 713c752998bSGaetan Rivet break; 714c752998bSGaetan Rivet } 715c752998bSGaetan Rivet 716c752998bSGaetan Rivet if (!ret) 717c752998bSGaetan Rivet p->dev = dev; 718c752998bSGaetan Rivet 719c752998bSGaetan Rivet return ret; 720c752998bSGaetan Rivet } 721c752998bSGaetan Rivet 722c752998bSGaetan Rivet void 723c752998bSGaetan Rivet rte_pci_ioport_read(struct rte_pci_ioport *p, 724c752998bSGaetan Rivet void *data, size_t len, off_t offset) 725c752998bSGaetan Rivet { 726c752998bSGaetan Rivet switch (p->dev->kdrv) { 727c752998bSGaetan Rivet #ifdef VFIO_PRESENT 7287c0d798aSDavid Marchand case RTE_PCI_KDRV_VFIO: 729c752998bSGaetan Rivet pci_vfio_ioport_read(p, data, len, offset); 730c752998bSGaetan Rivet break; 731c752998bSGaetan Rivet #endif 7327c0d798aSDavid Marchand case RTE_PCI_KDRV_IGB_UIO: 7337c0d798aSDavid Marchand case RTE_PCI_KDRV_UIO_GENERIC: 734c752998bSGaetan Rivet pci_uio_ioport_read(p, data, len, offset); 735c752998bSGaetan Rivet break; 736c752998bSGaetan Rivet default: 737c752998bSGaetan Rivet break; 738c752998bSGaetan Rivet } 739c752998bSGaetan Rivet } 740c752998bSGaetan Rivet 741c752998bSGaetan Rivet void 742c752998bSGaetan Rivet rte_pci_ioport_write(struct rte_pci_ioport *p, 743c752998bSGaetan Rivet const void *data, size_t len, off_t offset) 744c752998bSGaetan Rivet { 745c752998bSGaetan Rivet switch (p->dev->kdrv) { 746c752998bSGaetan Rivet #ifdef VFIO_PRESENT 7477c0d798aSDavid Marchand case RTE_PCI_KDRV_VFIO: 748c752998bSGaetan Rivet pci_vfio_ioport_write(p, data, len, offset); 749c752998bSGaetan Rivet break; 750c752998bSGaetan Rivet #endif 7517c0d798aSDavid Marchand case RTE_PCI_KDRV_IGB_UIO: 7527c0d798aSDavid Marchand case RTE_PCI_KDRV_UIO_GENERIC: 753c752998bSGaetan Rivet pci_uio_ioport_write(p, data, len, offset); 754c752998bSGaetan Rivet break; 755c752998bSGaetan Rivet default: 756c752998bSGaetan Rivet break; 757c752998bSGaetan Rivet } 758c752998bSGaetan Rivet } 759c752998bSGaetan Rivet 760c752998bSGaetan Rivet int 761c752998bSGaetan Rivet rte_pci_ioport_unmap(struct rte_pci_ioport *p) 762c752998bSGaetan Rivet { 763c752998bSGaetan Rivet int ret = -1; 764c752998bSGaetan Rivet 765c752998bSGaetan Rivet switch (p->dev->kdrv) { 766c752998bSGaetan Rivet #ifdef VFIO_PRESENT 7677c0d798aSDavid Marchand case RTE_PCI_KDRV_VFIO: 768c752998bSGaetan Rivet if (pci_vfio_is_enabled()) 769c752998bSGaetan Rivet ret = pci_vfio_ioport_unmap(p); 770c752998bSGaetan Rivet break; 771c752998bSGaetan Rivet #endif 7727c0d798aSDavid Marchand case RTE_PCI_KDRV_IGB_UIO: 7737c0d798aSDavid Marchand case RTE_PCI_KDRV_UIO_GENERIC: 774c752998bSGaetan Rivet ret = pci_uio_ioport_unmap(p); 775c752998bSGaetan Rivet break; 776c752998bSGaetan Rivet default: 777c752998bSGaetan Rivet break; 778c752998bSGaetan Rivet } 779c752998bSGaetan Rivet 780c752998bSGaetan Rivet return ret; 781c752998bSGaetan Rivet } 782