From patchwork Fri Jan 18 08:55:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Auger X-Patchwork-Id: 1027182 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43gvtj2T5dz9sCs for ; Fri, 18 Jan 2019 19:56:13 +1100 (AEDT) Received: from localhost ([127.0.0.1]:34631 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gkPwh-00022C-C6 for incoming@patchwork.ozlabs.org; Fri, 18 Jan 2019 03:56:11 -0500 Received: from eggs.gnu.org ([209.51.188.92]:59226) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gkPwN-00020s-3e for qemu-devel@nongnu.org; Fri, 18 Jan 2019 03:55:52 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gkPwM-0008FJ-0p for qemu-devel@nongnu.org; Fri, 18 Jan 2019 03:55:51 -0500 Received: from mx1.redhat.com ([209.132.183.28]:6908) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gkPwL-0008ET-Ol for qemu-devel@nongnu.org; Fri, 18 Jan 2019 03:55:49 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6CD6FC0D18AA; Fri, 18 Jan 2019 08:55:48 +0000 (UTC) Received: from laptop.redhat.com (ovpn-116-183.ams2.redhat.com [10.36.116.183]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1CDDA18036; Fri, 18 Jan 2019 08:55:31 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, alex.williamson@redhat.com Date: Fri, 18 Jan 2019 09:55:25 +0100 Message-Id: <20190118085525.24542-1-eric.auger@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Fri, 18 Jan 2019 08:55:48 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3] hw/vfio/common: Refactor container initialization X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: aik@ozlabs.ru, groug@kaod.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" In vfio_connect_container() the code that selects the iommu type can benefit from helpers such as vfio_iommu_get_type() and vfio_init_container(). As a result we end up with a switch/case on the iommu type that makes the code a little bit more readable and ready for addition of new iommu types. Also ioctl's get called once per iommu_type. Signed-off-by: Eric Auger Reviewed-by: Greg Kurz --- v2 -> v3: - fix ret/errno v1 -> v2: - handle SPAPR case, s/ret/errno in error error_setg_errno, fix ret value when vfio_iommu_get_type fails - removed Greg's R-b v1: - originally submitted in [RFC v2 00/28] vSMMUv3/pSMMUv3 2 stage VFIO integration --- hw/vfio/common.c | 112 +++++++++++++++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 37 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 4262b80c44..2e6d5a84b0 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1036,12 +1036,65 @@ static void vfio_put_address_space(VFIOAddressSpace *space) } } +/* + * vfio_iommu_get_type - selects the richest iommu_type (v2 first) + */ +static int vfio_iommu_get_type(VFIOContainer *container, + Error **errp) +{ + int fd = container->fd; + + if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU)) { + return VFIO_TYPE1v2_IOMMU; + } else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) { + return VFIO_TYPE1_IOMMU; + } else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_v2_IOMMU)) { + return VFIO_SPAPR_TCE_v2_IOMMU; + } else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_IOMMU)) { + return VFIO_SPAPR_TCE_IOMMU; + } else { + error_setg(errp, "No available IOMMU models"); + return -EINVAL; + } +} + +static int vfio_init_container(VFIOContainer *container, int group_fd, + int iommu_type, Error **errp) +{ + int ret; + + ret = ioctl(group_fd, VFIO_GROUP_SET_CONTAINER, &container->fd); + if (ret) { + error_setg_errno(errp, errno, "failed to set group container"); + return -errno; + } + + ret = ioctl(container->fd, VFIO_SET_IOMMU, iommu_type); + if (ret && iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { + /* + * On sPAPR, despite the IOMMU subdriver always advertises v1 and v2, + * the running platform may not support v2 and there is no way to + * guess it until an IOMMU group gets added to the container. So in + * case it fails with v2, try v1 as a fallback + */ + iommu_type = VFIO_SPAPR_TCE_IOMMU; + ret = ioctl(container->fd, VFIO_SET_IOMMU, iommu_type); + } + if (ret) { + error_setg_errno(errp, errno, "failed to set iommu for container"); + return -errno; + } + container->iommu_type = iommu_type; + return ret; +} + static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, Error **errp) { VFIOContainer *container; int ret, fd; VFIOAddressSpace *space; + int iommu_type; space = vfio_get_address_space(as); @@ -1101,23 +1154,21 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, container->fd = fd; QLIST_INIT(&container->giommu_list); QLIST_INIT(&container->hostwin_list); - if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU) || - ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU)) { - bool v2 = !!ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU); + + iommu_type = vfio_iommu_get_type(container, errp); + if (iommu_type < 0) { + ret = -EINVAL; + goto free_container_exit; + } + + switch (iommu_type) { + case VFIO_TYPE1v2_IOMMU: + case VFIO_TYPE1_IOMMU: + { struct vfio_iommu_type1_info info; - ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd); + ret = vfio_init_container(container, group->fd, iommu_type, errp); if (ret) { - error_setg_errno(errp, errno, "failed to set group container"); - ret = -errno; - goto free_container_exit; - } - - container->iommu_type = v2 ? VFIO_TYPE1v2_IOMMU : VFIO_TYPE1_IOMMU; - ret = ioctl(fd, VFIO_SET_IOMMU, container->iommu_type); - if (ret) { - error_setg_errno(errp, errno, "failed to set iommu for container"); - ret = -errno; goto free_container_exit; } @@ -1137,31 +1188,21 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, } vfio_host_win_add(container, 0, (hwaddr)-1, info.iova_pgsizes); container->pgsizes = info.iova_pgsizes; - } else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_IOMMU) || - ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_v2_IOMMU)) { + break; + } + case VFIO_SPAPR_TCE_v2_IOMMU: + case VFIO_SPAPR_TCE_IOMMU: + { struct vfio_iommu_spapr_tce_info info; - bool v2 = !!ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_v2_IOMMU); + bool v2; - ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd); + ret = vfio_init_container(container, group->fd, iommu_type, errp); if (ret) { - error_setg_errno(errp, errno, "failed to set group container"); - ret = -errno; - goto free_container_exit; - } - container->iommu_type = - v2 ? VFIO_SPAPR_TCE_v2_IOMMU : VFIO_SPAPR_TCE_IOMMU; - ret = ioctl(fd, VFIO_SET_IOMMU, container->iommu_type); - if (ret) { - container->iommu_type = VFIO_SPAPR_TCE_IOMMU; - v2 = false; - ret = ioctl(fd, VFIO_SET_IOMMU, container->iommu_type); - } - if (ret) { - error_setg_errno(errp, errno, "failed to set iommu for container"); - ret = -errno; goto free_container_exit; } + v2 = container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU; + /* * The host kernel code implementing VFIO_IOMMU_DISABLE is called * when container fd is closed so we do not call it explicitly @@ -1222,10 +1263,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, info.dma32_window_size - 1, 0x1000); } - } else { - error_setg(errp, "No available IOMMU models"); - ret = -EINVAL; - goto free_container_exit; + } } vfio_kvm_device_add_group(group);