Signed-off-by: Zhenzhong Duan <zhenzhong.d...@intel.com>
---
hw/vfio/iommufd.c | 89 +++++++++++++++++++++++++++++++++++++----------
1 file changed, 70 insertions(+), 19 deletions(-)
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index aee64d63f3..c1daaf1c39 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -217,38 +217,91 @@ static VFIOIOASHwpt
*vfio_container_get_hwpt(VFIOIOMMUFDContainer *container,
static void vfio_container_put_hwpt(IOMMUFDBackend *be, VFIOIOASHwpt *hwpt)
{
QLIST_REMOVE(hwpt, next);
+ iommufd_backend_free_id(be->fd, hwpt->hwpt_id);
g_free(hwpt);
}
-static int vfio_device_attach_container(VFIODevice *vbasedev,
- VFIOIOMMUFDContainer *container,
- Error **errp)
+static int __vfio_device_attach_hwpt(VFIODevice *vbasedev, uint32_t hwpt_id,
+ Error **errp)
{
- int ret, iommufd = vbasedev->iommufd->fd;
- VFIOIOASHwpt *hwpt;
struct vfio_device_attach_iommufd_pt attach_data = {
.argsz = sizeof(attach_data),
.flags = 0,
- .pt_id = container->ioas_id,
+ .pt_id = hwpt_id,
};
+ int ret;
- /* Attach device to an ioas within iommufd */
ret = ioctl(vbasedev->fd, VFIO_DEVICE_ATTACH_IOMMUFD_PT, &attach_data);
if (ret) {
error_setg_errno(errp, errno,
- "[iommufd=%d] error attach %s (%d) to ioasid=%d",
- container->be->fd, vbasedev->name, vbasedev->fd,
- attach_data.pt_id);
+ "[iommufd=%d] error attach %s (%d) to hwpt_id=%d",
+ vbasedev->iommufd->fd, vbasedev->name, vbasedev->fd,
+ hwpt_id);
+ }
+ return ret;
+}
+
+static int __vfio_device_detach_hwpt(VFIODevice *vbasedev, Error **errp)
+{
+ struct vfio_device_detach_iommufd_pt detach_data = {
+ .argsz = sizeof(detach_data),
+ .flags = 0,
+ };
+ int ret;
+
+ ret = ioctl(vbasedev->fd, VFIO_DEVICE_DETACH_IOMMUFD_PT, &detach_data);
+ if (ret) {
+ error_setg_errno(errp, errno, "detach %s from ioas failed",
+ vbasedev->name);
+ }
+ return ret;
+}
+
+static int vfio_device_attach_container(VFIODevice *vbasedev,
+ VFIOIOMMUFDContainer *container,
+ Error **errp)
+{
+ int ret, iommufd = vbasedev->iommufd->fd;
+ VFIOIOASHwpt *hwpt;
+ uint32_t hwpt_id;
+ Error *err = NULL;
+
+ /* try to attach to an existing hwpt in this container */
+ QLIST_FOREACH(hwpt, &container->hwpt_list, next) {
+ ret = __vfio_device_attach_hwpt(vbasedev, hwpt->hwpt_id, &err);
+ if (ret) {
+ const char *msg = error_get_pretty(err);
+
+ trace_vfio_iommufd_fail_attach_existing_hwpt(msg);
+ error_free(err);
+ err = NULL;
+ } else {
+ goto found_hwpt;
+ }
+ }
+
+ ret = iommufd_backend_alloc_hwpt(iommufd, vbasedev->devid,
+ container->ioas_id, &hwpt_id);
+
+ if (ret) {
+ error_setg_errno(errp, errno, "error alloc shadow hwpt");
return ret;
+ }
+ /* Attach device to an hwpt within iommufd */
+ ret = __vfio_device_attach_hwpt(vbasedev, hwpt_id, errp);
+ if (ret) {
+ iommufd_backend_free_id(iommufd, hwpt_id);
+ return ret;
}
- hwpt = vfio_container_get_hwpt(container, attach_data.pt_id);
+ hwpt = vfio_container_get_hwpt(container, hwpt_id);
+found_hwpt:
QLIST_INSERT_HEAD(&hwpt->device_list, vbasedev, next);
vbasedev->hwpt = hwpt;
trace_vfio_iommufd_attach_device(iommufd, vbasedev->name, vbasedev->fd,
- container->ioas_id, attach_data.pt_id);
+ container->ioas_id, hwpt->hwpt_id);
return ret;
}
@@ -256,14 +309,12 @@ static void vfio_device_detach_container(VFIODevice *vbasedev,
VFIOIOMMUFDContainer *container)
{
VFIOIOASHwpt *hwpt = vbasedev->hwpt;
- struct vfio_device_attach_iommufd_pt detach_data = {
- .argsz = sizeof(detach_data),
- .flags = 0,
- };
+ Error *err = NULL;
+ int ret;
- if (ioctl(vbasedev->fd, VFIO_DEVICE_DETACH_IOMMUFD_PT, &detach_data)) {
- error_report("detach %s from ioas id=%d failed: %m", vbasedev->name,
- container->ioas_id);
+ ret = __vfio_device_detach_hwpt(vbasedev, &err);
+ if (ret) {
+ error_report_err(err);
}
QLIST_REMOVE(vbasedev, next);