1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2018, Microsoft Corporation. 3 * All Rights Reserved. 4 */ 5 6 #include <fcntl.h> 7 #include <string.h> 8 #include <unistd.h> 9 #include <sys/types.h> 10 #include <sys/mman.h> 11 12 #include <rte_eal.h> 13 #include <rte_tailq.h> 14 #include <rte_log.h> 15 #include <rte_malloc.h> 16 #include <rte_bus.h> 17 #include <rte_bus_vmbus.h> 18 19 #include "private.h" 20 21 static struct rte_tailq_elem vmbus_tailq = { 22 .name = "VMBUS_RESOURCE_LIST", 23 }; 24 EAL_REGISTER_TAILQ(vmbus_tailq) 25 26 struct mapped_vmbus_resource * 27 vmbus_uio_find_resource(const struct rte_vmbus_device *dev) 28 { 29 struct mapped_vmbus_resource *uio_res; 30 struct mapped_vmbus_res_list *uio_res_list = 31 RTE_TAILQ_CAST(vmbus_tailq.head, mapped_vmbus_res_list); 32 33 if (dev == NULL) 34 return NULL; 35 36 TAILQ_FOREACH(uio_res, uio_res_list, next) { 37 if (rte_uuid_compare(uio_res->id, dev->device_id) == 0) 38 return uio_res; 39 } 40 return NULL; 41 } 42 43 static int 44 vmbus_uio_map_secondary(struct rte_vmbus_device *dev) 45 { 46 struct mapped_vmbus_resource *uio_res; 47 struct vmbus_channel *chan; 48 int fd, i; 49 50 uio_res = vmbus_uio_find_resource(dev); 51 if (!uio_res) { 52 VMBUS_LOG(ERR, "Cannot find resource for device"); 53 return -1; 54 } 55 56 /* open /dev/uioX */ 57 fd = open(uio_res->path, O_RDWR); 58 if (fd < 0) { 59 VMBUS_LOG(ERR, "Cannot open %s: %s", 60 uio_res->path, strerror(errno)); 61 return -1; 62 } 63 64 for (i = 0; i != uio_res->nb_maps; i++) { 65 void *mapaddr; 66 off_t offset = i * PAGE_SIZE; 67 68 mapaddr = vmbus_map_resource(uio_res->maps[i].addr, 69 fd, offset, 70 uio_res->maps[i].size, 0); 71 72 if (mapaddr == uio_res->maps[i].addr) 73 continue; /* successful map */ 74 75 if (mapaddr == MAP_FAILED) 76 VMBUS_LOG(ERR, 77 "mmap resource %d in secondary failed", i); 78 else 79 VMBUS_LOG(ERR, 80 "mmap resource %d address mismatch", i); 81 82 close(fd); 83 return -1; 84 } 85 86 /* fd is not needed in slave process, close it */ 87 close(fd); 88 89 dev->primary = uio_res->primary; 90 if (!dev->primary) { 91 VMBUS_LOG(ERR, "missing primary channel"); 92 return -1; 93 } 94 95 STAILQ_FOREACH(chan, &dev->primary->subchannel_list, next) { 96 if (vmbus_uio_map_secondary_subchan(dev, chan) != 0) { 97 VMBUS_LOG(ERR, "cannot map secondary subchan"); 98 return -1; 99 } 100 } 101 return 0; 102 } 103 104 static int 105 vmbus_uio_map_primary(struct rte_vmbus_device *dev) 106 { 107 int i, ret; 108 struct mapped_vmbus_resource *uio_res = NULL; 109 struct mapped_vmbus_res_list *uio_res_list = 110 RTE_TAILQ_CAST(vmbus_tailq.head, mapped_vmbus_res_list); 111 112 /* allocate uio resource */ 113 ret = vmbus_uio_alloc_resource(dev, &uio_res); 114 if (ret) 115 return ret; 116 117 /* Map the resources */ 118 for (i = 0; i < VMBUS_MAX_RESOURCE; i++) { 119 /* stop at empty BAR */ 120 if (dev->resource[i].len == 0) 121 break; 122 123 ret = vmbus_uio_map_resource_by_index(dev, i, uio_res, 0); 124 if (ret) 125 goto error; 126 } 127 128 uio_res->nb_maps = i; 129 130 TAILQ_INSERT_TAIL(uio_res_list, uio_res, next); 131 132 return 0; 133 error: 134 while (--i >= 0) { 135 vmbus_unmap_resource(uio_res->maps[i].addr, 136 (size_t)uio_res->maps[i].size); 137 } 138 vmbus_uio_free_resource(dev, uio_res); 139 return -1; 140 } 141 142 /* map the VMBUS resource of a VMBUS device in virtual memory */ 143 int 144 vmbus_uio_map_resource(struct rte_vmbus_device *dev) 145 { 146 struct mapped_vmbus_resource *uio_res; 147 int ret; 148 149 /* TODO: handle rescind */ 150 dev->intr_handle.fd = -1; 151 dev->intr_handle.uio_cfg_fd = -1; 152 dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN; 153 154 /* secondary processes - use already recorded details */ 155 if (rte_eal_process_type() != RTE_PROC_PRIMARY) 156 ret = vmbus_uio_map_secondary(dev); 157 else 158 ret = vmbus_uio_map_primary(dev); 159 160 if (ret != 0) 161 return ret; 162 163 uio_res = vmbus_uio_find_resource(dev); 164 if (!uio_res) { 165 VMBUS_LOG(ERR, "can not find resources!"); 166 return -EIO; 167 } 168 169 if (uio_res->nb_maps <= HV_MON_PAGE_MAP) { 170 VMBUS_LOG(ERR, "VMBUS: only %u resources found!", 171 uio_res->nb_maps); 172 return -EINVAL; 173 } 174 175 dev->int_page = (uint32_t *)((char *)uio_res->maps[HV_INT_PAGE_MAP].addr 176 + (PAGE_SIZE >> 1)); 177 dev->monitor_page = uio_res->maps[HV_MON_PAGE_MAP].addr; 178 return 0; 179 } 180 181 static void 182 vmbus_uio_unmap(struct mapped_vmbus_resource *uio_res) 183 { 184 int i; 185 186 if (uio_res == NULL) 187 return; 188 189 for (i = 0; i != uio_res->nb_maps; i++) { 190 vmbus_unmap_resource(uio_res->maps[i].addr, 191 (size_t)uio_res->maps[i].size); 192 } 193 } 194 195 /* unmap the VMBUS resource of a VMBUS device in virtual memory */ 196 void 197 vmbus_uio_unmap_resource(struct rte_vmbus_device *dev) 198 { 199 struct mapped_vmbus_resource *uio_res; 200 struct mapped_vmbus_res_list *uio_res_list = 201 RTE_TAILQ_CAST(vmbus_tailq.head, mapped_vmbus_res_list); 202 203 if (dev == NULL) 204 return; 205 206 /* find an entry for the device */ 207 uio_res = vmbus_uio_find_resource(dev); 208 if (uio_res == NULL) 209 return; 210 211 /* secondary processes - just free maps */ 212 if (rte_eal_process_type() != RTE_PROC_PRIMARY) 213 return vmbus_uio_unmap(uio_res); 214 215 TAILQ_REMOVE(uio_res_list, uio_res, next); 216 217 /* unmap all resources */ 218 vmbus_uio_unmap(uio_res); 219 220 /* free uio resource */ 221 rte_free(uio_res); 222 223 /* close fd if in primary process */ 224 close(dev->intr_handle.fd); 225 if (dev->intr_handle.uio_cfg_fd >= 0) { 226 close(dev->intr_handle.uio_cfg_fd); 227 dev->intr_handle.uio_cfg_fd = -1; 228 } 229 230 dev->intr_handle.fd = -1; 231 dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN; 232 } 233