xref: /dpdk/drivers/bus/vmbus/vmbus_common_uio.c (revision 84aaf06d817c94761e7489b7d2472afd12a8ca66)
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_vmbus.h>
17 
18 #include "private.h"
19 
20 static struct rte_tailq_elem vmbus_tailq = {
21 	.name = "VMBUS_RESOURCE_LIST",
22 };
EAL_REGISTER_TAILQ(vmbus_tailq)23 EAL_REGISTER_TAILQ(vmbus_tailq)
24 
25 struct mapped_vmbus_resource *
26 vmbus_uio_find_resource(const struct rte_vmbus_device *dev)
27 {
28 	struct mapped_vmbus_resource *uio_res;
29 	struct mapped_vmbus_res_list *uio_res_list =
30 			RTE_TAILQ_CAST(vmbus_tailq.head, mapped_vmbus_res_list);
31 
32 	if (dev == NULL)
33 		return NULL;
34 
35 	TAILQ_FOREACH(uio_res, uio_res_list, next) {
36 		if (rte_uuid_compare(uio_res->id, dev->device_id) == 0)
37 			return uio_res;
38 	}
39 	return NULL;
40 }
41 
42 static int
vmbus_uio_map_secondary(struct rte_vmbus_device * dev)43 vmbus_uio_map_secondary(struct rte_vmbus_device *dev)
44 {
45 	struct mapped_vmbus_resource *uio_res;
46 	struct vmbus_channel *chan;
47 	int fd, i;
48 
49 	uio_res = vmbus_uio_find_resource(dev);
50 	if (!uio_res) {
51 		VMBUS_LOG(ERR,  "Cannot find resource for device");
52 		return -1;
53 	}
54 
55 	/* open /dev/uioX */
56 	fd = open(uio_res->path, O_RDWR);
57 	if (fd < 0) {
58 		VMBUS_LOG(ERR, "Cannot open %s: %s",
59 			  uio_res->path, strerror(errno));
60 		return -1;
61 	}
62 
63 	for (i = 0; i != uio_res->nb_maps; i++) {
64 		void *mapaddr;
65 		off_t offset = i * rte_mem_page_size();
66 
67 		mapaddr = vmbus_map_resource(uio_res->maps[i].addr,
68 					     fd, offset,
69 					     uio_res->maps[i].size, 0);
70 
71 		if (mapaddr == uio_res->maps[i].addr) {
72 			dev->resource[i].addr = mapaddr;
73 			continue;	/* successful map */
74 		}
75 
76 		if (mapaddr == MAP_FAILED)
77 			VMBUS_LOG(ERR,
78 				  "mmap resource %d in secondary failed", i);
79 		else {
80 			VMBUS_LOG(ERR,
81 				  "mmap resource %d address mismatch", i);
82 			vmbus_unmap_resource(mapaddr, uio_res->maps[i].size);
83 		}
84 
85 		close(fd);
86 		return -1;
87 	}
88 
89 	/* fd is not needed in secondary process, close it */
90 	close(fd);
91 
92 	/* Create and map primary channel */
93 	if (vmbus_chan_create(dev, dev->relid, 0,
94 					dev->monitor_id, &dev->primary)) {
95 		VMBUS_LOG(ERR, "cannot create primary channel");
96 		goto failed_primary;
97 	}
98 
99 	/* Create and map sub channels */
100 	for (i = 0; i < uio_res->nb_subchannels; i++) {
101 		if (rte_vmbus_subchan_open(dev->primary, &chan)) {
102 			VMBUS_LOG(ERR,
103 				"failed to create subchannel at index %d", i);
104 			goto failed_secondary;
105 		}
106 	}
107 
108 	return 0;
109 
110 failed_secondary:
111 	while (!STAILQ_EMPTY(&dev->primary->subchannel_list)) {
112 		chan = STAILQ_FIRST(&dev->primary->subchannel_list);
113 		vmbus_unmap_resource(chan->txbr.vbr, chan->txbr.dsize * 2);
114 		rte_vmbus_chan_close(chan);
115 	}
116 	rte_vmbus_chan_close(dev->primary);
117 
118 failed_primary:
119 	for (i = 0; i != uio_res->nb_maps; i++) {
120 		vmbus_unmap_resource(
121 				uio_res->maps[i].addr, uio_res->maps[i].size);
122 	}
123 
124 	return -1;
125 }
126 
127 static int
vmbus_uio_map_primary(struct rte_vmbus_device * dev)128 vmbus_uio_map_primary(struct rte_vmbus_device *dev)
129 {
130 	int i, ret;
131 	struct mapped_vmbus_resource *uio_res = NULL;
132 	struct mapped_vmbus_res_list *uio_res_list =
133 		RTE_TAILQ_CAST(vmbus_tailq.head, mapped_vmbus_res_list);
134 
135 	/* allocate uio resource */
136 	ret = vmbus_uio_alloc_resource(dev, &uio_res);
137 	if (ret)
138 		return ret;
139 
140 	/* Map the resources */
141 	for (i = 0; i < VMBUS_MAX_RESOURCE; i++) {
142 		/* stop at empty BAR */
143 		if (dev->resource[i].len == 0)
144 			break;
145 
146 		ret = vmbus_uio_map_resource_by_index(dev, i, uio_res, 0);
147 		if (ret)
148 			goto error;
149 	}
150 
151 	uio_res->nb_maps = i;
152 
153 	TAILQ_INSERT_TAIL(uio_res_list, uio_res, next);
154 
155 	return 0;
156 error:
157 	while (--i >= 0) {
158 		vmbus_unmap_resource(uio_res->maps[i].addr,
159 				(size_t)uio_res->maps[i].size);
160 	}
161 	vmbus_uio_free_resource(dev, uio_res);
162 	return -1;
163 }
164 
165 /* map the VMBUS resource of a VMBUS device in virtual memory */
166 int
vmbus_uio_map_resource(struct rte_vmbus_device * dev)167 vmbus_uio_map_resource(struct rte_vmbus_device *dev)
168 {
169 	struct mapped_vmbus_resource *uio_res;
170 	int ret;
171 
172 	/* TODO: handle rescind */
173 	if (rte_intr_fd_set(dev->intr_handle, -1))
174 		return -1;
175 
176 	if (rte_intr_dev_fd_set(dev->intr_handle, -1))
177 		return -1;
178 
179 	if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN))
180 		return -1;
181 
182 	/* secondary processes - use already recorded details */
183 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
184 		ret = vmbus_uio_map_secondary(dev);
185 	else
186 		ret = vmbus_uio_map_primary(dev);
187 
188 	if (ret != 0)
189 		return ret;
190 
191 	uio_res = vmbus_uio_find_resource(dev);
192 	if (!uio_res) {
193 		VMBUS_LOG(ERR, "can not find resources!");
194 		return -EIO;
195 	}
196 
197 	if (uio_res->nb_maps <= HV_MON_PAGE_MAP) {
198 		VMBUS_LOG(ERR, "VMBUS: only %u resources found!",
199 			uio_res->nb_maps);
200 		return -EINVAL;
201 	}
202 
203 	dev->int_page = (uint32_t *)((char *)uio_res->maps[HV_INT_PAGE_MAP].addr
204 				     + (rte_mem_page_size() >> 1));
205 	dev->monitor_page = uio_res->maps[HV_MON_PAGE_MAP].addr;
206 	return 0;
207 }
208 
209 static void
vmbus_uio_unmap(struct mapped_vmbus_resource * uio_res)210 vmbus_uio_unmap(struct mapped_vmbus_resource *uio_res)
211 {
212 	int i;
213 
214 	if (uio_res == NULL)
215 		return;
216 
217 	for (i = 0; i < uio_res->nb_subchannels; i++) {
218 		vmbus_unmap_resource(uio_res->subchannel_maps[i].addr,
219 				uio_res->subchannel_maps[i].size);
220 	}
221 
222 	for (i = 0; i != uio_res->nb_maps; i++) {
223 		vmbus_unmap_resource(uio_res->maps[i].addr,
224 				     (size_t)uio_res->maps[i].size);
225 	}
226 }
227 
228 /* unmap the VMBUS resource of a VMBUS device in virtual memory */
229 void
vmbus_uio_unmap_resource(struct rte_vmbus_device * dev)230 vmbus_uio_unmap_resource(struct rte_vmbus_device *dev)
231 {
232 	struct mapped_vmbus_resource *uio_res;
233 	struct mapped_vmbus_res_list *uio_res_list =
234 			RTE_TAILQ_CAST(vmbus_tailq.head, mapped_vmbus_res_list);
235 
236 	if (dev == NULL)
237 		return;
238 
239 	/* find an entry for the device */
240 	uio_res = vmbus_uio_find_resource(dev);
241 	if (uio_res == NULL)
242 		return;
243 
244 	/* secondary processes - just free maps */
245 	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
246 		vmbus_uio_unmap(uio_res);
247 		rte_free(dev->primary);
248 		return;
249 	}
250 
251 	TAILQ_REMOVE(uio_res_list, uio_res, next);
252 
253 	/* unmap all resources */
254 	vmbus_uio_unmap(uio_res);
255 
256 	/* free uio resource */
257 	rte_free(uio_res);
258 
259 	/* close fd if in primary process */
260 	if (rte_intr_fd_get(dev->intr_handle) >= 0)
261 		close(rte_intr_fd_get(dev->intr_handle));
262 
263 	if (rte_intr_dev_fd_get(dev->intr_handle) >= 0) {
264 		close(rte_intr_dev_fd_get(dev->intr_handle));
265 		rte_intr_dev_fd_set(dev->intr_handle, -1);
266 	}
267 
268 	rte_intr_fd_set(dev->intr_handle, -1);
269 	rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
270 }
271