1
2
3
4
5
6#include <string.h>
7#include <unistd.h>
8#include <fcntl.h>
9#include <dirent.h>
10#include <inttypes.h>
11#include <sys/stat.h>
12#include <sys/mman.h>
13
14#include <rte_eal.h>
15#include <rte_log.h>
16#include <rte_memory.h>
17#include <rte_common.h>
18#include <rte_malloc.h>
19#include <rte_bus_vmbus.h>
20#include <rte_string_fns.h>
21
22#include "private.h"
23
24
25#define SYSFS_VMBUS_DEVICES "/sys/bus/vmbus/devices"
26
27static void *vmbus_map_addr;
28
29
30void vmbus_uio_irq_control(struct rte_vmbus_device *dev, int32_t onoff)
31{
32 if ((rte_intr_fd_get(dev->intr_handle) < 0) ||
33 write(rte_intr_fd_get(dev->intr_handle), &onoff,
34 sizeof(onoff)) < 0) {
35 VMBUS_LOG(ERR, "cannot write to %d:%s",
36 rte_intr_fd_get(dev->intr_handle),
37 strerror(errno));
38 }
39}
40
41int vmbus_uio_irq_read(struct rte_vmbus_device *dev)
42{
43 int32_t count;
44 int cc;
45
46 if (rte_intr_fd_get(dev->intr_handle) < 0)
47 return -1;
48
49 cc = read(rte_intr_fd_get(dev->intr_handle), &count,
50 sizeof(count));
51 if (cc < (int)sizeof(count)) {
52 if (cc < 0) {
53 VMBUS_LOG(ERR, "IRQ read failed %s",
54 strerror(errno));
55 return -errno;
56 }
57 VMBUS_LOG(ERR, "can't read IRQ count");
58 return -EINVAL;
59 }
60
61 return count;
62}
63
64void
65vmbus_uio_free_resource(struct rte_vmbus_device *dev,
66 struct mapped_vmbus_resource *uio_res)
67{
68 rte_free(uio_res);
69
70 if (rte_intr_dev_fd_get(dev->intr_handle) >= 0) {
71 close(rte_intr_dev_fd_get(dev->intr_handle));
72 rte_intr_dev_fd_set(dev->intr_handle, -1);
73 }
74
75 if (rte_intr_fd_get(dev->intr_handle) >= 0) {
76 close(rte_intr_fd_get(dev->intr_handle));
77 rte_intr_fd_set(dev->intr_handle, -1);
78 rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
79 }
80}
81
82int
83vmbus_uio_alloc_resource(struct rte_vmbus_device *dev,
84 struct mapped_vmbus_resource **uio_res)
85{
86 char devname[PATH_MAX];
87 int fd;
88
89
90 snprintf(devname, sizeof(devname), "/dev/uio%u", dev->uio_num);
91 fd = open(devname, O_RDWR);
92 if (fd < 0) {
93 VMBUS_LOG(ERR, "Cannot open %s: %s",
94 devname, strerror(errno));
95 goto error;
96 }
97
98 if (rte_intr_fd_set(dev->intr_handle, fd))
99 goto error;
100
101 if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UIO_INTX))
102 goto error;
103
104
105 *uio_res = rte_zmalloc("UIO_RES", sizeof(**uio_res), 0);
106 if (*uio_res == NULL) {
107 VMBUS_LOG(ERR, "cannot store uio mmap details");
108 goto error;
109 }
110
111 strlcpy((*uio_res)->path, devname, PATH_MAX);
112 rte_uuid_copy((*uio_res)->id, dev->device_id);
113
114 return 0;
115
116error:
117 vmbus_uio_free_resource(dev, *uio_res);
118 return -1;
119}
120
121static int
122find_max_end_va(const struct rte_memseg_list *msl, void *arg)
123{
124 size_t sz = msl->memseg_arr.len * msl->page_sz;
125 void *end_va = RTE_PTR_ADD(msl->base_va, sz);
126 void **max_va = arg;
127
128 if (*max_va < end_va)
129 *max_va = end_va;
130 return 0;
131}
132
133
134
135
136
137static void *
138vmbus_find_max_end_va(void)
139{
140 void *va = NULL;
141
142 rte_memseg_list_walk(find_max_end_va, &va);
143 return va;
144}
145
146int
147vmbus_uio_map_resource_by_index(struct rte_vmbus_device *dev, int idx,
148 struct mapped_vmbus_resource *uio_res,
149 int flags)
150{
151 size_t size = dev->resource[idx].len;
152 struct vmbus_map *maps = uio_res->maps;
153 void *mapaddr;
154 off_t offset;
155 int fd;
156
157
158 fd = open(uio_res->path, O_RDWR);
159 if (fd < 0) {
160 VMBUS_LOG(ERR, "Cannot open %s: %s",
161 uio_res->path, strerror(errno));
162 return -1;
163 }
164
165
166 if (vmbus_map_addr == NULL)
167 vmbus_map_addr = vmbus_find_max_end_va();
168
169
170 offset = idx * rte_mem_page_size();
171
172 mapaddr = vmbus_map_resource(vmbus_map_addr, fd, offset, size, flags);
173 close(fd);
174
175 if (mapaddr == MAP_FAILED)
176 return -1;
177
178 dev->resource[idx].addr = mapaddr;
179 vmbus_map_addr = RTE_PTR_ADD(mapaddr, size);
180
181
182 maps[idx].addr = mapaddr;
183 maps[idx].size = size;
184
185 return 0;
186}
187
188static int vmbus_uio_map_primary(struct vmbus_channel *chan,
189 void **ring_buf, uint32_t *ring_size)
190{
191 struct mapped_vmbus_resource *uio_res;
192
193 uio_res = vmbus_uio_find_resource(chan->device);
194 if (!uio_res) {
195 VMBUS_LOG(ERR, "can not find resources!");
196 return -ENOMEM;
197 }
198
199 if (uio_res->nb_maps < VMBUS_MAX_RESOURCE) {
200 VMBUS_LOG(ERR, "VMBUS: only %u resources found!",
201 uio_res->nb_maps);
202 return -EINVAL;
203 }
204
205 *ring_size = uio_res->maps[HV_TXRX_RING_MAP].size / 2;
206 *ring_buf = uio_res->maps[HV_TXRX_RING_MAP].addr;
207 return 0;
208}
209
210static int vmbus_uio_map_subchan(const struct rte_vmbus_device *dev,
211 const struct vmbus_channel *chan,
212 void **ring_buf, uint32_t *ring_size)
213{
214 char ring_path[PATH_MAX];
215 size_t file_size;
216 struct stat sb;
217 void *mapaddr;
218 int fd;
219 struct mapped_vmbus_resource *uio_res;
220 int channel_idx;
221
222 uio_res = vmbus_uio_find_resource(dev);
223 if (!uio_res) {
224 VMBUS_LOG(ERR, "can not find resources for mapping subchan");
225 return -ENOMEM;
226 }
227
228 if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
229 if (uio_res->nb_subchannels >= UIO_MAX_SUBCHANNEL) {
230 VMBUS_LOG(ERR,
231 "exceeding max subchannels UIO_MAX_SUBCHANNEL(%d)",
232 UIO_MAX_SUBCHANNEL);
233 VMBUS_LOG(ERR, "Change UIO_MAX_SUBCHANNEL and recompile");
234 return -ENOMEM;
235 }
236 } else {
237 for (channel_idx = 0; channel_idx < uio_res->nb_subchannels;
238 channel_idx++)
239 if (uio_res->subchannel_maps[channel_idx].relid ==
240 chan->relid)
241 break;
242 if (channel_idx == uio_res->nb_subchannels) {
243 VMBUS_LOG(ERR,
244 "couldn't find sub channel %d from shared mapping in primary",
245 chan->relid);
246 return -ENOMEM;
247 }
248 vmbus_map_addr = uio_res->subchannel_maps[channel_idx].addr;
249 }
250
251 snprintf(ring_path, sizeof(ring_path),
252 "%s/%s/channels/%u/ring",
253 SYSFS_VMBUS_DEVICES, dev->device.name,
254 chan->relid);
255
256 fd = open(ring_path, O_RDWR);
257 if (fd < 0) {
258 VMBUS_LOG(ERR, "Cannot open %s: %s",
259 ring_path, strerror(errno));
260 return -errno;
261 }
262
263 if (fstat(fd, &sb) < 0) {
264 VMBUS_LOG(ERR, "Cannot state %s: %s",
265 ring_path, strerror(errno));
266 close(fd);
267 return -errno;
268 }
269 file_size = sb.st_size;
270
271 if (file_size == 0 || (file_size & (rte_mem_page_size() - 1))) {
272 VMBUS_LOG(ERR, "incorrect size %s: %zu",
273 ring_path, file_size);
274
275 close(fd);
276 return -EINVAL;
277 }
278
279 mapaddr = vmbus_map_resource(vmbus_map_addr, fd,
280 0, file_size, 0);
281 close(fd);
282
283 if (mapaddr == MAP_FAILED)
284 return -EIO;
285
286 if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
287
288
289 uio_res->subchannel_maps[uio_res->nb_subchannels].relid =
290 chan->relid;
291 uio_res->subchannel_maps[uio_res->nb_subchannels].addr =
292 mapaddr;
293 uio_res->subchannel_maps[uio_res->nb_subchannels].size =
294 file_size;
295 uio_res->nb_subchannels++;
296
297 vmbus_map_addr = RTE_PTR_ADD(mapaddr, file_size);
298 } else {
299 if (mapaddr != vmbus_map_addr) {
300 VMBUS_LOG(ERR, "failed to map channel %d to addr %p",
301 chan->relid, mapaddr);
302 vmbus_unmap_resource(mapaddr, file_size);
303 return -EIO;
304 }
305 }
306
307 *ring_size = file_size / 2;
308 *ring_buf = mapaddr;
309
310 return 0;
311}
312
313int vmbus_uio_map_rings(struct vmbus_channel *chan)
314{
315 const struct rte_vmbus_device *dev = chan->device;
316 uint32_t ring_size;
317 void *ring_buf;
318 int ret;
319
320
321 if (chan->subchannel_id == 0)
322 ret = vmbus_uio_map_primary(chan, &ring_buf, &ring_size);
323 else
324 ret = vmbus_uio_map_subchan(dev, chan, &ring_buf, &ring_size);
325
326 if (ret)
327 return ret;
328
329 vmbus_br_setup(&chan->txbr, ring_buf, ring_size);
330 vmbus_br_setup(&chan->rxbr, (char *)ring_buf + ring_size, ring_size);
331 return 0;
332}
333
334static int vmbus_uio_sysfs_read(const char *dir, const char *name,
335 unsigned long *val, unsigned long max_range)
336{
337 char path[PATH_MAX];
338 FILE *f;
339 int ret;
340
341 snprintf(path, sizeof(path), "%s/%s", dir, name);
342 f = fopen(path, "r");
343 if (!f) {
344 VMBUS_LOG(ERR, "can't open %s:%s",
345 path, strerror(errno));
346 return -errno;
347 }
348
349 if (fscanf(f, "%lu", val) != 1)
350 ret = -EIO;
351 else if (*val > max_range)
352 ret = -ERANGE;
353 else
354 ret = 0;
355 fclose(f);
356
357 return ret;
358}
359
360static bool vmbus_uio_ring_present(const struct rte_vmbus_device *dev,
361 uint32_t relid)
362{
363 char ring_path[PATH_MAX];
364
365
366 snprintf(ring_path, sizeof(ring_path),
367 "%s/%s/channels/%u/ring",
368 SYSFS_VMBUS_DEVICES, dev->device.name, relid);
369
370 return access(ring_path, R_OK|W_OK) == 0;
371}
372
373bool vmbus_uio_subchannels_supported(const struct rte_vmbus_device *dev,
374 const struct vmbus_channel *chan)
375{
376 return vmbus_uio_ring_present(dev, chan->relid);
377}
378
379static bool vmbus_isnew_subchannel(struct vmbus_channel *primary,
380 unsigned long id)
381{
382 const struct vmbus_channel *c;
383
384 STAILQ_FOREACH(c, &primary->subchannel_list, next) {
385 if (c->relid == id)
386 return false;
387 }
388 return true;
389}
390
391int vmbus_uio_get_subchan(struct vmbus_channel *primary,
392 struct vmbus_channel **subchan)
393{
394 const struct rte_vmbus_device *dev = primary->device;
395 char chan_path[PATH_MAX], subchan_path[PATH_MAX];
396 struct dirent *ent;
397 DIR *chan_dir;
398 int err;
399
400 snprintf(chan_path, sizeof(chan_path),
401 "%s/%s/channels",
402 SYSFS_VMBUS_DEVICES, dev->device.name);
403
404 chan_dir = opendir(chan_path);
405 if (!chan_dir) {
406 VMBUS_LOG(ERR, "cannot open %s: %s",
407 chan_path, strerror(errno));
408 return -errno;
409 }
410
411 while ((ent = readdir(chan_dir))) {
412 unsigned long relid, subid, monid;
413 char *endp;
414
415 if (ent->d_name[0] == '.')
416 continue;
417
418 errno = 0;
419 relid = strtoul(ent->d_name, &endp, 0);
420 if (*endp || errno != 0 || relid > UINT16_MAX) {
421 VMBUS_LOG(NOTICE, "not a valid channel relid: %s",
422 ent->d_name);
423 continue;
424 }
425
426 if (!vmbus_isnew_subchannel(primary, relid)) {
427 VMBUS_LOG(DEBUG, "skip already found channel: %lu",
428 relid);
429 continue;
430 }
431
432 if (!vmbus_uio_ring_present(dev, relid)) {
433 VMBUS_LOG(DEBUG, "ring mmap not found (yet) for: %lu",
434 relid);
435 continue;
436 }
437
438 snprintf(subchan_path, sizeof(subchan_path), "%s/%lu",
439 chan_path, relid);
440 err = vmbus_uio_sysfs_read(subchan_path, "subchannel_id",
441 &subid, UINT16_MAX);
442 if (err) {
443 VMBUS_LOG(NOTICE, "no subchannel_id in %s:%s",
444 subchan_path, strerror(-err));
445 goto fail;
446 }
447
448 if (subid == 0)
449 continue;
450
451 err = vmbus_uio_sysfs_read(subchan_path, "monitor_id",
452 &monid, UINT8_MAX);
453 if (err) {
454 VMBUS_LOG(NOTICE, "no monitor_id in %s:%s",
455 subchan_path, strerror(-err));
456 goto fail;
457 }
458
459 err = vmbus_chan_create(dev, relid, subid, monid, subchan);
460 if (err) {
461 VMBUS_LOG(ERR, "subchannel setup failed");
462 goto fail;
463 }
464 break;
465 }
466 closedir(chan_dir);
467
468 return (ent == NULL) ? -ENOENT : 0;
469fail:
470 closedir(chan_dir);
471 return err;
472}
473