15566a3e3SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 25566a3e3SBruce Richardson * Copyright(c) 2010-2015 Intel Corporation 3c752998bSGaetan Rivet */ 4c752998bSGaetan Rivet 5c752998bSGaetan Rivet #include <fcntl.h> 6c752998bSGaetan Rivet #include <string.h> 7c752998bSGaetan Rivet #include <unistd.h> 8c752998bSGaetan Rivet #include <sys/types.h> 9c752998bSGaetan Rivet #include <sys/stat.h> 10c752998bSGaetan Rivet #include <sys/mman.h> 11c752998bSGaetan Rivet 12c752998bSGaetan Rivet #include <rte_eal.h> 13c752998bSGaetan Rivet #include <rte_pci.h> 14c752998bSGaetan Rivet #include <rte_bus_pci.h> 15c752998bSGaetan Rivet #include <rte_tailq.h> 16c752998bSGaetan Rivet #include <rte_log.h> 17c752998bSGaetan Rivet #include <rte_malloc.h> 18c752998bSGaetan Rivet 19c752998bSGaetan Rivet #include "private.h" 20c752998bSGaetan Rivet 21c752998bSGaetan Rivet static struct rte_tailq_elem rte_uio_tailq = { 22c752998bSGaetan Rivet .name = "UIO_RESOURCE_LIST", 23c752998bSGaetan Rivet }; 24c752998bSGaetan Rivet EAL_REGISTER_TAILQ(rte_uio_tailq) 25c752998bSGaetan Rivet 26c752998bSGaetan Rivet static int 27c752998bSGaetan Rivet pci_uio_map_secondary(struct rte_pci_device *dev) 28c752998bSGaetan Rivet { 299e0a0e38SZerun Fu int fd, i = 0, j, res_idx; 30c752998bSGaetan Rivet struct mapped_pci_resource *uio_res; 31c752998bSGaetan Rivet struct mapped_pci_res_list *uio_res_list = 32c752998bSGaetan Rivet RTE_TAILQ_CAST(rte_uio_tailq.head, mapped_pci_res_list); 33c752998bSGaetan Rivet 34c752998bSGaetan Rivet TAILQ_FOREACH(uio_res, uio_res_list, next) { 35c752998bSGaetan Rivet 36c752998bSGaetan Rivet /* skip this element if it doesn't match our PCI address */ 370e3ef055SGaetan Rivet if (rte_pci_addr_cmp(&uio_res->pci_addr, &dev->addr)) 38c752998bSGaetan Rivet continue; 39c752998bSGaetan Rivet 409e0a0e38SZerun Fu /* Map all BARs */ 419e0a0e38SZerun Fu for (res_idx = 0; res_idx != PCI_MAX_RESOURCE; res_idx++) { 429e0a0e38SZerun Fu /* skip empty BAR */ 439e0a0e38SZerun Fu if (dev->mem_resource[res_idx].phys_addr == 0) 449e0a0e38SZerun Fu continue; 459e0a0e38SZerun Fu 469e0a0e38SZerun Fu if (i >= uio_res->nb_maps) 479e0a0e38SZerun Fu return -1; 489e0a0e38SZerun Fu 49c752998bSGaetan Rivet /* 50c752998bSGaetan Rivet * open devname, to mmap it 51c752998bSGaetan Rivet */ 52c752998bSGaetan Rivet fd = open(uio_res->maps[i].path, O_RDWR); 53c752998bSGaetan Rivet if (fd < 0) { 54849f773bSDavid Marchand PCI_LOG(ERR, "Cannot open %s: %s", 55c752998bSGaetan Rivet uio_res->maps[i].path, strerror(errno)); 56c752998bSGaetan Rivet return -1; 57c752998bSGaetan Rivet } 58c752998bSGaetan Rivet 59c752998bSGaetan Rivet void *mapaddr = pci_map_resource(uio_res->maps[i].addr, 60c752998bSGaetan Rivet fd, (off_t)uio_res->maps[i].offset, 61c752998bSGaetan Rivet (size_t)uio_res->maps[i].size, 0); 6220b6fd65SStephen Hemminger 6320b6fd65SStephen Hemminger /* fd is not needed in secondary process, close it */ 64c752998bSGaetan Rivet close(fd); 65c752998bSGaetan Rivet if (mapaddr != uio_res->maps[i].addr) { 66849f773bSDavid Marchand PCI_LOG(ERR, "Cannot mmap device resource file %s to address: %p", 67c752998bSGaetan Rivet uio_res->maps[i].path, 68c752998bSGaetan Rivet uio_res->maps[i].addr); 69e200535cSDavid Marchand if (mapaddr != NULL) { 70c752998bSGaetan Rivet /* unmap addrs correctly mapped */ 71c752998bSGaetan Rivet for (j = 0; j < i; j++) 72c752998bSGaetan Rivet pci_unmap_resource( 73c752998bSGaetan Rivet uio_res->maps[j].addr, 74c752998bSGaetan Rivet (size_t)uio_res->maps[j].size); 75c752998bSGaetan Rivet /* unmap addr wrongly mapped */ 76c752998bSGaetan Rivet pci_unmap_resource(mapaddr, 77c752998bSGaetan Rivet (size_t)uio_res->maps[i].size); 78c752998bSGaetan Rivet } 79c752998bSGaetan Rivet return -1; 80c752998bSGaetan Rivet } 819e0a0e38SZerun Fu dev->mem_resource[res_idx].addr = mapaddr; 829e0a0e38SZerun Fu 839e0a0e38SZerun Fu i++; 84c752998bSGaetan Rivet } 85c752998bSGaetan Rivet return 0; 86c752998bSGaetan Rivet } 87c752998bSGaetan Rivet 88849f773bSDavid Marchand PCI_LOG(ERR, "Cannot find resource for device"); 89c752998bSGaetan Rivet return 1; 90c752998bSGaetan Rivet } 91c752998bSGaetan Rivet 92c752998bSGaetan Rivet /* map the PCI resource of a PCI device in virtual memory */ 93c752998bSGaetan Rivet int 94c752998bSGaetan Rivet pci_uio_map_resource(struct rte_pci_device *dev) 95c752998bSGaetan Rivet { 96c752998bSGaetan Rivet int i, map_idx = 0, ret; 97c752998bSGaetan Rivet uint64_t phaddr; 98c752998bSGaetan Rivet struct mapped_pci_resource *uio_res = NULL; 99c752998bSGaetan Rivet struct mapped_pci_res_list *uio_res_list = 100c752998bSGaetan Rivet RTE_TAILQ_CAST(rte_uio_tailq.head, mapped_pci_res_list); 101c752998bSGaetan Rivet 102d61138d4SHarman Kalra if (rte_intr_fd_set(dev->intr_handle, -1)) 103d61138d4SHarman Kalra return -1; 104d61138d4SHarman Kalra 105d61138d4SHarman Kalra if (rte_intr_dev_fd_set(dev->intr_handle, -1)) 106d61138d4SHarman Kalra return -1; 107c752998bSGaetan Rivet 108c752998bSGaetan Rivet /* allocate uio resource */ 109c752998bSGaetan Rivet ret = pci_uio_alloc_resource(dev, &uio_res); 110c752998bSGaetan Rivet if (ret) 111c752998bSGaetan Rivet return ret; 112c752998bSGaetan Rivet 113*847d78fbSZerun Fu /* secondary processes - use already recorded details */ 114*847d78fbSZerun Fu if (rte_eal_process_type() != RTE_PROC_PRIMARY) 115*847d78fbSZerun Fu return pci_uio_map_secondary(dev); 116*847d78fbSZerun Fu 117c752998bSGaetan Rivet /* Map all BARs */ 118c752998bSGaetan Rivet for (i = 0; i != PCI_MAX_RESOURCE; i++) { 119c752998bSGaetan Rivet /* skip empty BAR */ 120c752998bSGaetan Rivet phaddr = dev->mem_resource[i].phys_addr; 121c752998bSGaetan Rivet if (phaddr == 0) 122c752998bSGaetan Rivet continue; 123c752998bSGaetan Rivet 124c752998bSGaetan Rivet ret = pci_uio_map_resource_by_index(dev, i, 125c752998bSGaetan Rivet uio_res, map_idx); 126c752998bSGaetan Rivet if (ret) 127c752998bSGaetan Rivet goto error; 128c752998bSGaetan Rivet 129c752998bSGaetan Rivet map_idx++; 130c752998bSGaetan Rivet } 131c752998bSGaetan Rivet 132c752998bSGaetan Rivet uio_res->nb_maps = map_idx; 133c752998bSGaetan Rivet 134c752998bSGaetan Rivet TAILQ_INSERT_TAIL(uio_res_list, uio_res, next); 135c752998bSGaetan Rivet 136c752998bSGaetan Rivet return 0; 137c752998bSGaetan Rivet error: 138c752998bSGaetan Rivet for (i = 0; i < map_idx; i++) { 139c752998bSGaetan Rivet pci_unmap_resource(uio_res->maps[i].addr, 140c752998bSGaetan Rivet (size_t)uio_res->maps[i].size); 141c752998bSGaetan Rivet rte_free(uio_res->maps[i].path); 142c752998bSGaetan Rivet } 143c752998bSGaetan Rivet pci_uio_free_resource(dev, uio_res); 144c752998bSGaetan Rivet return -1; 145c752998bSGaetan Rivet } 146c752998bSGaetan Rivet 147c752998bSGaetan Rivet static void 148c752998bSGaetan Rivet pci_uio_unmap(struct mapped_pci_resource *uio_res) 149c752998bSGaetan Rivet { 150c752998bSGaetan Rivet int i; 151c752998bSGaetan Rivet 152c752998bSGaetan Rivet if (uio_res == NULL) 153c752998bSGaetan Rivet return; 154c752998bSGaetan Rivet 155c752998bSGaetan Rivet for (i = 0; i != uio_res->nb_maps; i++) { 156c752998bSGaetan Rivet pci_unmap_resource(uio_res->maps[i].addr, 157c752998bSGaetan Rivet (size_t)uio_res->maps[i].size); 158c752998bSGaetan Rivet if (rte_eal_process_type() == RTE_PROC_PRIMARY) 159c752998bSGaetan Rivet rte_free(uio_res->maps[i].path); 160c752998bSGaetan Rivet } 161c752998bSGaetan Rivet } 162c752998bSGaetan Rivet 163b01dc3daSJeff Guo /* remap the PCI resource of a PCI device in anonymous virtual memory */ 164b01dc3daSJeff Guo int 165b01dc3daSJeff Guo pci_uio_remap_resource(struct rte_pci_device *dev) 166b01dc3daSJeff Guo { 167b01dc3daSJeff Guo int i; 168b01dc3daSJeff Guo void *map_address; 169b01dc3daSJeff Guo 170b01dc3daSJeff Guo if (dev == NULL) 171b01dc3daSJeff Guo return -1; 172b01dc3daSJeff Guo 173b01dc3daSJeff Guo /* Remap all BARs */ 174b01dc3daSJeff Guo for (i = 0; i != PCI_MAX_RESOURCE; i++) { 175b01dc3daSJeff Guo /* skip empty BAR */ 176b01dc3daSJeff Guo if (dev->mem_resource[i].phys_addr == 0) 177b01dc3daSJeff Guo continue; 178b01dc3daSJeff Guo map_address = mmap(dev->mem_resource[i].addr, 179b01dc3daSJeff Guo (size_t)dev->mem_resource[i].len, 180b01dc3daSJeff Guo PROT_READ | PROT_WRITE, 181b01dc3daSJeff Guo MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 182b01dc3daSJeff Guo if (map_address == MAP_FAILED) { 183849f773bSDavid Marchand PCI_LOG(ERR, "Cannot remap resource for device %s", dev->name); 184b01dc3daSJeff Guo return -1; 185b01dc3daSJeff Guo } 186849f773bSDavid Marchand PCI_LOG(INFO, "Successful remap resource for device %s", dev->name); 187b01dc3daSJeff Guo } 188b01dc3daSJeff Guo 189b01dc3daSJeff Guo return 0; 190b01dc3daSJeff Guo } 191b01dc3daSJeff Guo 192c752998bSGaetan Rivet static struct mapped_pci_resource * 193c752998bSGaetan Rivet pci_uio_find_resource(struct rte_pci_device *dev) 194c752998bSGaetan Rivet { 195c752998bSGaetan Rivet struct mapped_pci_resource *uio_res; 196c752998bSGaetan Rivet struct mapped_pci_res_list *uio_res_list = 197c752998bSGaetan Rivet RTE_TAILQ_CAST(rte_uio_tailq.head, mapped_pci_res_list); 198c752998bSGaetan Rivet 199c752998bSGaetan Rivet if (dev == NULL) 200c752998bSGaetan Rivet return NULL; 201c752998bSGaetan Rivet 202c752998bSGaetan Rivet TAILQ_FOREACH(uio_res, uio_res_list, next) { 203c752998bSGaetan Rivet 204c752998bSGaetan Rivet /* skip this element if it doesn't match our PCI address */ 2050e3ef055SGaetan Rivet if (!rte_pci_addr_cmp(&uio_res->pci_addr, &dev->addr)) 206c752998bSGaetan Rivet return uio_res; 207c752998bSGaetan Rivet } 208c752998bSGaetan Rivet return NULL; 209c752998bSGaetan Rivet } 210c752998bSGaetan Rivet 211c752998bSGaetan Rivet /* unmap the PCI resource of a PCI device in virtual memory */ 212c752998bSGaetan Rivet void 213c752998bSGaetan Rivet pci_uio_unmap_resource(struct rte_pci_device *dev) 214c752998bSGaetan Rivet { 215c752998bSGaetan Rivet struct mapped_pci_resource *uio_res; 216c752998bSGaetan Rivet struct mapped_pci_res_list *uio_res_list = 217c752998bSGaetan Rivet RTE_TAILQ_CAST(rte_uio_tailq.head, mapped_pci_res_list); 218d61138d4SHarman Kalra int uio_cfg_fd; 219c752998bSGaetan Rivet 220c752998bSGaetan Rivet if (dev == NULL) 221c752998bSGaetan Rivet return; 222c752998bSGaetan Rivet 223c752998bSGaetan Rivet /* find an entry for the device */ 224c752998bSGaetan Rivet uio_res = pci_uio_find_resource(dev); 225c752998bSGaetan Rivet if (uio_res == NULL) 226c752998bSGaetan Rivet return; 227c752998bSGaetan Rivet 228*847d78fbSZerun Fu /* close fd */ 229*847d78fbSZerun Fu if (rte_intr_fd_get(dev->intr_handle) >= 0) 230*847d78fbSZerun Fu close(rte_intr_fd_get(dev->intr_handle)); 231*847d78fbSZerun Fu uio_cfg_fd = rte_intr_dev_fd_get(dev->intr_handle); 232*847d78fbSZerun Fu if (uio_cfg_fd >= 0) { 233*847d78fbSZerun Fu close(uio_cfg_fd); 234*847d78fbSZerun Fu rte_intr_dev_fd_set(dev->intr_handle, -1); 235*847d78fbSZerun Fu } 236*847d78fbSZerun Fu 237*847d78fbSZerun Fu rte_intr_fd_set(dev->intr_handle, -1); 238*847d78fbSZerun Fu rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN); 239*847d78fbSZerun Fu 240c752998bSGaetan Rivet /* secondary processes - just free maps */ 241c752998bSGaetan Rivet if (rte_eal_process_type() != RTE_PROC_PRIMARY) 242c752998bSGaetan Rivet return pci_uio_unmap(uio_res); 243c752998bSGaetan Rivet 244c752998bSGaetan Rivet TAILQ_REMOVE(uio_res_list, uio_res, next); 245c752998bSGaetan Rivet 246c752998bSGaetan Rivet /* unmap all resources */ 247c752998bSGaetan Rivet pci_uio_unmap(uio_res); 248c752998bSGaetan Rivet 249c752998bSGaetan Rivet /* free uio resource */ 250c752998bSGaetan Rivet rte_free(uio_res); 251c752998bSGaetan Rivet } 252