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 <unistd.h> 7c752998bSGaetan Rivet #include <fcntl.h> 8c752998bSGaetan Rivet #include <dirent.h> 9c752998bSGaetan Rivet #include <inttypes.h> 10c752998bSGaetan Rivet #include <sys/stat.h> 11c752998bSGaetan Rivet #include <sys/mman.h> 12c752998bSGaetan Rivet #include <sys/sysmacros.h> 13c752998bSGaetan Rivet 14c752998bSGaetan Rivet #if defined(RTE_ARCH_X86) 15c752998bSGaetan Rivet #include <sys/io.h> 16c752998bSGaetan Rivet #endif 17c752998bSGaetan Rivet 186723c0fcSBruce Richardson #include <rte_string_fns.h> 19c752998bSGaetan Rivet #include <rte_log.h> 20c752998bSGaetan Rivet #include <rte_pci.h> 21c752998bSGaetan Rivet #include <rte_bus_pci.h> 22c752998bSGaetan Rivet #include <rte_common.h> 23c752998bSGaetan Rivet #include <rte_malloc.h> 24c752998bSGaetan Rivet 25c752998bSGaetan Rivet #include "eal_filesystem.h" 26c752998bSGaetan Rivet #include "pci_init.h" 27e1ece609SDavid Marchand #include "private.h" 28c752998bSGaetan Rivet 29c752998bSGaetan Rivet void *pci_map_addr = NULL; 30c752998bSGaetan Rivet 31c752998bSGaetan Rivet #define OFF_MAX ((uint64_t)(off_t)-1) 32c752998bSGaetan Rivet 33c752998bSGaetan Rivet int 34c752998bSGaetan Rivet pci_uio_read_config(const struct rte_intr_handle *intr_handle, 35c752998bSGaetan Rivet void *buf, size_t len, off_t offset) 36c752998bSGaetan Rivet { 37d61138d4SHarman Kalra int uio_cfg_fd = rte_intr_dev_fd_get(intr_handle); 38d61138d4SHarman Kalra 39aedd054cSHarman Kalra if (uio_cfg_fd < 0) 40aedd054cSHarman Kalra return -1; 41aedd054cSHarman Kalra 42d61138d4SHarman Kalra return pread(uio_cfg_fd, buf, len, offset); 43c752998bSGaetan Rivet } 44c752998bSGaetan Rivet 45c752998bSGaetan Rivet int 46c752998bSGaetan Rivet pci_uio_write_config(const struct rte_intr_handle *intr_handle, 47c752998bSGaetan Rivet const void *buf, size_t len, off_t offset) 48c752998bSGaetan Rivet { 49d61138d4SHarman Kalra int uio_cfg_fd = rte_intr_dev_fd_get(intr_handle); 50d61138d4SHarman Kalra 51aedd054cSHarman Kalra if (uio_cfg_fd < 0) 52aedd054cSHarman Kalra return -1; 53aedd054cSHarman Kalra 54d61138d4SHarman Kalra return pwrite(uio_cfg_fd, buf, len, offset); 55c752998bSGaetan Rivet } 56c752998bSGaetan Rivet 57095cf6e6SChenbo Xia int 58095cf6e6SChenbo Xia pci_uio_mmio_read(const struct rte_pci_device *dev, int bar, 59095cf6e6SChenbo Xia void *buf, size_t len, off_t offset) 60095cf6e6SChenbo Xia { 61095cf6e6SChenbo Xia if (bar >= PCI_MAX_RESOURCE || dev->mem_resource[bar].addr == NULL || 62095cf6e6SChenbo Xia (uint64_t)offset + len > dev->mem_resource[bar].len) 63095cf6e6SChenbo Xia return -1; 64095cf6e6SChenbo Xia memcpy(buf, (uint8_t *)dev->mem_resource[bar].addr + offset, len); 65095cf6e6SChenbo Xia return len; 66095cf6e6SChenbo Xia } 67095cf6e6SChenbo Xia 68095cf6e6SChenbo Xia int 69095cf6e6SChenbo Xia pci_uio_mmio_write(const struct rte_pci_device *dev, int bar, 70095cf6e6SChenbo Xia const void *buf, size_t len, off_t offset) 71095cf6e6SChenbo Xia { 72095cf6e6SChenbo Xia if (bar >= PCI_MAX_RESOURCE || dev->mem_resource[bar].addr == NULL || 73095cf6e6SChenbo Xia (uint64_t)offset + len > dev->mem_resource[bar].len) 74095cf6e6SChenbo Xia return -1; 75095cf6e6SChenbo Xia memcpy((uint8_t *)dev->mem_resource[bar].addr + offset, buf, len); 76095cf6e6SChenbo Xia return len; 77095cf6e6SChenbo Xia } 78095cf6e6SChenbo Xia 79c752998bSGaetan Rivet static int 80c752998bSGaetan Rivet pci_mknod_uio_dev(const char *sysfs_uio_path, unsigned uio_num) 81c752998bSGaetan Rivet { 82c752998bSGaetan Rivet FILE *f; 83c752998bSGaetan Rivet char filename[PATH_MAX]; 84c752998bSGaetan Rivet int ret; 85c752998bSGaetan Rivet unsigned major, minor; 86c752998bSGaetan Rivet dev_t dev; 87c752998bSGaetan Rivet 88c752998bSGaetan Rivet /* get the name of the sysfs file that contains the major and minor 89c752998bSGaetan Rivet * of the uio device and read its content */ 90c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "%s/dev", sysfs_uio_path); 91c752998bSGaetan Rivet 92c752998bSGaetan Rivet f = fopen(filename, "r"); 93c752998bSGaetan Rivet if (f == NULL) { 94849f773bSDavid Marchand PCI_LOG(ERR, "%s(): cannot open sysfs to get major:minor", __func__); 95c752998bSGaetan Rivet return -1; 96c752998bSGaetan Rivet } 97c752998bSGaetan Rivet 98c752998bSGaetan Rivet ret = fscanf(f, "%u:%u", &major, &minor); 99c752998bSGaetan Rivet if (ret != 2) { 100849f773bSDavid Marchand PCI_LOG(ERR, "%s(): cannot parse sysfs to get major:minor", __func__); 101c752998bSGaetan Rivet fclose(f); 102c752998bSGaetan Rivet return -1; 103c752998bSGaetan Rivet } 104c752998bSGaetan Rivet fclose(f); 105c752998bSGaetan Rivet 106c752998bSGaetan Rivet /* create the char device "mknod /dev/uioX c major minor" */ 107c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "/dev/uio%u", uio_num); 108c752998bSGaetan Rivet dev = makedev(major, minor); 109c752998bSGaetan Rivet ret = mknod(filename, S_IFCHR | S_IRUSR | S_IWUSR, dev); 110c752998bSGaetan Rivet if (ret != 0) { 111849f773bSDavid Marchand PCI_LOG(ERR, "%s(): mknod() failed %s", __func__, strerror(errno)); 112c752998bSGaetan Rivet return -1; 113c752998bSGaetan Rivet } 114c752998bSGaetan Rivet 115c752998bSGaetan Rivet return ret; 116c752998bSGaetan Rivet } 117c752998bSGaetan Rivet 118c752998bSGaetan Rivet /* 119c752998bSGaetan Rivet * Return the uioX char device used for a pci device. On success, return 120c752998bSGaetan Rivet * the UIO number and fill dstbuf string with the path of the device in 121c752998bSGaetan Rivet * sysfs. On error, return a negative value. In this case dstbuf is 122c752998bSGaetan Rivet * invalid. 123c752998bSGaetan Rivet */ 124c752998bSGaetan Rivet static int 125c752998bSGaetan Rivet pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf, 126c752998bSGaetan Rivet unsigned int buflen, int create) 127c752998bSGaetan Rivet { 128c752998bSGaetan Rivet struct rte_pci_addr *loc = &dev->addr; 129c752998bSGaetan Rivet int uio_num = -1; 130c752998bSGaetan Rivet struct dirent *e; 131c752998bSGaetan Rivet DIR *dir; 132c752998bSGaetan Rivet char dirname[PATH_MAX]; 133c752998bSGaetan Rivet 134c752998bSGaetan Rivet /* depending on kernel version, uio can be located in uio/uioX 135c752998bSGaetan Rivet * or uio:uioX */ 136c752998bSGaetan Rivet 137c752998bSGaetan Rivet snprintf(dirname, sizeof(dirname), 138c52dd394SThomas Monjalon "%s/" PCI_PRI_FMT "/uio", rte_pci_get_sysfs_path(), 139c752998bSGaetan Rivet loc->domain, loc->bus, loc->devid, loc->function); 140c752998bSGaetan Rivet 141c752998bSGaetan Rivet dir = opendir(dirname); 142c752998bSGaetan Rivet if (dir == NULL) { 143c752998bSGaetan Rivet /* retry with the parent directory */ 144c752998bSGaetan Rivet snprintf(dirname, sizeof(dirname), 145c52dd394SThomas Monjalon "%s/" PCI_PRI_FMT, rte_pci_get_sysfs_path(), 146c752998bSGaetan Rivet loc->domain, loc->bus, loc->devid, loc->function); 147c752998bSGaetan Rivet dir = opendir(dirname); 148c752998bSGaetan Rivet 149c752998bSGaetan Rivet if (dir == NULL) { 150849f773bSDavid Marchand PCI_LOG(ERR, "Cannot opendir %s", dirname); 151c752998bSGaetan Rivet return -1; 152c752998bSGaetan Rivet } 153c752998bSGaetan Rivet } 154c752998bSGaetan Rivet 155c752998bSGaetan Rivet /* take the first file starting with "uio" */ 156c752998bSGaetan Rivet while ((e = readdir(dir)) != NULL) { 157c752998bSGaetan Rivet /* format could be uio%d ...*/ 158c752998bSGaetan Rivet int shortprefix_len = sizeof("uio") - 1; 159c752998bSGaetan Rivet /* ... or uio:uio%d */ 160c752998bSGaetan Rivet int longprefix_len = sizeof("uio:uio") - 1; 161c752998bSGaetan Rivet char *endptr; 162c752998bSGaetan Rivet 163c752998bSGaetan Rivet if (strncmp(e->d_name, "uio", 3) != 0) 164c752998bSGaetan Rivet continue; 165c752998bSGaetan Rivet 166c752998bSGaetan Rivet /* first try uio%d */ 167c752998bSGaetan Rivet errno = 0; 168c752998bSGaetan Rivet uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); 169c752998bSGaetan Rivet if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { 170c752998bSGaetan Rivet snprintf(dstbuf, buflen, "%s/uio%u", dirname, uio_num); 171c752998bSGaetan Rivet break; 172c752998bSGaetan Rivet } 173c752998bSGaetan Rivet 174c752998bSGaetan Rivet /* then try uio:uio%d */ 175c752998bSGaetan Rivet errno = 0; 176c752998bSGaetan Rivet uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); 177c752998bSGaetan Rivet if (errno == 0 && endptr != (e->d_name + longprefix_len)) { 178c752998bSGaetan Rivet snprintf(dstbuf, buflen, "%s/uio:uio%u", dirname, uio_num); 179c752998bSGaetan Rivet break; 180c752998bSGaetan Rivet } 181c752998bSGaetan Rivet } 182c752998bSGaetan Rivet closedir(dir); 183c752998bSGaetan Rivet 184c752998bSGaetan Rivet /* No uio resource found */ 185c752998bSGaetan Rivet if (e == NULL) 186c752998bSGaetan Rivet return -1; 187c752998bSGaetan Rivet 188c752998bSGaetan Rivet /* create uio device if we've been asked to */ 189c752998bSGaetan Rivet if (rte_eal_create_uio_dev() && create && 190c752998bSGaetan Rivet pci_mknod_uio_dev(dstbuf, uio_num) < 0) 191849f773bSDavid Marchand PCI_LOG(WARNING, "Cannot create /dev/uio%u", uio_num); 192c752998bSGaetan Rivet 193c752998bSGaetan Rivet return uio_num; 194c752998bSGaetan Rivet } 195c752998bSGaetan Rivet 196c752998bSGaetan Rivet void 197c752998bSGaetan Rivet pci_uio_free_resource(struct rte_pci_device *dev, 198c752998bSGaetan Rivet struct mapped_pci_resource *uio_res) 199c752998bSGaetan Rivet { 200d61138d4SHarman Kalra int uio_cfg_fd = rte_intr_dev_fd_get(dev->intr_handle); 201d61138d4SHarman Kalra 202c752998bSGaetan Rivet rte_free(uio_res); 203c752998bSGaetan Rivet 204d61138d4SHarman Kalra if (uio_cfg_fd >= 0) { 205d61138d4SHarman Kalra close(uio_cfg_fd); 206d61138d4SHarman Kalra rte_intr_dev_fd_set(dev->intr_handle, -1); 207c752998bSGaetan Rivet } 208d61138d4SHarman Kalra 209d61138d4SHarman Kalra if (rte_intr_fd_get(dev->intr_handle) >= 0) { 210d61138d4SHarman Kalra close(rte_intr_fd_get(dev->intr_handle)); 211d61138d4SHarman Kalra rte_intr_fd_set(dev->intr_handle, -1); 212d61138d4SHarman Kalra rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN); 213c752998bSGaetan Rivet } 214c752998bSGaetan Rivet } 215c752998bSGaetan Rivet 216c752998bSGaetan Rivet int 217c752998bSGaetan Rivet pci_uio_alloc_resource(struct rte_pci_device *dev, 218c752998bSGaetan Rivet struct mapped_pci_resource **uio_res) 219c752998bSGaetan Rivet { 220c752998bSGaetan Rivet char dirname[PATH_MAX]; 221c752998bSGaetan Rivet char cfgname[PATH_MAX]; 222c752998bSGaetan Rivet char devname[PATH_MAX]; /* contains the /dev/uioX */ 223d61138d4SHarman Kalra int uio_num, fd, uio_cfg_fd; 224c752998bSGaetan Rivet struct rte_pci_addr *loc; 225c752998bSGaetan Rivet 226c752998bSGaetan Rivet loc = &dev->addr; 227c752998bSGaetan Rivet 228c752998bSGaetan Rivet /* find uio resource */ 229c752998bSGaetan Rivet uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 1); 230c752998bSGaetan Rivet if (uio_num < 0) { 231849f773bSDavid Marchand PCI_LOG(WARNING, " "PCI_PRI_FMT" not managed by UIO driver, skipping", 232849f773bSDavid Marchand loc->domain, loc->bus, loc->devid, loc->function); 233c752998bSGaetan Rivet return 1; 234c752998bSGaetan Rivet } 235c752998bSGaetan Rivet snprintf(devname, sizeof(devname), "/dev/uio%u", uio_num); 236c752998bSGaetan Rivet 237*847d78fbSZerun Fu /* save fd */ 238d61138d4SHarman Kalra fd = open(devname, O_RDWR); 239d61138d4SHarman Kalra if (fd < 0) { 240849f773bSDavid Marchand PCI_LOG(ERR, "Cannot open %s: %s", devname, strerror(errno)); 241c752998bSGaetan Rivet goto error; 242c752998bSGaetan Rivet } 243c752998bSGaetan Rivet 244d61138d4SHarman Kalra if (rte_intr_fd_set(dev->intr_handle, fd)) 245d61138d4SHarman Kalra goto error; 246d61138d4SHarman Kalra 247c752998bSGaetan Rivet snprintf(cfgname, sizeof(cfgname), 248c752998bSGaetan Rivet "/sys/class/uio/uio%u/device/config", uio_num); 249d61138d4SHarman Kalra 250d61138d4SHarman Kalra uio_cfg_fd = open(cfgname, O_RDWR); 251d61138d4SHarman Kalra if (uio_cfg_fd < 0) { 252849f773bSDavid Marchand PCI_LOG(ERR, "Cannot open %s: %s", cfgname, strerror(errno)); 253c752998bSGaetan Rivet goto error; 254c752998bSGaetan Rivet } 255c752998bSGaetan Rivet 256d61138d4SHarman Kalra if (rte_intr_dev_fd_set(dev->intr_handle, uio_cfg_fd)) 257d61138d4SHarman Kalra goto error; 258d61138d4SHarman Kalra 259d61138d4SHarman Kalra if (dev->kdrv == RTE_PCI_KDRV_IGB_UIO) { 260d61138d4SHarman Kalra if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UIO)) 261d61138d4SHarman Kalra goto error; 262d61138d4SHarman Kalra } else { 263d61138d4SHarman Kalra if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UIO_INTX)) 264d61138d4SHarman Kalra goto error; 265c752998bSGaetan Rivet 266c752998bSGaetan Rivet /* set bus master that is not done by uio_pci_generic */ 267b3d590a0SDavid Marchand if (rte_pci_set_bus_master(dev, true)) { 268849f773bSDavid Marchand PCI_LOG(ERR, "Cannot set up bus mastering!"); 269c752998bSGaetan Rivet goto error; 270c752998bSGaetan Rivet } 271c752998bSGaetan Rivet } 272c752998bSGaetan Rivet 273*847d78fbSZerun Fu if (rte_eal_process_type() != RTE_PROC_PRIMARY) 274*847d78fbSZerun Fu return 0; 275*847d78fbSZerun Fu 276c752998bSGaetan Rivet /* allocate the mapping details for secondary processes*/ 277c752998bSGaetan Rivet *uio_res = rte_zmalloc("UIO_RES", sizeof(**uio_res), 0); 278c752998bSGaetan Rivet if (*uio_res == NULL) { 279849f773bSDavid Marchand PCI_LOG(ERR, "%s(): cannot store uio mmap details", __func__); 280c752998bSGaetan Rivet goto error; 281c752998bSGaetan Rivet } 282c752998bSGaetan Rivet 2836723c0fcSBruce Richardson strlcpy((*uio_res)->path, devname, sizeof((*uio_res)->path)); 284c752998bSGaetan Rivet memcpy(&(*uio_res)->pci_addr, &dev->addr, sizeof((*uio_res)->pci_addr)); 285c752998bSGaetan Rivet 286c752998bSGaetan Rivet return 0; 287c752998bSGaetan Rivet 288c752998bSGaetan Rivet error: 289c752998bSGaetan Rivet pci_uio_free_resource(dev, *uio_res); 290c752998bSGaetan Rivet return -1; 291c752998bSGaetan Rivet } 292c752998bSGaetan Rivet 293c752998bSGaetan Rivet int 294c752998bSGaetan Rivet pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx, 295c752998bSGaetan Rivet struct mapped_pci_resource *uio_res, int map_idx) 296c752998bSGaetan Rivet { 2974a928ef9SRafal Kozik int fd = -1; 298c752998bSGaetan Rivet char devname[PATH_MAX]; 299c752998bSGaetan Rivet void *mapaddr; 300c752998bSGaetan Rivet struct rte_pci_addr *loc; 301c752998bSGaetan Rivet struct pci_map *maps; 3024a928ef9SRafal Kozik int wc_activate = 0; 3034a928ef9SRafal Kozik 3044a928ef9SRafal Kozik if (dev->driver != NULL) 3054a928ef9SRafal Kozik wc_activate = dev->driver->drv_flags & RTE_PCI_DRV_WC_ACTIVATE; 306c752998bSGaetan Rivet 307c752998bSGaetan Rivet loc = &dev->addr; 308c752998bSGaetan Rivet maps = uio_res->maps; 309c752998bSGaetan Rivet 310c752998bSGaetan Rivet /* allocate memory to keep path */ 311d3110b12SFerruh Yigit maps[map_idx].path = rte_malloc(NULL, sizeof(devname), 0); 312c752998bSGaetan Rivet if (maps[map_idx].path == NULL) { 313849f773bSDavid Marchand PCI_LOG(ERR, "Cannot allocate memory for path: %s", strerror(errno)); 314c752998bSGaetan Rivet return -1; 315c752998bSGaetan Rivet } 316c752998bSGaetan Rivet 317c752998bSGaetan Rivet /* 318c752998bSGaetan Rivet * open resource file, to mmap it 319c752998bSGaetan Rivet */ 3204a928ef9SRafal Kozik if (wc_activate) { 3214a928ef9SRafal Kozik /* update devname for mmap */ 3224a928ef9SRafal Kozik snprintf(devname, sizeof(devname), 3234a928ef9SRafal Kozik "%s/" PCI_PRI_FMT "/resource%d_wc", 3244a928ef9SRafal Kozik rte_pci_get_sysfs_path(), 3254a928ef9SRafal Kozik loc->domain, loc->bus, loc->devid, 3264a928ef9SRafal Kozik loc->function, res_idx); 3274a928ef9SRafal Kozik 3284a928ef9SRafal Kozik fd = open(devname, O_RDWR); 329c530aa78SStephen Hemminger if (fd < 0 && errno != ENOENT) { 330849f773bSDavid Marchand PCI_LOG(INFO, "%s cannot be mapped. Fall-back to non prefetchable mode.", 3314a928ef9SRafal Kozik devname); 3324a928ef9SRafal Kozik } 3334a928ef9SRafal Kozik } 3344a928ef9SRafal Kozik 3354a928ef9SRafal Kozik if (!wc_activate || fd < 0) { 3364a928ef9SRafal Kozik snprintf(devname, sizeof(devname), 3374a928ef9SRafal Kozik "%s/" PCI_PRI_FMT "/resource%d", 3384a928ef9SRafal Kozik rte_pci_get_sysfs_path(), 3394a928ef9SRafal Kozik loc->domain, loc->bus, loc->devid, 3404a928ef9SRafal Kozik loc->function, res_idx); 3414a928ef9SRafal Kozik 3424a928ef9SRafal Kozik /* then try to map resource file */ 343c752998bSGaetan Rivet fd = open(devname, O_RDWR); 344c752998bSGaetan Rivet if (fd < 0) { 345849f773bSDavid Marchand PCI_LOG(ERR, "Cannot open %s: %s", devname, strerror(errno)); 346c752998bSGaetan Rivet goto error; 347c752998bSGaetan Rivet } 3484a928ef9SRafal Kozik } 349c752998bSGaetan Rivet 350c752998bSGaetan Rivet /* try mapping somewhere close to the end of hugepages */ 351c752998bSGaetan Rivet if (pci_map_addr == NULL) 352c752998bSGaetan Rivet pci_map_addr = pci_find_max_end_va(); 353c752998bSGaetan Rivet 354c752998bSGaetan Rivet mapaddr = pci_map_resource(pci_map_addr, fd, 0, 355c752998bSGaetan Rivet (size_t)dev->mem_resource[res_idx].len, 0); 356c752998bSGaetan Rivet close(fd); 357e200535cSDavid Marchand if (mapaddr == NULL) 358c752998bSGaetan Rivet goto error; 359c752998bSGaetan Rivet 360c752998bSGaetan Rivet pci_map_addr = RTE_PTR_ADD(mapaddr, 361c752998bSGaetan Rivet (size_t)dev->mem_resource[res_idx].len); 362c752998bSGaetan Rivet 363d25ab4b7SWangyu (Eric) pci_map_addr = RTE_PTR_ALIGN(pci_map_addr, sysconf(_SC_PAGE_SIZE)); 364d25ab4b7SWangyu (Eric) 365c752998bSGaetan Rivet maps[map_idx].phaddr = dev->mem_resource[res_idx].phys_addr; 366c752998bSGaetan Rivet maps[map_idx].size = dev->mem_resource[res_idx].len; 367c752998bSGaetan Rivet maps[map_idx].addr = mapaddr; 368c752998bSGaetan Rivet maps[map_idx].offset = 0; 369c752998bSGaetan Rivet strcpy(maps[map_idx].path, devname); 370c752998bSGaetan Rivet dev->mem_resource[res_idx].addr = mapaddr; 371c752998bSGaetan Rivet 372c752998bSGaetan Rivet return 0; 373c752998bSGaetan Rivet 374c752998bSGaetan Rivet error: 375c752998bSGaetan Rivet rte_free(maps[map_idx].path); 376c752998bSGaetan Rivet return -1; 377c752998bSGaetan Rivet } 378c752998bSGaetan Rivet 379df58e45eSHuawei Xie #define PIO_MAX 0x10000 380df58e45eSHuawei Xie 381c752998bSGaetan Rivet #if defined(RTE_ARCH_X86) 382c752998bSGaetan Rivet int 383c752998bSGaetan Rivet pci_uio_ioport_map(struct rte_pci_device *dev, int bar, 384c752998bSGaetan Rivet struct rte_pci_ioport *p) 385c752998bSGaetan Rivet { 38646dcbccdSHuawei Xie FILE *f = NULL; 387c752998bSGaetan Rivet char dirname[PATH_MAX]; 388c752998bSGaetan Rivet char filename[PATH_MAX]; 38946dcbccdSHuawei Xie char buf[BUFSIZ]; 39046dcbccdSHuawei Xie uint64_t phys_addr, end_addr, flags; 39146dcbccdSHuawei Xie unsigned long base; 392d61138d4SHarman Kalra int i, fd; 393c752998bSGaetan Rivet 39446dcbccdSHuawei Xie /* open and read addresses of the corresponding resource in sysfs */ 39546dcbccdSHuawei Xie snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource", 39646dcbccdSHuawei Xie rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus, 39746dcbccdSHuawei Xie dev->addr.devid, dev->addr.function); 39846dcbccdSHuawei Xie f = fopen(filename, "r"); 39946dcbccdSHuawei Xie if (f == NULL) { 400849f773bSDavid Marchand PCI_LOG(ERR, "%s(): Cannot open sysfs resource: %s", __func__, strerror(errno)); 401c752998bSGaetan Rivet return -1; 402c752998bSGaetan Rivet } 40346dcbccdSHuawei Xie 40446dcbccdSHuawei Xie for (i = 0; i < bar + 1; i++) { 40546dcbccdSHuawei Xie if (fgets(buf, sizeof(buf), f) == NULL) { 406849f773bSDavid Marchand PCI_LOG(ERR, "%s(): Cannot read sysfs resource", __func__); 40746dcbccdSHuawei Xie goto error; 40846dcbccdSHuawei Xie } 40946dcbccdSHuawei Xie } 41046dcbccdSHuawei Xie if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr, 41146dcbccdSHuawei Xie &end_addr, &flags) < 0) 41246dcbccdSHuawei Xie goto error; 41346dcbccdSHuawei Xie 414df58e45eSHuawei Xie if (flags & IORESOURCE_IO) { 415df58e45eSHuawei Xie if (rte_eal_iopl_init()) { 416849f773bSDavid Marchand PCI_LOG(ERR, "%s(): insufficient ioport permissions for PCI device %s", 417df58e45eSHuawei Xie __func__, dev->name); 41846dcbccdSHuawei Xie goto error; 41946dcbccdSHuawei Xie } 42046dcbccdSHuawei Xie 421df58e45eSHuawei Xie base = (unsigned long)phys_addr; 422df58e45eSHuawei Xie if (base > PIO_MAX) { 423849f773bSDavid Marchand PCI_LOG(ERR, "%s(): %08lx too large PIO resource", __func__, base); 42446dcbccdSHuawei Xie goto error; 425df58e45eSHuawei Xie } 426df58e45eSHuawei Xie 427849f773bSDavid Marchand PCI_LOG(DEBUG, "%s(): PIO BAR %08lx detected", __func__, base); 428df58e45eSHuawei Xie } else if (flags & IORESOURCE_MEM) { 429df58e45eSHuawei Xie base = (unsigned long)dev->mem_resource[bar].addr; 430849f773bSDavid Marchand PCI_LOG(DEBUG, "%s(): MMIO BAR %08lx detected", __func__, base); 431df58e45eSHuawei Xie } else { 432849f773bSDavid Marchand PCI_LOG(ERR, "%s(): unknown BAR type", __func__); 433df58e45eSHuawei Xie goto error; 434df58e45eSHuawei Xie } 435c752998bSGaetan Rivet 436c752998bSGaetan Rivet /* FIXME only for primary process ? */ 437d61138d4SHarman Kalra if (rte_intr_type_get(dev->intr_handle) == 438d61138d4SHarman Kalra RTE_INTR_HANDLE_UNKNOWN) { 43946dcbccdSHuawei Xie int uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0); 44046dcbccdSHuawei Xie if (uio_num < 0) { 441849f773bSDavid Marchand PCI_LOG(ERR, "cannot open %s: %s", dirname, strerror(errno)); 44246dcbccdSHuawei Xie goto error; 44346dcbccdSHuawei Xie } 444c752998bSGaetan Rivet 445c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "/dev/uio%u", uio_num); 446d61138d4SHarman Kalra fd = open(filename, O_RDWR); 447d61138d4SHarman Kalra if (fd < 0) { 448849f773bSDavid Marchand PCI_LOG(ERR, "Cannot open %s: %s", filename, strerror(errno)); 44946dcbccdSHuawei Xie goto error; 450c752998bSGaetan Rivet } 451d61138d4SHarman Kalra if (rte_intr_fd_set(dev->intr_handle, fd)) 452d61138d4SHarman Kalra goto error; 453d61138d4SHarman Kalra 454d61138d4SHarman Kalra if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UIO)) 455d61138d4SHarman Kalra goto error; 456c752998bSGaetan Rivet } 457c752998bSGaetan Rivet 458849f773bSDavid Marchand PCI_LOG(DEBUG, "PCI Port IO found start=0x%lx", base); 459c752998bSGaetan Rivet 46046dcbccdSHuawei Xie p->base = base; 461c752998bSGaetan Rivet p->len = 0; 46246dcbccdSHuawei Xie fclose(f); 463c752998bSGaetan Rivet return 0; 46446dcbccdSHuawei Xie error: 46546dcbccdSHuawei Xie if (f) 46646dcbccdSHuawei Xie fclose(f); 46746dcbccdSHuawei Xie return -1; 468c752998bSGaetan Rivet } 469c752998bSGaetan Rivet #else 470c752998bSGaetan Rivet int 471c752998bSGaetan Rivet pci_uio_ioport_map(struct rte_pci_device *dev, int bar, 472c752998bSGaetan Rivet struct rte_pci_ioport *p) 473c752998bSGaetan Rivet { 474c752998bSGaetan Rivet FILE *f; 475c752998bSGaetan Rivet char buf[BUFSIZ]; 476c752998bSGaetan Rivet char filename[PATH_MAX]; 477c752998bSGaetan Rivet uint64_t phys_addr, end_addr, flags; 478c752998bSGaetan Rivet int fd, i; 479c752998bSGaetan Rivet void *addr; 480c752998bSGaetan Rivet 481c752998bSGaetan Rivet /* open and read addresses of the corresponding resource in sysfs */ 482c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource", 483c52dd394SThomas Monjalon rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus, 484c752998bSGaetan Rivet dev->addr.devid, dev->addr.function); 485c752998bSGaetan Rivet f = fopen(filename, "r"); 486c752998bSGaetan Rivet if (f == NULL) { 487849f773bSDavid Marchand PCI_LOG(ERR, "Cannot open sysfs resource: %s", strerror(errno)); 488c752998bSGaetan Rivet return -1; 489c752998bSGaetan Rivet } 490c752998bSGaetan Rivet for (i = 0; i < bar + 1; i++) { 491c752998bSGaetan Rivet if (fgets(buf, sizeof(buf), f) == NULL) { 492849f773bSDavid Marchand PCI_LOG(ERR, "Cannot read sysfs resource"); 493c752998bSGaetan Rivet goto error; 494c752998bSGaetan Rivet } 495c752998bSGaetan Rivet } 496c752998bSGaetan Rivet if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr, 497c752998bSGaetan Rivet &end_addr, &flags) < 0) 498c752998bSGaetan Rivet goto error; 499c752998bSGaetan Rivet if ((flags & IORESOURCE_IO) == 0) { 500849f773bSDavid Marchand PCI_LOG(ERR, "BAR %d is not an IO resource", bar); 501c752998bSGaetan Rivet goto error; 502c752998bSGaetan Rivet } 503c752998bSGaetan Rivet snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource%d", 504c52dd394SThomas Monjalon rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus, 505c752998bSGaetan Rivet dev->addr.devid, dev->addr.function, bar); 506c752998bSGaetan Rivet 507c752998bSGaetan Rivet /* mmap the pci resource */ 508c752998bSGaetan Rivet fd = open(filename, O_RDWR); 509c752998bSGaetan Rivet if (fd < 0) { 510849f773bSDavid Marchand PCI_LOG(ERR, "Cannot open %s: %s", filename, strerror(errno)); 511c752998bSGaetan Rivet goto error; 512c752998bSGaetan Rivet } 513c752998bSGaetan Rivet addr = mmap(NULL, end_addr + 1, PROT_READ | PROT_WRITE, 514c752998bSGaetan Rivet MAP_SHARED, fd, 0); 515c752998bSGaetan Rivet close(fd); 516c752998bSGaetan Rivet if (addr == MAP_FAILED) { 517849f773bSDavid Marchand PCI_LOG(ERR, "Cannot mmap IO port resource: %s", strerror(errno)); 518c752998bSGaetan Rivet goto error; 519c752998bSGaetan Rivet } 520c752998bSGaetan Rivet 521c752998bSGaetan Rivet /* strangely, the base address is mmap addr + phys_addr */ 522c752998bSGaetan Rivet p->base = (uintptr_t)addr + phys_addr; 523c752998bSGaetan Rivet p->len = end_addr + 1; 524849f773bSDavid Marchand PCI_LOG(DEBUG, "PCI Port IO found start=0x%"PRIx64, p->base); 525c752998bSGaetan Rivet fclose(f); 526c752998bSGaetan Rivet 527c752998bSGaetan Rivet return 0; 528c752998bSGaetan Rivet 529c752998bSGaetan Rivet error: 530c752998bSGaetan Rivet fclose(f); 531c752998bSGaetan Rivet return -1; 532c752998bSGaetan Rivet } 533c752998bSGaetan Rivet #endif 534c752998bSGaetan Rivet 535df58e45eSHuawei Xie #if defined(RTE_ARCH_X86) 536204a7f44SThomas Monjalon 537df58e45eSHuawei Xie static inline uint8_t ioread8(void *addr) 538df58e45eSHuawei Xie { 539df58e45eSHuawei Xie uint8_t val; 540df58e45eSHuawei Xie 541df58e45eSHuawei Xie val = (uint64_t)(uintptr_t)addr >= PIO_MAX ? 542df58e45eSHuawei Xie *(volatile uint8_t *)addr : 543204a7f44SThomas Monjalon #ifdef __GLIBC__ 544df58e45eSHuawei Xie inb_p((unsigned long)addr); 545204a7f44SThomas Monjalon #else 546204a7f44SThomas Monjalon inb((unsigned long)addr); 547204a7f44SThomas Monjalon #endif 548df58e45eSHuawei Xie 549df58e45eSHuawei Xie return val; 550df58e45eSHuawei Xie } 551df58e45eSHuawei Xie 552df58e45eSHuawei Xie static inline uint16_t ioread16(void *addr) 553df58e45eSHuawei Xie { 554df58e45eSHuawei Xie uint16_t val; 555df58e45eSHuawei Xie 556df58e45eSHuawei Xie val = (uint64_t)(uintptr_t)addr >= PIO_MAX ? 557df58e45eSHuawei Xie *(volatile uint16_t *)addr : 558204a7f44SThomas Monjalon #ifdef __GLIBC__ 559df58e45eSHuawei Xie inw_p((unsigned long)addr); 560204a7f44SThomas Monjalon #else 561204a7f44SThomas Monjalon inw((unsigned long)addr); 562204a7f44SThomas Monjalon #endif 563df58e45eSHuawei Xie 564df58e45eSHuawei Xie return val; 565df58e45eSHuawei Xie } 566df58e45eSHuawei Xie 567df58e45eSHuawei Xie static inline uint32_t ioread32(void *addr) 568df58e45eSHuawei Xie { 569df58e45eSHuawei Xie uint32_t val; 570df58e45eSHuawei Xie 571df58e45eSHuawei Xie val = (uint64_t)(uintptr_t)addr >= PIO_MAX ? 572df58e45eSHuawei Xie *(volatile uint32_t *)addr : 573204a7f44SThomas Monjalon #ifdef __GLIBC__ 574df58e45eSHuawei Xie inl_p((unsigned long)addr); 575204a7f44SThomas Monjalon #else 576204a7f44SThomas Monjalon inl((unsigned long)addr); 577204a7f44SThomas Monjalon #endif 578df58e45eSHuawei Xie 579df58e45eSHuawei Xie return val; 580df58e45eSHuawei Xie } 581df58e45eSHuawei Xie 582df58e45eSHuawei Xie static inline void iowrite8(uint8_t val, void *addr) 583df58e45eSHuawei Xie { 584df58e45eSHuawei Xie (uint64_t)(uintptr_t)addr >= PIO_MAX ? 585df58e45eSHuawei Xie *(volatile uint8_t *)addr = val : 586204a7f44SThomas Monjalon #ifdef __GLIBC__ 587df58e45eSHuawei Xie outb_p(val, (unsigned long)addr); 588204a7f44SThomas Monjalon #else 589204a7f44SThomas Monjalon outb(val, (unsigned long)addr); 590204a7f44SThomas Monjalon #endif 591df58e45eSHuawei Xie } 592df58e45eSHuawei Xie 593df58e45eSHuawei Xie static inline void iowrite16(uint16_t val, void *addr) 594df58e45eSHuawei Xie { 595df58e45eSHuawei Xie (uint64_t)(uintptr_t)addr >= PIO_MAX ? 596df58e45eSHuawei Xie *(volatile uint16_t *)addr = val : 597204a7f44SThomas Monjalon #ifdef __GLIBC__ 598df58e45eSHuawei Xie outw_p(val, (unsigned long)addr); 599204a7f44SThomas Monjalon #else 600204a7f44SThomas Monjalon outw(val, (unsigned long)addr); 601204a7f44SThomas Monjalon #endif 602df58e45eSHuawei Xie } 603df58e45eSHuawei Xie 604df58e45eSHuawei Xie static inline void iowrite32(uint32_t val, void *addr) 605df58e45eSHuawei Xie { 606df58e45eSHuawei Xie (uint64_t)(uintptr_t)addr >= PIO_MAX ? 607df58e45eSHuawei Xie *(volatile uint32_t *)addr = val : 608204a7f44SThomas Monjalon #ifdef __GLIBC__ 609df58e45eSHuawei Xie outl_p(val, (unsigned long)addr); 610df58e45eSHuawei Xie #else 611204a7f44SThomas Monjalon outl(val, (unsigned long)addr); 612204a7f44SThomas Monjalon #endif 613204a7f44SThomas Monjalon } 614204a7f44SThomas Monjalon 615204a7f44SThomas Monjalon #else /* !RTE_ARCH_X86 */ 616204a7f44SThomas Monjalon 617df58e45eSHuawei Xie static inline uint8_t ioread8(void *addr) 618df58e45eSHuawei Xie { 619df58e45eSHuawei Xie return *(volatile uint8_t *)addr; 620df58e45eSHuawei Xie } 621df58e45eSHuawei Xie 622df58e45eSHuawei Xie static inline uint16_t ioread16(void *addr) 623df58e45eSHuawei Xie { 624df58e45eSHuawei Xie return *(volatile uint16_t *)addr; 625df58e45eSHuawei Xie } 626df58e45eSHuawei Xie 627df58e45eSHuawei Xie static inline uint32_t ioread32(void *addr) 628df58e45eSHuawei Xie { 629df58e45eSHuawei Xie return *(volatile uint32_t *)addr; 630df58e45eSHuawei Xie } 631df58e45eSHuawei Xie 632df58e45eSHuawei Xie static inline void iowrite8(uint8_t val, void *addr) 633df58e45eSHuawei Xie { 634df58e45eSHuawei Xie *(volatile uint8_t *)addr = val; 635df58e45eSHuawei Xie } 636df58e45eSHuawei Xie 637df58e45eSHuawei Xie static inline void iowrite16(uint16_t val, void *addr) 638df58e45eSHuawei Xie { 639df58e45eSHuawei Xie *(volatile uint16_t *)addr = val; 640df58e45eSHuawei Xie } 641df58e45eSHuawei Xie 642df58e45eSHuawei Xie static inline void iowrite32(uint32_t val, void *addr) 643df58e45eSHuawei Xie { 644df58e45eSHuawei Xie *(volatile uint32_t *)addr = val; 645df58e45eSHuawei Xie } 646204a7f44SThomas Monjalon 647204a7f44SThomas Monjalon #endif /* !RTE_ARCH_X86 */ 648df58e45eSHuawei Xie 649c752998bSGaetan Rivet void 650c752998bSGaetan Rivet pci_uio_ioport_read(struct rte_pci_ioport *p, 651c752998bSGaetan Rivet void *data, size_t len, off_t offset) 652c752998bSGaetan Rivet { 653c752998bSGaetan Rivet uint8_t *d; 654c752998bSGaetan Rivet int size; 655c752998bSGaetan Rivet uintptr_t reg = p->base + offset; 656c752998bSGaetan Rivet 657c752998bSGaetan Rivet for (d = data; len > 0; d += size, reg += size, len -= size) { 658c752998bSGaetan Rivet if (len >= 4) { 659c752998bSGaetan Rivet size = 4; 660df58e45eSHuawei Xie *(uint32_t *)d = ioread32((void *)reg); 661c752998bSGaetan Rivet } else if (len >= 2) { 662c752998bSGaetan Rivet size = 2; 663df58e45eSHuawei Xie *(uint16_t *)d = ioread16((void *)reg); 664c752998bSGaetan Rivet } else { 665c752998bSGaetan Rivet size = 1; 666df58e45eSHuawei Xie *d = ioread8((void *)reg); 667c752998bSGaetan Rivet } 668c752998bSGaetan Rivet } 669c752998bSGaetan Rivet } 670c752998bSGaetan Rivet 671c752998bSGaetan Rivet void 672c752998bSGaetan Rivet pci_uio_ioport_write(struct rte_pci_ioport *p, 673c752998bSGaetan Rivet const void *data, size_t len, off_t offset) 674c752998bSGaetan Rivet { 675c752998bSGaetan Rivet const uint8_t *s; 676c752998bSGaetan Rivet int size; 677c752998bSGaetan Rivet uintptr_t reg = p->base + offset; 678c752998bSGaetan Rivet 679c752998bSGaetan Rivet for (s = data; len > 0; s += size, reg += size, len -= size) { 680c752998bSGaetan Rivet if (len >= 4) { 681c752998bSGaetan Rivet size = 4; 682df58e45eSHuawei Xie iowrite32(*(const uint32_t *)s, (void *)reg); 683c752998bSGaetan Rivet } else if (len >= 2) { 684c752998bSGaetan Rivet size = 2; 685df58e45eSHuawei Xie iowrite16(*(const uint16_t *)s, (void *)reg); 686c752998bSGaetan Rivet } else { 687c752998bSGaetan Rivet size = 1; 688df58e45eSHuawei Xie iowrite8(*s, (void *)reg); 689c752998bSGaetan Rivet } 690c752998bSGaetan Rivet } 691c752998bSGaetan Rivet } 692c752998bSGaetan Rivet 693c752998bSGaetan Rivet int 694c752998bSGaetan Rivet pci_uio_ioport_unmap(struct rte_pci_ioport *p) 695c752998bSGaetan Rivet { 696c752998bSGaetan Rivet #if defined(RTE_ARCH_X86) 697c752998bSGaetan Rivet RTE_SET_USED(p); 698c752998bSGaetan Rivet /* FIXME close intr fd ? */ 699c752998bSGaetan Rivet return 0; 700c752998bSGaetan Rivet #else 701c752998bSGaetan Rivet return munmap((void *)(uintptr_t)p->base, p->len); 702c752998bSGaetan Rivet #endif 703c752998bSGaetan Rivet } 704