15566a3e3SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 25566a3e3SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation 3c752998bSGaetan Rivet */ 4c752998bSGaetan Rivet 5c752998bSGaetan Rivet #include <ctype.h> 6c752998bSGaetan Rivet #include <stdio.h> 7c752998bSGaetan Rivet #include <stdlib.h> 8c752998bSGaetan Rivet #include <string.h> 9c752998bSGaetan Rivet #include <stdarg.h> 10c752998bSGaetan Rivet #include <unistd.h> 11c752998bSGaetan Rivet #include <inttypes.h> 12c752998bSGaetan Rivet #include <sys/types.h> 13c752998bSGaetan Rivet #include <sys/stat.h> 14c752998bSGaetan Rivet #include <fcntl.h> 15c752998bSGaetan Rivet #include <errno.h> 16c752998bSGaetan Rivet #include <dirent.h> 17c752998bSGaetan Rivet #include <limits.h> 18c752998bSGaetan Rivet #include <sys/queue.h> 19c752998bSGaetan Rivet #include <sys/mman.h> 20c752998bSGaetan Rivet #include <sys/ioctl.h> 21c752998bSGaetan Rivet #include <sys/pciio.h> 22c752998bSGaetan Rivet #include <dev/pci/pcireg.h> 23c752998bSGaetan Rivet 24c752998bSGaetan Rivet #if defined(RTE_ARCH_X86) 25c752998bSGaetan Rivet #include <machine/cpufunc.h> 26c752998bSGaetan Rivet #endif 27c752998bSGaetan Rivet 28c752998bSGaetan Rivet #include <rte_interrupts.h> 29c752998bSGaetan Rivet #include <rte_log.h> 30c752998bSGaetan Rivet #include <rte_pci.h> 31c752998bSGaetan Rivet #include <rte_common.h> 32c752998bSGaetan Rivet #include <rte_launch.h> 33c752998bSGaetan Rivet #include <rte_memory.h> 34c752998bSGaetan Rivet #include <rte_eal.h> 35c752998bSGaetan Rivet #include <rte_per_lcore.h> 36c752998bSGaetan Rivet #include <rte_lcore.h> 37c752998bSGaetan Rivet #include <rte_malloc.h> 38c752998bSGaetan Rivet #include <rte_string_fns.h> 39c752998bSGaetan Rivet #include <rte_debug.h> 40c752998bSGaetan Rivet #include <rte_devargs.h> 41c752998bSGaetan Rivet 42c752998bSGaetan Rivet #include "eal_filesystem.h" 43c752998bSGaetan Rivet #include "private.h" 44c752998bSGaetan Rivet 45c752998bSGaetan Rivet /** 46c752998bSGaetan Rivet * @file 47aa777f00SThomas Monjalon * PCI probing under BSD. 48c752998bSGaetan Rivet */ 49c752998bSGaetan Rivet 50c752998bSGaetan Rivet /* Map pci device */ 51c752998bSGaetan Rivet int 52c752998bSGaetan Rivet rte_pci_map_device(struct rte_pci_device *dev) 53c752998bSGaetan Rivet { 54c752998bSGaetan Rivet int ret = -1; 55c752998bSGaetan Rivet 56c752998bSGaetan Rivet /* try mapping the NIC resources */ 57c752998bSGaetan Rivet switch (dev->kdrv) { 587c0d798aSDavid Marchand case RTE_PCI_KDRV_NIC_UIO: 59c752998bSGaetan Rivet /* map resources for devices that use uio */ 60c752998bSGaetan Rivet ret = pci_uio_map_resource(dev); 61c752998bSGaetan Rivet break; 62c752998bSGaetan Rivet default: 63c752998bSGaetan Rivet RTE_LOG(DEBUG, EAL, 64c752998bSGaetan Rivet " Not managed by a supported kernel driver, skipped\n"); 65c752998bSGaetan Rivet ret = 1; 66c752998bSGaetan Rivet break; 67c752998bSGaetan Rivet } 68c752998bSGaetan Rivet 69c752998bSGaetan Rivet return ret; 70c752998bSGaetan Rivet } 71c752998bSGaetan Rivet 72c752998bSGaetan Rivet /* Unmap pci device */ 73c752998bSGaetan Rivet void 74c752998bSGaetan Rivet rte_pci_unmap_device(struct rte_pci_device *dev) 75c752998bSGaetan Rivet { 76c752998bSGaetan Rivet /* try unmapping the NIC resources */ 77c752998bSGaetan Rivet switch (dev->kdrv) { 787c0d798aSDavid Marchand case RTE_PCI_KDRV_NIC_UIO: 79c752998bSGaetan Rivet /* unmap resources for devices that use uio */ 80c752998bSGaetan Rivet pci_uio_unmap_resource(dev); 81c752998bSGaetan Rivet break; 82c752998bSGaetan Rivet default: 83c752998bSGaetan Rivet RTE_LOG(DEBUG, EAL, 84c752998bSGaetan Rivet " Not managed by a supported kernel driver, skipped\n"); 85c752998bSGaetan Rivet break; 86c752998bSGaetan Rivet } 87c752998bSGaetan Rivet } 88c752998bSGaetan Rivet 89c752998bSGaetan Rivet void 90c752998bSGaetan Rivet pci_uio_free_resource(struct rte_pci_device *dev, 91c752998bSGaetan Rivet struct mapped_pci_resource *uio_res) 92c752998bSGaetan Rivet { 93c752998bSGaetan Rivet rte_free(uio_res); 94c752998bSGaetan Rivet 95d61138d4SHarman Kalra if (rte_intr_fd_get(dev->intr_handle)) { 96d61138d4SHarman Kalra close(rte_intr_fd_get(dev->intr_handle)); 97d61138d4SHarman Kalra rte_intr_fd_set(dev->intr_handle, -1); 98d61138d4SHarman Kalra rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN); 99c752998bSGaetan Rivet } 100c752998bSGaetan Rivet } 101c752998bSGaetan Rivet 102c752998bSGaetan Rivet int 103c752998bSGaetan Rivet pci_uio_alloc_resource(struct rte_pci_device *dev, 104c752998bSGaetan Rivet struct mapped_pci_resource **uio_res) 105c752998bSGaetan Rivet { 106c752998bSGaetan Rivet char devname[PATH_MAX]; /* contains the /dev/uioX */ 107c752998bSGaetan Rivet struct rte_pci_addr *loc; 108c752998bSGaetan Rivet 109c752998bSGaetan Rivet loc = &dev->addr; 110c752998bSGaetan Rivet 111c752998bSGaetan Rivet snprintf(devname, sizeof(devname), "/dev/uio@pci:%u:%u:%u", 112c752998bSGaetan Rivet dev->addr.bus, dev->addr.devid, dev->addr.function); 113c752998bSGaetan Rivet 114c752998bSGaetan Rivet if (access(devname, O_RDWR) < 0) { 115c752998bSGaetan Rivet RTE_LOG(WARNING, EAL, " "PCI_PRI_FMT" not managed by UIO driver, " 116c752998bSGaetan Rivet "skipping\n", loc->domain, loc->bus, loc->devid, loc->function); 117c752998bSGaetan Rivet return 1; 118c752998bSGaetan Rivet } 119c752998bSGaetan Rivet 120c752998bSGaetan Rivet /* save fd if in primary process */ 121d61138d4SHarman Kalra if (rte_intr_fd_set(dev->intr_handle, open(devname, O_RDWR))) { 122d61138d4SHarman Kalra RTE_LOG(WARNING, EAL, "Failed to save fd"); 123d61138d4SHarman Kalra goto error; 124d61138d4SHarman Kalra } 125d61138d4SHarman Kalra 126d61138d4SHarman Kalra if (rte_intr_fd_get(dev->intr_handle) < 0) { 127c752998bSGaetan Rivet RTE_LOG(ERR, EAL, "Cannot open %s: %s\n", 128c752998bSGaetan Rivet devname, strerror(errno)); 129c752998bSGaetan Rivet goto error; 130c752998bSGaetan Rivet } 131d61138d4SHarman Kalra 132d61138d4SHarman Kalra if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UIO)) 133d61138d4SHarman Kalra goto error; 134c752998bSGaetan Rivet 135c752998bSGaetan Rivet /* allocate the mapping details for secondary processes*/ 136c752998bSGaetan Rivet *uio_res = rte_zmalloc("UIO_RES", sizeof(**uio_res), 0); 137c752998bSGaetan Rivet if (*uio_res == NULL) { 138c752998bSGaetan Rivet RTE_LOG(ERR, EAL, 139c752998bSGaetan Rivet "%s(): cannot store uio mmap details\n", __func__); 140c752998bSGaetan Rivet goto error; 141c752998bSGaetan Rivet } 142c752998bSGaetan Rivet 143f9acaf84SBruce Richardson strlcpy((*uio_res)->path, devname, sizeof((*uio_res)->path)); 144c752998bSGaetan Rivet memcpy(&(*uio_res)->pci_addr, &dev->addr, sizeof((*uio_res)->pci_addr)); 145c752998bSGaetan Rivet 146c752998bSGaetan Rivet return 0; 147c752998bSGaetan Rivet 148c752998bSGaetan Rivet error: 149c752998bSGaetan Rivet pci_uio_free_resource(dev, *uio_res); 150c752998bSGaetan Rivet return -1; 151c752998bSGaetan Rivet } 152c752998bSGaetan Rivet 153c752998bSGaetan Rivet int 154c752998bSGaetan Rivet pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx, 155c752998bSGaetan Rivet struct mapped_pci_resource *uio_res, int map_idx) 156c752998bSGaetan Rivet { 157c752998bSGaetan Rivet int fd; 158c752998bSGaetan Rivet char *devname; 159c752998bSGaetan Rivet void *mapaddr; 160c752998bSGaetan Rivet uint64_t offset; 161c752998bSGaetan Rivet uint64_t pagesz; 162c752998bSGaetan Rivet struct pci_map *maps; 163c752998bSGaetan Rivet 164c752998bSGaetan Rivet maps = uio_res->maps; 165c752998bSGaetan Rivet devname = uio_res->path; 166c752998bSGaetan Rivet pagesz = sysconf(_SC_PAGESIZE); 167c752998bSGaetan Rivet 168c752998bSGaetan Rivet /* allocate memory to keep path */ 169c752998bSGaetan Rivet maps[map_idx].path = rte_malloc(NULL, strlen(devname) + 1, 0); 170c752998bSGaetan Rivet if (maps[map_idx].path == NULL) { 171c752998bSGaetan Rivet RTE_LOG(ERR, EAL, "Cannot allocate memory for path: %s\n", 172c752998bSGaetan Rivet strerror(errno)); 173c752998bSGaetan Rivet return -1; 174c752998bSGaetan Rivet } 175c752998bSGaetan Rivet 176c752998bSGaetan Rivet /* 177c752998bSGaetan Rivet * open resource file, to mmap it 178c752998bSGaetan Rivet */ 179c752998bSGaetan Rivet fd = open(devname, O_RDWR); 180c752998bSGaetan Rivet if (fd < 0) { 181c752998bSGaetan Rivet RTE_LOG(ERR, EAL, "Cannot open %s: %s\n", 182c752998bSGaetan Rivet devname, strerror(errno)); 183c752998bSGaetan Rivet goto error; 184c752998bSGaetan Rivet } 185c752998bSGaetan Rivet 186c752998bSGaetan Rivet /* if matching map is found, then use it */ 187c752998bSGaetan Rivet offset = res_idx * pagesz; 188c752998bSGaetan Rivet mapaddr = pci_map_resource(NULL, fd, (off_t)offset, 189c752998bSGaetan Rivet (size_t)dev->mem_resource[res_idx].len, 0); 190c752998bSGaetan Rivet close(fd); 191e200535cSDavid Marchand if (mapaddr == NULL) 192c752998bSGaetan Rivet goto error; 193c752998bSGaetan Rivet 194c752998bSGaetan Rivet maps[map_idx].phaddr = dev->mem_resource[res_idx].phys_addr; 195c752998bSGaetan Rivet maps[map_idx].size = dev->mem_resource[res_idx].len; 196c752998bSGaetan Rivet maps[map_idx].addr = mapaddr; 197c752998bSGaetan Rivet maps[map_idx].offset = offset; 198c752998bSGaetan Rivet strcpy(maps[map_idx].path, devname); 199c752998bSGaetan Rivet dev->mem_resource[res_idx].addr = mapaddr; 200c752998bSGaetan Rivet 201c752998bSGaetan Rivet return 0; 202c752998bSGaetan Rivet 203c752998bSGaetan Rivet error: 204c752998bSGaetan Rivet rte_free(maps[map_idx].path); 205c752998bSGaetan Rivet return -1; 206c752998bSGaetan Rivet } 207c752998bSGaetan Rivet 208c752998bSGaetan Rivet static int 209c752998bSGaetan Rivet pci_scan_one(int dev_pci_fd, struct pci_conf *conf) 210c752998bSGaetan Rivet { 21187a02023SChenbo Xia struct rte_pci_device_internal *pdev; 212c752998bSGaetan Rivet struct rte_pci_device *dev; 213c752998bSGaetan Rivet struct pci_bar_io bar; 214c752998bSGaetan Rivet unsigned i, max; 215c752998bSGaetan Rivet 21687a02023SChenbo Xia pdev = malloc(sizeof(*pdev)); 21787a02023SChenbo Xia if (pdev == NULL) { 21887a02023SChenbo Xia RTE_LOG(ERR, EAL, "Cannot allocate memory for internal pci device\n"); 219c752998bSGaetan Rivet return -1; 220c752998bSGaetan Rivet } 221c752998bSGaetan Rivet 22287a02023SChenbo Xia memset(pdev, 0, sizeof(*pdev)); 22387a02023SChenbo Xia dev = &pdev->device; 2246844d146SThomas Monjalon dev->device.bus = &rte_pci_bus.bus; 2256844d146SThomas Monjalon 226c752998bSGaetan Rivet dev->addr.domain = conf->pc_sel.pc_domain; 227c752998bSGaetan Rivet dev->addr.bus = conf->pc_sel.pc_bus; 228c752998bSGaetan Rivet dev->addr.devid = conf->pc_sel.pc_dev; 229c752998bSGaetan Rivet dev->addr.function = conf->pc_sel.pc_func; 230c752998bSGaetan Rivet 231c752998bSGaetan Rivet /* get vendor id */ 232c752998bSGaetan Rivet dev->id.vendor_id = conf->pc_vendor; 233c752998bSGaetan Rivet 234c752998bSGaetan Rivet /* get device id */ 235c752998bSGaetan Rivet dev->id.device_id = conf->pc_device; 236c752998bSGaetan Rivet 237c752998bSGaetan Rivet /* get subsystem_vendor id */ 238c752998bSGaetan Rivet dev->id.subsystem_vendor_id = conf->pc_subvendor; 239c752998bSGaetan Rivet 240c752998bSGaetan Rivet /* get subsystem_device id */ 241c752998bSGaetan Rivet dev->id.subsystem_device_id = conf->pc_subdevice; 242c752998bSGaetan Rivet 243c752998bSGaetan Rivet /* get class id */ 244c752998bSGaetan Rivet dev->id.class_id = (conf->pc_class << 16) | 245c752998bSGaetan Rivet (conf->pc_subclass << 8) | 246c752998bSGaetan Rivet (conf->pc_progif); 247c752998bSGaetan Rivet 248c752998bSGaetan Rivet /* TODO: get max_vfs */ 249c752998bSGaetan Rivet dev->max_vfs = 0; 250c752998bSGaetan Rivet 251c752998bSGaetan Rivet /* FreeBSD has no NUMA support (yet) */ 2527dcd73e3SOlivier Matz dev->device.numa_node = SOCKET_ID_ANY; 253c752998bSGaetan Rivet 2548f4de2dbSDavid Marchand pci_common_set(dev); 255c752998bSGaetan Rivet 256c752998bSGaetan Rivet /* FreeBSD has only one pass through driver */ 2577c0d798aSDavid Marchand dev->kdrv = RTE_PCI_KDRV_NIC_UIO; 258c752998bSGaetan Rivet 259c752998bSGaetan Rivet /* parse resources */ 260c752998bSGaetan Rivet switch (conf->pc_hdr & PCIM_HDRTYPE) { 261c752998bSGaetan Rivet case PCIM_HDRTYPE_NORMAL: 262c752998bSGaetan Rivet max = PCIR_MAX_BAR_0; 263c752998bSGaetan Rivet break; 264c752998bSGaetan Rivet case PCIM_HDRTYPE_BRIDGE: 265c752998bSGaetan Rivet max = PCIR_MAX_BAR_1; 266c752998bSGaetan Rivet break; 267c752998bSGaetan Rivet case PCIM_HDRTYPE_CARDBUS: 268c752998bSGaetan Rivet max = PCIR_MAX_BAR_2; 269c752998bSGaetan Rivet break; 270c752998bSGaetan Rivet default: 271c752998bSGaetan Rivet goto skipdev; 272c752998bSGaetan Rivet } 273c752998bSGaetan Rivet 274c752998bSGaetan Rivet for (i = 0; i <= max; i++) { 275c752998bSGaetan Rivet bar.pbi_sel = conf->pc_sel; 276c752998bSGaetan Rivet bar.pbi_reg = PCIR_BAR(i); 277c752998bSGaetan Rivet if (ioctl(dev_pci_fd, PCIOCGETBAR, &bar) < 0) 278c752998bSGaetan Rivet continue; 279c752998bSGaetan Rivet 280c752998bSGaetan Rivet dev->mem_resource[i].len = bar.pbi_length; 281c752998bSGaetan Rivet if (PCI_BAR_IO(bar.pbi_base)) { 282c752998bSGaetan Rivet dev->mem_resource[i].addr = (void *)(bar.pbi_base & ~((uint64_t)0xf)); 283c752998bSGaetan Rivet continue; 284c752998bSGaetan Rivet } 285c752998bSGaetan Rivet dev->mem_resource[i].phys_addr = bar.pbi_base & ~((uint64_t)0xf); 286c752998bSGaetan Rivet } 287c752998bSGaetan Rivet 288c752998bSGaetan Rivet /* device is valid, add in list (sorted) */ 289c752998bSGaetan Rivet if (TAILQ_EMPTY(&rte_pci_bus.device_list)) { 290c752998bSGaetan Rivet rte_pci_add_device(dev); 291c752998bSGaetan Rivet } 292c752998bSGaetan Rivet else { 293c752998bSGaetan Rivet struct rte_pci_device *dev2 = NULL; 294c752998bSGaetan Rivet int ret; 295c752998bSGaetan Rivet 296c752998bSGaetan Rivet TAILQ_FOREACH(dev2, &rte_pci_bus.device_list, next) { 2970e3ef055SGaetan Rivet ret = rte_pci_addr_cmp(&dev->addr, &dev2->addr); 298c752998bSGaetan Rivet if (ret > 0) 299c752998bSGaetan Rivet continue; 300c752998bSGaetan Rivet else if (ret < 0) { 301c752998bSGaetan Rivet rte_pci_insert_device(dev2, dev); 302c752998bSGaetan Rivet } else { /* already registered */ 303c752998bSGaetan Rivet dev2->kdrv = dev->kdrv; 304c752998bSGaetan Rivet dev2->max_vfs = dev->max_vfs; 3058f4de2dbSDavid Marchand pci_common_set(dev2); 306c752998bSGaetan Rivet memmove(dev2->mem_resource, 307c752998bSGaetan Rivet dev->mem_resource, 308c752998bSGaetan Rivet sizeof(dev->mem_resource)); 30987a02023SChenbo Xia pci_free(pdev); 310c752998bSGaetan Rivet } 311c752998bSGaetan Rivet return 0; 312c752998bSGaetan Rivet } 313c752998bSGaetan Rivet rte_pci_add_device(dev); 314c752998bSGaetan Rivet } 315c752998bSGaetan Rivet 316c752998bSGaetan Rivet return 0; 317c752998bSGaetan Rivet 318c752998bSGaetan Rivet skipdev: 31987a02023SChenbo Xia pci_free(pdev); 320c752998bSGaetan Rivet return 0; 321c752998bSGaetan Rivet } 322c752998bSGaetan Rivet 323c752998bSGaetan Rivet /* 324c752998bSGaetan Rivet * Scan the content of the PCI bus, and add the devices in the devices 325c752998bSGaetan Rivet * list. Call pci_scan_one() for each pci entry found. 326c752998bSGaetan Rivet */ 327c752998bSGaetan Rivet int 328c752998bSGaetan Rivet rte_pci_scan(void) 329c752998bSGaetan Rivet { 330c752998bSGaetan Rivet int fd; 331c752998bSGaetan Rivet unsigned dev_count = 0; 332c752998bSGaetan Rivet struct pci_conf matches[16]; 333c752998bSGaetan Rivet struct pci_conf_io conf_io = { 334c752998bSGaetan Rivet .pat_buf_len = 0, 335c752998bSGaetan Rivet .num_patterns = 0, 336c752998bSGaetan Rivet .patterns = NULL, 337c752998bSGaetan Rivet .match_buf_len = sizeof(matches), 338c752998bSGaetan Rivet .matches = &matches[0], 339c752998bSGaetan Rivet }; 340463a5245SSunil Kumar Kori struct rte_pci_addr pci_addr; 341c752998bSGaetan Rivet 342c752998bSGaetan Rivet /* for debug purposes, PCI can be disabled */ 343c752998bSGaetan Rivet if (!rte_eal_has_pci()) 344c752998bSGaetan Rivet return 0; 345c752998bSGaetan Rivet 346c752998bSGaetan Rivet fd = open("/dev/pci", O_RDONLY); 347c752998bSGaetan Rivet if (fd < 0) { 348c752998bSGaetan Rivet RTE_LOG(ERR, EAL, "%s(): error opening /dev/pci\n", __func__); 349c752998bSGaetan Rivet goto error; 350c752998bSGaetan Rivet } 351c752998bSGaetan Rivet 352c752998bSGaetan Rivet do { 353c752998bSGaetan Rivet unsigned i; 354c752998bSGaetan Rivet if (ioctl(fd, PCIOCGETCONF, &conf_io) < 0) { 355c752998bSGaetan Rivet RTE_LOG(ERR, EAL, "%s(): error with ioctl on /dev/pci: %s\n", 356c752998bSGaetan Rivet __func__, strerror(errno)); 357c752998bSGaetan Rivet goto error; 358c752998bSGaetan Rivet } 359c752998bSGaetan Rivet 360463a5245SSunil Kumar Kori for (i = 0; i < conf_io.num_matches; i++) { 361463a5245SSunil Kumar Kori pci_addr.domain = matches[i].pc_sel.pc_domain; 362463a5245SSunil Kumar Kori pci_addr.bus = matches[i].pc_sel.pc_bus; 363463a5245SSunil Kumar Kori pci_addr.devid = matches[i].pc_sel.pc_dev; 364463a5245SSunil Kumar Kori pci_addr.function = matches[i].pc_sel.pc_func; 365463a5245SSunil Kumar Kori 366463a5245SSunil Kumar Kori if (rte_pci_ignore_device(&pci_addr)) 367463a5245SSunil Kumar Kori continue; 368463a5245SSunil Kumar Kori 369c752998bSGaetan Rivet if (pci_scan_one(fd, &matches[i]) < 0) 370c752998bSGaetan Rivet goto error; 371463a5245SSunil Kumar Kori } 372c752998bSGaetan Rivet 373c752998bSGaetan Rivet dev_count += conf_io.num_matches; 374c752998bSGaetan Rivet } while(conf_io.status == PCI_GETCONF_MORE_DEVS); 375c752998bSGaetan Rivet 376c752998bSGaetan Rivet close(fd); 377c752998bSGaetan Rivet 378c752998bSGaetan Rivet RTE_LOG(DEBUG, EAL, "PCI scan found %u devices\n", dev_count); 379c752998bSGaetan Rivet return 0; 380c752998bSGaetan Rivet 381c752998bSGaetan Rivet error: 382c752998bSGaetan Rivet if (fd >= 0) 383c752998bSGaetan Rivet close(fd); 384c752998bSGaetan Rivet return -1; 385c752998bSGaetan Rivet } 386c752998bSGaetan Rivet 38766d3724bSDavid Marchand bool 38866d3724bSDavid Marchand pci_device_iommu_support_va(__rte_unused const struct rte_pci_device *dev) 38966d3724bSDavid Marchand { 39066d3724bSDavid Marchand return false; 39166d3724bSDavid Marchand } 39266d3724bSDavid Marchand 393c752998bSGaetan Rivet enum rte_iova_mode 394703458e1SBen Walker pci_device_iova_mode(const struct rte_pci_driver *pdrv __rte_unused, 395703458e1SBen Walker const struct rte_pci_device *pdev) 396c752998bSGaetan Rivet { 3977c0d798aSDavid Marchand if (pdev->kdrv != RTE_PCI_KDRV_NIC_UIO) 398703458e1SBen Walker RTE_LOG(DEBUG, EAL, "Unsupported kernel driver? Defaulting to IOVA as 'PA'\n"); 399703458e1SBen Walker 400c752998bSGaetan Rivet return RTE_IOVA_PA; 401c752998bSGaetan Rivet } 402c752998bSGaetan Rivet 403c752998bSGaetan Rivet /* Read PCI config space. */ 404c752998bSGaetan Rivet int rte_pci_read_config(const struct rte_pci_device *dev, 405c752998bSGaetan Rivet void *buf, size_t len, off_t offset) 406c752998bSGaetan Rivet { 407c752998bSGaetan Rivet int fd = -1; 408c752998bSGaetan Rivet int size; 409e8d435f1SLuca Boccassi /* Copy Linux implementation's behaviour */ 410e8d435f1SLuca Boccassi const int return_len = len; 411c752998bSGaetan Rivet struct pci_io pi = { 412c752998bSGaetan Rivet .pi_sel = { 413c752998bSGaetan Rivet .pc_domain = dev->addr.domain, 414c752998bSGaetan Rivet .pc_bus = dev->addr.bus, 415c752998bSGaetan Rivet .pc_dev = dev->addr.devid, 416c752998bSGaetan Rivet .pc_func = dev->addr.function, 417c752998bSGaetan Rivet }, 418c752998bSGaetan Rivet .pi_reg = offset, 419c752998bSGaetan Rivet }; 420c752998bSGaetan Rivet 421c752998bSGaetan Rivet fd = open("/dev/pci", O_RDWR); 422c752998bSGaetan Rivet if (fd < 0) { 423c752998bSGaetan Rivet RTE_LOG(ERR, EAL, "%s(): error opening /dev/pci\n", __func__); 424c752998bSGaetan Rivet goto error; 425c752998bSGaetan Rivet } 426c752998bSGaetan Rivet 427c752998bSGaetan Rivet while (len > 0) { 428c752998bSGaetan Rivet size = (len >= 4) ? 4 : ((len >= 2) ? 2 : 1); 429c752998bSGaetan Rivet pi.pi_width = size; 430c752998bSGaetan Rivet 431c752998bSGaetan Rivet if (ioctl(fd, PCIOCREAD, &pi) < 0) 432c752998bSGaetan Rivet goto error; 433c752998bSGaetan Rivet memcpy(buf, &pi.pi_data, size); 434c752998bSGaetan Rivet 435c752998bSGaetan Rivet buf = (char *)buf + size; 436c752998bSGaetan Rivet pi.pi_reg += size; 437c752998bSGaetan Rivet len -= size; 438c752998bSGaetan Rivet } 439c752998bSGaetan Rivet close(fd); 440c752998bSGaetan Rivet 441e8d435f1SLuca Boccassi return return_len; 442c752998bSGaetan Rivet 443c752998bSGaetan Rivet error: 444c752998bSGaetan Rivet if (fd >= 0) 445c752998bSGaetan Rivet close(fd); 446c752998bSGaetan Rivet return -1; 447c752998bSGaetan Rivet } 448c752998bSGaetan Rivet 449c752998bSGaetan Rivet /* Write PCI config space. */ 450c752998bSGaetan Rivet int rte_pci_write_config(const struct rte_pci_device *dev, 451c752998bSGaetan Rivet const void *buf, size_t len, off_t offset) 452c752998bSGaetan Rivet { 453c752998bSGaetan Rivet int fd = -1; 454c752998bSGaetan Rivet 455c752998bSGaetan Rivet struct pci_io pi = { 456c752998bSGaetan Rivet .pi_sel = { 457c752998bSGaetan Rivet .pc_domain = dev->addr.domain, 458c752998bSGaetan Rivet .pc_bus = dev->addr.bus, 459c752998bSGaetan Rivet .pc_dev = dev->addr.devid, 460c752998bSGaetan Rivet .pc_func = dev->addr.function, 461c752998bSGaetan Rivet }, 462c752998bSGaetan Rivet .pi_reg = offset, 463c752998bSGaetan Rivet .pi_data = *(const uint32_t *)buf, 464c752998bSGaetan Rivet .pi_width = len, 465c752998bSGaetan Rivet }; 466c752998bSGaetan Rivet 467c752998bSGaetan Rivet if (len == 3 || len > sizeof(pi.pi_data)) { 468c752998bSGaetan Rivet RTE_LOG(ERR, EAL, "%s(): invalid pci read length\n", __func__); 469c752998bSGaetan Rivet goto error; 470c752998bSGaetan Rivet } 471c752998bSGaetan Rivet 472c752998bSGaetan Rivet memcpy(&pi.pi_data, buf, len); 473c752998bSGaetan Rivet 474c752998bSGaetan Rivet fd = open("/dev/pci", O_RDWR); 475c752998bSGaetan Rivet if (fd < 0) { 476c752998bSGaetan Rivet RTE_LOG(ERR, EAL, "%s(): error opening /dev/pci\n", __func__); 477c752998bSGaetan Rivet goto error; 478c752998bSGaetan Rivet } 479c752998bSGaetan Rivet 480c752998bSGaetan Rivet if (ioctl(fd, PCIOCWRITE, &pi) < 0) 481c752998bSGaetan Rivet goto error; 482c752998bSGaetan Rivet 483c752998bSGaetan Rivet close(fd); 484c752998bSGaetan Rivet return 0; 485c752998bSGaetan Rivet 486c752998bSGaetan Rivet error: 487c752998bSGaetan Rivet if (fd >= 0) 488c752998bSGaetan Rivet close(fd); 489c752998bSGaetan Rivet return -1; 490c752998bSGaetan Rivet } 491c752998bSGaetan Rivet 492*095cf6e6SChenbo Xia /* Read PCI MMIO space. */ 493*095cf6e6SChenbo Xia int rte_pci_mmio_read(const struct rte_pci_device *dev, int bar, 494*095cf6e6SChenbo Xia void *buf, size_t len, off_t offset) 495*095cf6e6SChenbo Xia { 496*095cf6e6SChenbo Xia if (bar >= PCI_MAX_RESOURCE || dev->mem_resource[bar].addr == NULL || 497*095cf6e6SChenbo Xia (uint64_t)offset + len > dev->mem_resource[bar].len) 498*095cf6e6SChenbo Xia return -1; 499*095cf6e6SChenbo Xia memcpy(buf, (uint8_t *)dev->mem_resource[bar].addr + offset, len); 500*095cf6e6SChenbo Xia return len; 501*095cf6e6SChenbo Xia } 502*095cf6e6SChenbo Xia 503*095cf6e6SChenbo Xia /* Write PCI MMIO space. */ 504*095cf6e6SChenbo Xia int rte_pci_mmio_write(const struct rte_pci_device *dev, int bar, 505*095cf6e6SChenbo Xia const void *buf, size_t len, off_t offset) 506*095cf6e6SChenbo Xia { 507*095cf6e6SChenbo Xia if (bar >= PCI_MAX_RESOURCE || dev->mem_resource[bar].addr == NULL || 508*095cf6e6SChenbo Xia (uint64_t)offset + len > dev->mem_resource[bar].len) 509*095cf6e6SChenbo Xia return -1; 510*095cf6e6SChenbo Xia memcpy((uint8_t *)dev->mem_resource[bar].addr + offset, buf, len); 511*095cf6e6SChenbo Xia return len; 512*095cf6e6SChenbo Xia } 513*095cf6e6SChenbo Xia 514c752998bSGaetan Rivet int 515c752998bSGaetan Rivet rte_pci_ioport_map(struct rte_pci_device *dev, int bar, 516c752998bSGaetan Rivet struct rte_pci_ioport *p) 517c752998bSGaetan Rivet { 518c752998bSGaetan Rivet int ret; 519c752998bSGaetan Rivet 520c752998bSGaetan Rivet switch (dev->kdrv) { 521c752998bSGaetan Rivet #if defined(RTE_ARCH_X86) 5227c0d798aSDavid Marchand case RTE_PCI_KDRV_NIC_UIO: 523e02b661bSDavid Marchand if (rte_eal_iopl_init() != 0) { 524e02b661bSDavid Marchand RTE_LOG(ERR, EAL, "%s(): insufficient ioport permissions for PCI device %s\n", 525e02b661bSDavid Marchand __func__, dev->name); 526e02b661bSDavid Marchand return -1; 527e02b661bSDavid Marchand } 528c752998bSGaetan Rivet if ((uintptr_t) dev->mem_resource[bar].addr <= UINT16_MAX) { 529c752998bSGaetan Rivet p->base = (uintptr_t)dev->mem_resource[bar].addr; 530c752998bSGaetan Rivet ret = 0; 531c752998bSGaetan Rivet } else 532c752998bSGaetan Rivet ret = -1; 533c752998bSGaetan Rivet break; 534c752998bSGaetan Rivet #endif 535c752998bSGaetan Rivet default: 536c752998bSGaetan Rivet ret = -1; 537c752998bSGaetan Rivet break; 538c752998bSGaetan Rivet } 539c752998bSGaetan Rivet 540c752998bSGaetan Rivet if (!ret) 541c752998bSGaetan Rivet p->dev = dev; 542c752998bSGaetan Rivet 543c752998bSGaetan Rivet return ret; 544c752998bSGaetan Rivet } 545c752998bSGaetan Rivet 546c752998bSGaetan Rivet static void 547c752998bSGaetan Rivet pci_uio_ioport_read(struct rte_pci_ioport *p, 548c752998bSGaetan Rivet void *data, size_t len, off_t offset) 549c752998bSGaetan Rivet { 550c752998bSGaetan Rivet #if defined(RTE_ARCH_X86) 551c752998bSGaetan Rivet uint8_t *d; 552c752998bSGaetan Rivet int size; 553c752998bSGaetan Rivet unsigned short reg = p->base + offset; 554c752998bSGaetan Rivet 555c752998bSGaetan Rivet for (d = data; len > 0; d += size, reg += size, len -= size) { 556c752998bSGaetan Rivet if (len >= 4) { 557c752998bSGaetan Rivet size = 4; 558c752998bSGaetan Rivet *(uint32_t *)d = inl(reg); 559c752998bSGaetan Rivet } else if (len >= 2) { 560c752998bSGaetan Rivet size = 2; 561c752998bSGaetan Rivet *(uint16_t *)d = inw(reg); 562c752998bSGaetan Rivet } else { 563c752998bSGaetan Rivet size = 1; 564c752998bSGaetan Rivet *d = inb(reg); 565c752998bSGaetan Rivet } 566c752998bSGaetan Rivet } 567c752998bSGaetan Rivet #else 568c752998bSGaetan Rivet RTE_SET_USED(p); 569c752998bSGaetan Rivet RTE_SET_USED(data); 570c752998bSGaetan Rivet RTE_SET_USED(len); 571c752998bSGaetan Rivet RTE_SET_USED(offset); 572c752998bSGaetan Rivet #endif 573c752998bSGaetan Rivet } 574c752998bSGaetan Rivet 575c752998bSGaetan Rivet void 576c752998bSGaetan Rivet rte_pci_ioport_read(struct rte_pci_ioport *p, 577c752998bSGaetan Rivet void *data, size_t len, off_t offset) 578c752998bSGaetan Rivet { 579c752998bSGaetan Rivet switch (p->dev->kdrv) { 5807c0d798aSDavid Marchand case RTE_PCI_KDRV_NIC_UIO: 581c752998bSGaetan Rivet pci_uio_ioport_read(p, data, len, offset); 582c752998bSGaetan Rivet break; 583c752998bSGaetan Rivet default: 584c752998bSGaetan Rivet break; 585c752998bSGaetan Rivet } 586c752998bSGaetan Rivet } 587c752998bSGaetan Rivet 588c752998bSGaetan Rivet static void 589c752998bSGaetan Rivet pci_uio_ioport_write(struct rte_pci_ioport *p, 590c752998bSGaetan Rivet const void *data, size_t len, off_t offset) 591c752998bSGaetan Rivet { 592c752998bSGaetan Rivet #if defined(RTE_ARCH_X86) 593c752998bSGaetan Rivet const uint8_t *s; 594c752998bSGaetan Rivet int size; 595c752998bSGaetan Rivet unsigned short reg = p->base + offset; 596c752998bSGaetan Rivet 597c752998bSGaetan Rivet for (s = data; len > 0; s += size, reg += size, len -= size) { 598c752998bSGaetan Rivet if (len >= 4) { 599c752998bSGaetan Rivet size = 4; 600c752998bSGaetan Rivet outl(reg, *(const uint32_t *)s); 601c752998bSGaetan Rivet } else if (len >= 2) { 602c752998bSGaetan Rivet size = 2; 603c752998bSGaetan Rivet outw(reg, *(const uint16_t *)s); 604c752998bSGaetan Rivet } else { 605c752998bSGaetan Rivet size = 1; 606c752998bSGaetan Rivet outb(reg, *s); 607c752998bSGaetan Rivet } 608c752998bSGaetan Rivet } 609c752998bSGaetan Rivet #else 610c752998bSGaetan Rivet RTE_SET_USED(p); 611c752998bSGaetan Rivet RTE_SET_USED(data); 612c752998bSGaetan Rivet RTE_SET_USED(len); 613c752998bSGaetan Rivet RTE_SET_USED(offset); 614c752998bSGaetan Rivet #endif 615c752998bSGaetan Rivet } 616c752998bSGaetan Rivet 617c752998bSGaetan Rivet void 618c752998bSGaetan Rivet rte_pci_ioport_write(struct rte_pci_ioport *p, 619c752998bSGaetan Rivet const void *data, size_t len, off_t offset) 620c752998bSGaetan Rivet { 621c752998bSGaetan Rivet switch (p->dev->kdrv) { 6227c0d798aSDavid Marchand case RTE_PCI_KDRV_NIC_UIO: 623c752998bSGaetan Rivet pci_uio_ioport_write(p, data, len, offset); 624c752998bSGaetan Rivet break; 625c752998bSGaetan Rivet default: 626c752998bSGaetan Rivet break; 627c752998bSGaetan Rivet } 628c752998bSGaetan Rivet } 629c752998bSGaetan Rivet 630c752998bSGaetan Rivet int 631c752998bSGaetan Rivet rte_pci_ioport_unmap(struct rte_pci_ioport *p) 632c752998bSGaetan Rivet { 633c752998bSGaetan Rivet int ret; 634c752998bSGaetan Rivet 635c752998bSGaetan Rivet switch (p->dev->kdrv) { 636c752998bSGaetan Rivet #if defined(RTE_ARCH_X86) 6377c0d798aSDavid Marchand case RTE_PCI_KDRV_NIC_UIO: 638c752998bSGaetan Rivet ret = 0; 639c752998bSGaetan Rivet break; 640c752998bSGaetan Rivet #endif 641c752998bSGaetan Rivet default: 642c752998bSGaetan Rivet ret = -1; 643c752998bSGaetan Rivet break; 644c752998bSGaetan Rivet } 645c752998bSGaetan Rivet 646c752998bSGaetan Rivet return ret; 647c752998bSGaetan Rivet } 648