master
c 701 lines 21 KB
Raw
1 /*
2 * iommufd container backend
3 *
4 * Copyright (C) 2023 Intel Corporation.
5 * Copyright Red Hat, Inc. 2023
6 *
7 * Authors: Yi Liu <yi.l.liu@intel.com>
8 * Eric Auger <eric.auger@redhat.com>
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13 #include "qemu/osdep.h"
14 #include "system/iommufd.h"
15 #include "qapi/error.h"
16 #include "qemu/module.h"
17 #include "qom/object_interfaces.h"
18 #include "qemu/error-report.h"
19 #include "migration/cpr.h"
20 #include "monitor/monitor.h"
21 #include "trace.h"
22 #include "hw/vfio/vfio-device.h"
23 #include <sys/ioctl.h>
24 #include <linux/iommufd.h>
25
26 static const char *iommufd_fd_name(IOMMUFDBackend *be)
27 {
28 return object_get_canonical_path_component(OBJECT(be));
29 }
30
31 static void iommufd_backend_init(Object *obj)
32 {
33 IOMMUFDBackend *be = IOMMUFD_BACKEND(obj);
34
35 be->fd = -1;
36 be->users = 0;
37 be->owned = true;
38 }
39
40 static void iommufd_backend_finalize(Object *obj)
41 {
42 IOMMUFDBackend *be = IOMMUFD_BACKEND(obj);
43
44 if (be->owned) {
45 close(be->fd);
46 be->fd = -1;
47 }
48 }
49
50 static void iommufd_backend_set_fd(Object *obj, const char *str, Error **errp)
51 {
52 ERRP_GUARD();
53 IOMMUFDBackend *be = IOMMUFD_BACKEND(obj);
54 int fd = -1;
55
56 fd = monitor_fd_param(monitor_cur(), str, errp);
57 if (fd == -1) {
58 error_prepend(errp, "Could not parse remote object fd %s:", str);
59 return;
60 }
61 be->fd = fd;
62 be->owned = false;
63 trace_iommu_backend_set_fd(be->fd);
64 }
65
66 static bool iommufd_backend_prepare_delete(UserCreatable *uc, Error **errp)
67 {
68 IOMMUFDBackend *be = IOMMUFD_BACKEND(uc);
69
70 if (be->users) {
71 error_setg(errp, "Can not delete IOMMUFD backend '%s' with %d users",
72 object_get_canonical_path_component(OBJECT(uc)), be->users);
73 return false;
74 }
75 return true;
76 }
77
78 static void iommufd_backend_complete(UserCreatable *uc, Error **errp)
79 {
80 IOMMUFDBackend *be = IOMMUFD_BACKEND(uc);
81 const char *name = iommufd_fd_name(be);
82
83 if (!be->owned) {
84 /* fd came from the command line. Fetch updated value from cpr state. */
85 if (cpr_is_incoming()) {
86 be->fd = cpr_find_fd(name, 0);
87 } else {
88 cpr_save_fd(name, 0, be->fd);
89 }
90 } else if (!g_file_test("/dev/iommu", G_FILE_TEST_EXISTS)) {
91 error_setg(errp, "/dev/iommu does not exist"
92 " (is your kernel config missing CONFIG_IOMMUFD?)");
93 }
94 }
95
96 static void iommufd_backend_class_init(ObjectClass *oc, const void *data)
97 {
98 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
99
100 ucc->prepare_delete = iommufd_backend_prepare_delete;
101 ucc->complete = iommufd_backend_complete;
102
103 object_class_property_add_str(oc, "fd", NULL, iommufd_backend_set_fd);
104 }
105
106 bool iommufd_change_process_capable(IOMMUFDBackend *be)
107 {
108 struct iommu_ioas_change_process args = {.size = sizeof(args)};
109
110 /*
111 * Call IOMMU_IOAS_CHANGE_PROCESS to verify it is a recognized ioctl.
112 * This is a no-op if the process has not changed since DMA was mapped.
113 */
114 return !ioctl(be->fd, IOMMU_IOAS_CHANGE_PROCESS, &args);
115 }
116
117 bool iommufd_change_process(IOMMUFDBackend *be, Error **errp)
118 {
119 struct iommu_ioas_change_process args = {.size = sizeof(args)};
120 bool ret = !ioctl(be->fd, IOMMU_IOAS_CHANGE_PROCESS, &args);
121
122 if (!ret) {
123 error_setg_errno(errp, errno, "IOMMU_IOAS_CHANGE_PROCESS fd %d failed",
124 be->fd);
125 }
126 trace_iommufd_change_process(be->fd, ret);
127 return ret;
128 }
129
130 bool iommufd_backend_connect(IOMMUFDBackend *be, Error **errp)
131 {
132 int fd;
133
134 if (be->owned && !be->users) {
135 fd = cpr_open_fd("/dev/iommu", O_RDWR, iommufd_fd_name(be), 0, errp);
136 if (fd < 0) {
137 return false;
138 }
139 be->fd = fd;
140 }
141 if (!be->users && !vfio_iommufd_cpr_register_iommufd(be, errp)) {
142 if (be->owned) {
143 close(be->fd);
144 be->fd = -1;
145 }
146 return false;
147 }
148 be->users++;
149
150 trace_iommufd_backend_connect(be->fd, be->owned, be->users);
151 return true;
152 }
153
154 void iommufd_backend_disconnect(IOMMUFDBackend *be)
155 {
156 if (!be->users) {
157 goto out;
158 }
159 be->users--;
160 if (!be->users) {
161 vfio_iommufd_cpr_unregister_iommufd(be);
162 if (be->owned) {
163 cpr_delete_fd(iommufd_fd_name(be), 0);
164 close(be->fd);
165 be->fd = -1;
166 }
167 }
168 out:
169 trace_iommufd_backend_disconnect(be->fd, be->users);
170 }
171
172 bool iommufd_backend_alloc_ioas(IOMMUFDBackend *be, uint32_t *ioas_id,
173 Error **errp)
174 {
175 int fd = be->fd;
176 struct iommu_ioas_alloc alloc_data = {
177 .size = sizeof(alloc_data),
178 .flags = 0,
179 };
180
181 if (ioctl(fd, IOMMU_IOAS_ALLOC, &alloc_data)) {
182 error_setg_errno(errp, errno, "Failed to allocate ioas");
183 return false;
184 }
185
186 *ioas_id = alloc_data.out_ioas_id;
187 trace_iommufd_backend_alloc_ioas(fd, *ioas_id);
188
189 return true;
190 }
191
192 void iommufd_backend_free_id(IOMMUFDBackend *be, uint32_t id)
193 {
194 int ret, fd = be->fd;
195 struct iommu_destroy des = {
196 .size = sizeof(des),
197 .id = id,
198 };
199
200 ret = ioctl(fd, IOMMU_DESTROY, &des);
201 trace_iommufd_backend_free_id(fd, id, ret);
202 if (ret) {
203 error_report("Failed to free id: %u %m", id);
204 }
205 }
206
207 int iommufd_backend_map_dma(IOMMUFDBackend *be, uint32_t ioas_id, hwaddr iova,
208 uint64_t size, void *vaddr, bool readonly)
209 {
210 int ret, fd = be->fd;
211 struct iommu_ioas_map map = {
212 .size = sizeof(map),
213 .flags = IOMMU_IOAS_MAP_READABLE |
214 IOMMU_IOAS_MAP_FIXED_IOVA,
215 .ioas_id = ioas_id,
216 .__reserved = 0,
217 .user_va = (uintptr_t)vaddr,
218 .iova = iova,
219 .length = size,
220 };
221
222 if (!readonly) {
223 map.flags |= IOMMU_IOAS_MAP_WRITEABLE;
224 }
225
226 ret = ioctl(fd, IOMMU_IOAS_MAP, &map);
227 trace_iommufd_backend_map_dma(fd, ioas_id, iova, size,
228 vaddr, readonly, ret);
229 if (ret) {
230 ret = -errno;
231
232 /* TODO: Not support mapping hardware PCI BAR region for now. */
233 if (errno == EFAULT) {
234 warn_report("IOMMU_IOAS_MAP failed: %m, PCI BAR?");
235 }
236 }
237 return ret;
238 }
239
240 int iommufd_backend_map_file_dma(IOMMUFDBackend *be, uint32_t ioas_id,
241 hwaddr iova, uint64_t size,
242 int mfd, unsigned long start, bool readonly)
243 {
244 int ret, fd = be->fd;
245 struct iommu_ioas_map_file map = {
246 .size = sizeof(map),
247 .flags = IOMMU_IOAS_MAP_READABLE |
248 IOMMU_IOAS_MAP_FIXED_IOVA,
249 .ioas_id = ioas_id,
250 .fd = mfd,
251 .start = start,
252 .iova = iova,
253 .length = size,
254 };
255
256 if (cpr_is_incoming()) {
257 return 0;
258 }
259
260 if (!readonly) {
261 map.flags |= IOMMU_IOAS_MAP_WRITEABLE;
262 }
263
264 ret = ioctl(fd, IOMMU_IOAS_MAP_FILE, &map);
265 trace_iommufd_backend_map_file_dma(fd, ioas_id, iova, size, mfd, start,
266 readonly, ret);
267 if (ret) {
268 ret = -errno;
269
270 /* TODO: Not support mapping hardware PCI BAR region for now. */
271 if (errno == EFAULT) {
272 warn_report("IOMMU_IOAS_MAP_FILE failed: %m, PCI BAR?");
273 }
274 }
275 return ret;
276 }
277
278 int iommufd_backend_unmap_dma(IOMMUFDBackend *be, uint32_t ioas_id,
279 hwaddr iova, uint64_t size)
280 {
281 int ret, fd = be->fd;
282 struct iommu_ioas_unmap unmap = {
283 .size = sizeof(unmap),
284 .ioas_id = ioas_id,
285 .iova = iova,
286 .length = size,
287 };
288
289 if (cpr_is_incoming()) {
290 return 0;
291 }
292
293 ret = ioctl(fd, IOMMU_IOAS_UNMAP, &unmap);
294 /*
295 * IOMMUFD takes mapping as some kind of object, unmapping
296 * nonexistent mapping is treated as deleting a nonexistent
297 * object and return ENOENT. This is different from legacy
298 * backend which allows it. vIOMMU may trigger a lot of
299 * redundant unmapping, to avoid flush the log, treat them
300 * as succeess for IOMMUFD just like legacy backend.
301 */
302 if (ret && errno == ENOENT) {
303 trace_iommufd_backend_unmap_dma_non_exist(fd, ioas_id, iova, size, ret);
304 ret = 0;
305 } else {
306 trace_iommufd_backend_unmap_dma(fd, ioas_id, iova, size, ret);
307 }
308
309 if (ret) {
310 ret = -errno;
311 }
312 return ret;
313 }
314
315 bool iommufd_backend_alloc_hwpt(IOMMUFDBackend *be, uint32_t dev_id,
316 uint32_t pt_id, uint32_t flags,
317 uint32_t data_type, uint32_t data_len,
318 void *data_ptr, uint32_t *out_hwpt,
319 Error **errp)
320 {
321 int ret, fd = be->fd;
322 struct iommu_hwpt_alloc alloc_hwpt = {
323 .size = sizeof(struct iommu_hwpt_alloc),
324 .flags = flags,
325 .dev_id = dev_id,
326 .pt_id = pt_id,
327 .data_type = data_type,
328 .data_len = data_len,
329 .data_uptr = (uintptr_t)data_ptr,
330 };
331
332 ret = ioctl(fd, IOMMU_HWPT_ALLOC, &alloc_hwpt);
333 trace_iommufd_backend_alloc_hwpt(fd, dev_id, pt_id, flags, data_type,
334 data_len, (uintptr_t)data_ptr,
335 alloc_hwpt.out_hwpt_id, ret);
336 if (ret) {
337 error_setg_errno(errp, errno, "Failed to allocate hwpt");
338 return false;
339 }
340
341 *out_hwpt = alloc_hwpt.out_hwpt_id;
342 return true;
343 }
344
345 bool iommufd_backend_set_dirty_tracking(IOMMUFDBackend *be,
346 uint32_t hwpt_id, bool start,
347 Error **errp)
348 {
349 int ret;
350 struct iommu_hwpt_set_dirty_tracking set_dirty = {
351 .size = sizeof(set_dirty),
352 .hwpt_id = hwpt_id,
353 .flags = start ? IOMMU_HWPT_DIRTY_TRACKING_ENABLE : 0,
354 };
355
356 ret = ioctl(be->fd, IOMMU_HWPT_SET_DIRTY_TRACKING, &set_dirty);
357 trace_iommufd_backend_set_dirty(be->fd, hwpt_id, start, ret ? errno : 0);
358 if (ret) {
359 error_setg_errno(errp, errno,
360 "IOMMU_HWPT_SET_DIRTY_TRACKING(hwpt_id %u) failed",
361 hwpt_id);
362 return false;
363 }
364
365 return true;
366 }
367
368 bool iommufd_backend_get_dirty_bitmap(IOMMUFDBackend *be,
369 uint32_t hwpt_id,
370 uint64_t iova, ram_addr_t size,
371 uint64_t page_size, uint64_t *data,
372 uint64_t flags, Error **errp)
373 {
374 int ret;
375 struct iommu_hwpt_get_dirty_bitmap get_dirty_bitmap = {
376 .size = sizeof(get_dirty_bitmap),
377 .hwpt_id = hwpt_id,
378 .iova = iova,
379 .length = size,
380 .page_size = page_size,
381 .data = (uintptr_t)data,
382 .flags = flags,
383 };
384
385 ret = ioctl(be->fd, IOMMU_HWPT_GET_DIRTY_BITMAP, &get_dirty_bitmap);
386 trace_iommufd_backend_get_dirty_bitmap(be->fd, hwpt_id, iova, size,
387 flags, page_size, ret ? errno : 0);
388 if (ret) {
389 error_setg_errno(errp, errno,
390 "IOMMU_HWPT_GET_DIRTY_BITMAP (iova: 0x%"HWADDR_PRIx
391 " size: 0x"RAM_ADDR_FMT") failed", iova, size);
392 return false;
393 }
394
395 return true;
396 }
397
398 /*
399 * @type can carry a desired HW info type defined in the uapi headers. If caller
400 * doesn't have one, indicating it wants the default type, then @type should be
401 * zeroed (i.e. IOMMU_HW_INFO_TYPE_DEFAULT).
402 */
403 bool iommufd_backend_get_device_info(IOMMUFDBackend *be, uint32_t devid,
404 uint32_t *type, void *data, uint32_t len,
405 uint64_t *caps, uint8_t *max_pasid_log2,
406 Error **errp)
407 {
408 struct iommu_hw_info info = {
409 .flags = (*type) ? IOMMU_HW_INFO_FLAG_INPUT_TYPE : 0,
410 .size = sizeof(info),
411 .dev_id = devid,
412 .data_len = len,
413 .data_uptr = (uintptr_t)data,
414 .in_data_type = *type,
415 };
416
417 if (ioctl(be->fd, IOMMU_GET_HW_INFO, &info)) {
418 error_setg_errno(errp, errno, "Failed to get hardware info");
419 return false;
420 }
421
422 g_assert(type);
423 *type = info.out_data_type;
424 g_assert(caps);
425 *caps = info.out_capabilities;
426
427 if (max_pasid_log2) {
428 *max_pasid_log2 = info.out_max_pasid_log2;
429 }
430 return true;
431 }
432
433 bool iommufd_backend_invalidate_cache(IOMMUFDBackend *be, uint32_t id,
434 uint32_t data_type, uint32_t entry_len,
435 uint32_t *entry_num, void *data,
436 Error **errp)
437 {
438 int ret, fd = be->fd;
439 uint32_t total_entries = *entry_num;
440 struct iommu_hwpt_invalidate cache = {
441 .size = sizeof(cache),
442 .hwpt_id = id,
443 .data_type = data_type,
444 .entry_len = entry_len,
445 .entry_num = total_entries,
446 .data_uptr = (uintptr_t)data,
447 };
448
449 ret = ioctl(fd, IOMMU_HWPT_INVALIDATE, &cache);
450 trace_iommufd_backend_invalidate_cache(fd, id, data_type, entry_len,
451 total_entries, cache.entry_num,
452 (uintptr_t)data, ret ? errno : 0);
453 *entry_num = cache.entry_num;
454
455 if (ret) {
456 error_setg_errno(errp, errno, "IOMMU_HWPT_INVALIDATE failed:"
457 " total %d entries, processed %d entries",
458 total_entries, cache.entry_num);
459 } else if (total_entries != cache.entry_num) {
460 error_setg(errp, "IOMMU_HWPT_INVALIDATE succeed but with unprocessed"
461 " entries: total %d entries, processed %d entries."
462 " Kernel BUG?!", total_entries, cache.entry_num);
463 return false;
464 }
465
466 return !ret;
467 }
468
469 bool iommufd_backend_alloc_viommu(IOMMUFDBackend *be, uint32_t dev_id,
470 uint32_t viommu_type, uint32_t hwpt_id,
471 void *data_ptr, uint32_t data_len,
472 uint32_t *out_viommu_id, Error **errp)
473 {
474 int ret;
475 struct iommu_viommu_alloc alloc_viommu = {
476 .size = sizeof(alloc_viommu),
477 .type = viommu_type,
478 .dev_id = dev_id,
479 .hwpt_id = hwpt_id,
480 .data_len = data_len,
481 .data_uptr = (uintptr_t)data_ptr,
482 };
483
484 ret = ioctl(be->fd, IOMMU_VIOMMU_ALLOC, &alloc_viommu);
485
486 trace_iommufd_backend_alloc_viommu(be->fd, dev_id, viommu_type, hwpt_id,
487 (uintptr_t)data_ptr, data_len,
488 alloc_viommu.out_viommu_id, ret);
489 if (ret) {
490 error_setg_errno(errp, errno, "IOMMU_VIOMMU_ALLOC failed");
491 return false;
492 }
493
494 g_assert(out_viommu_id);
495 *out_viommu_id = alloc_viommu.out_viommu_id;
496 return true;
497 }
498
499 bool iommufd_backend_alloc_vdev(IOMMUFDBackend *be, uint32_t dev_id,
500 uint32_t viommu_id, uint64_t virt_id,
501 uint32_t *out_vdev_id, Error **errp)
502 {
503 int ret;
504 struct iommu_vdevice_alloc alloc_vdev = {
505 .size = sizeof(alloc_vdev),
506 .viommu_id = viommu_id,
507 .dev_id = dev_id,
508 .virt_id = virt_id,
509 };
510
511 ret = ioctl(be->fd, IOMMU_VDEVICE_ALLOC, &alloc_vdev);
512
513 trace_iommufd_backend_alloc_vdev(be->fd, dev_id, viommu_id, virt_id,
514 alloc_vdev.out_vdevice_id, ret);
515
516 if (ret) {
517 error_setg_errno(errp, errno, "IOMMU_VDEVICE_ALLOC failed");
518 return false;
519 }
520
521 g_assert(out_vdev_id);
522 *out_vdev_id = alloc_vdev.out_vdevice_id;
523 return true;
524 }
525
526 bool iommufd_backend_alloc_veventq(IOMMUFDBackend *be, uint32_t viommu_id,
527 uint32_t type, uint32_t depth,
528 uint32_t *out_veventq_id,
529 uint32_t *out_veventq_fd, Error **errp)
530 {
531 int ret;
532 struct iommu_veventq_alloc alloc_veventq = {
533 .size = sizeof(alloc_veventq),
534 .flags = 0,
535 .type = type,
536 .veventq_depth = depth,
537 .viommu_id = viommu_id,
538 };
539
540 ret = ioctl(be->fd, IOMMU_VEVENTQ_ALLOC, &alloc_veventq);
541
542 trace_iommufd_viommu_alloc_eventq(be->fd, viommu_id, type,
543 alloc_veventq.out_veventq_id,
544 alloc_veventq.out_veventq_fd, ret);
545 if (ret) {
546 error_setg_errno(errp, errno, "IOMMU_VEVENTQ_ALLOC failed");
547 return false;
548 }
549
550 g_assert(out_veventq_id);
551 g_assert(out_veventq_fd);
552 *out_veventq_id = alloc_veventq.out_veventq_id;
553 *out_veventq_fd = alloc_veventq.out_veventq_fd;
554 return true;
555 }
556
557 bool iommufd_backend_alloc_hw_queue(IOMMUFDBackend *be, uint32_t viommu_id,
558 uint32_t queue_type, uint32_t index,
559 uint64_t addr, uint64_t length,
560 uint32_t *out_hw_queue_id, Error **errp)
561 {
562 int ret;
563 struct iommu_hw_queue_alloc alloc_hw_queue = {
564 .size = sizeof(alloc_hw_queue),
565 .flags = 0,
566 .viommu_id = viommu_id,
567 .type = queue_type,
568 .index = index,
569 .nesting_parent_iova = addr,
570 .length = length,
571 };
572
573 ret = ioctl(be->fd, IOMMU_HW_QUEUE_ALLOC, &alloc_hw_queue);
574
575 trace_iommufd_backend_alloc_hw_queue(be->fd, viommu_id, queue_type,
576 index, addr, length,
577 alloc_hw_queue.out_hw_queue_id, ret);
578 if (ret) {
579 error_setg_errno(errp, errno, "IOMMU_HW_QUEUE_ALLOC failed");
580 return false;
581 }
582
583 g_assert(out_hw_queue_id);
584 *out_hw_queue_id = alloc_hw_queue.out_hw_queue_id;
585 return true;
586 }
587
588 /*
589 * Helper to mmap HW MMIO regions exposed via iommufd for a vIOMMU instance.
590 * The caller is responsible for unmapping the mapped region.
591 */
592 bool iommufd_backend_viommu_mmap(IOMMUFDBackend *be, uint32_t viommu_id,
593 uint64_t size, off_t offset, void **out_ptr,
594 Error **errp)
595 {
596 g_assert(viommu_id);
597 g_assert(out_ptr);
598
599 *out_ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, be->fd,
600 offset);
601 trace_iommufd_backend_viommu_mmap(be->fd, viommu_id, size, offset);
602 if (*out_ptr == MAP_FAILED) {
603 error_setg_errno(errp, errno, "IOMMUFD vIOMMU mmap failed");
604 return false;
605 }
606
607 return true;
608 }
609
610 bool host_iommu_device_iommufd_attach_hwpt(HostIOMMUDeviceIOMMUFD *hiodi,
611 uint32_t pasid, uint32_t hwpt_id,
612 Error **errp)
613 {
614 HostIOMMUDeviceIOMMUFDClass *hiodic =
615 HOST_IOMMU_DEVICE_IOMMUFD_GET_CLASS(hiodi);
616
617 g_assert(hiodic->attach_hwpt);
618 return hiodic->attach_hwpt(hiodi, pasid, hwpt_id, errp);
619 }
620
621 bool host_iommu_device_iommufd_detach_hwpt(HostIOMMUDeviceIOMMUFD *hiodi,
622 uint32_t pasid, Error **errp)
623 {
624 HostIOMMUDeviceIOMMUFDClass *hiodic =
625 HOST_IOMMU_DEVICE_IOMMUFD_GET_CLASS(hiodi);
626
627 g_assert(hiodic->detach_hwpt);
628 return hiodic->detach_hwpt(hiodi, pasid, errp);
629 }
630
631 static int hiod_iommufd_get_cap(HostIOMMUDevice *hiod, int cap, Error **errp)
632 {
633 HostIOMMUDeviceCaps *caps = &hiod->caps;
634
635 switch (cap) {
636 case HOST_IOMMU_DEVICE_CAP_IOMMU_TYPE:
637 return caps->type;
638 case HOST_IOMMU_DEVICE_CAP_AW_BITS:
639 return vfio_device_get_aw_bits(hiod->agent);
640 default:
641 error_setg(errp, "%s: unsupported capability %x", hiod->name, cap);
642 return -EINVAL;
643 }
644 }
645
646 static bool hiod_iommufd_support_ats(HostIOMMUDevice *hiod)
647 {
648 HostIOMMUDeviceCaps *caps = &hiod->caps;
649
650 return !(caps->hw_caps & IOMMU_HW_CAP_PCI_ATS_NOT_SUPPORTED);
651 }
652
653 static bool hiod_iommufd_get_pasid_info(HostIOMMUDevice *hiod,
654 PasidInfo *pasid_info)
655 {
656 HostIOMMUDeviceCaps *caps = &hiod->caps;
657
658 if (!caps->max_pasid_log2) {
659 return false;
660 }
661
662 g_assert(pasid_info);
663 pasid_info->exec_perm = (caps->hw_caps & IOMMU_HW_CAP_PCI_PASID_EXEC);
664 pasid_info->priv_mod = (caps->hw_caps & IOMMU_HW_CAP_PCI_PASID_PRIV);
665 pasid_info->max_pasid_log2 = caps->max_pasid_log2;
666 return true;
667 }
668
669 static void hiod_iommufd_class_init(ObjectClass *oc, const void *data)
670 {
671 HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_CLASS(oc);
672
673 hiodc->get_cap = hiod_iommufd_get_cap;
674 hiodc->get_pasid_info = hiod_iommufd_get_pasid_info;
675 hiodc->support_ats = hiod_iommufd_support_ats;
676 };
677
678 static const TypeInfo types[] = {
679 {
680 .name = TYPE_IOMMUFD_BACKEND,
681 .parent = TYPE_OBJECT,
682 .instance_size = sizeof(IOMMUFDBackend),
683 .instance_init = iommufd_backend_init,
684 .instance_finalize = iommufd_backend_finalize,
685 .class_size = sizeof(IOMMUFDBackendClass),
686 .class_init = iommufd_backend_class_init,
687 .interfaces = (const InterfaceInfo[]) {
688 { TYPE_USER_CREATABLE },
689 { }
690 }
691 }, {
692 .name = TYPE_HOST_IOMMU_DEVICE_IOMMUFD,
693 .parent = TYPE_HOST_IOMMU_DEVICE,
694 .instance_size = sizeof(HostIOMMUDeviceIOMMUFD),
695 .class_size = sizeof(HostIOMMUDeviceIOMMUFDClass),
696 .class_init = hiod_iommufd_class_init,
697 .abstract = true,
698 }
699 };
700
701 DEFINE_TYPES(types)