From patchwork Tue Mar 16 19:16:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12143575 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-23.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,MENTIONS_GIT_HOSTING,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id F008BC433E9 for ; Tue, 16 Mar 2021 19:19:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BFA7765061 for ; Tue, 16 Mar 2021 19:19:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236614AbhCPTTE (ORCPT ); Tue, 16 Mar 2021 15:19:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58272 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236593AbhCPTSv (ORCPT ); Tue, 16 Mar 2021 15:18:51 -0400 Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B3216C06174A for ; Tue, 16 Mar 2021 12:18:50 -0700 (PDT) Received: by mail-wr1-x42e.google.com with SMTP id o14so7276664wrm.11 for ; Tue, 16 Mar 2021 12:18:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=hbwZsYD4Q8bJKtEB6fxh/bFBCimZQTVQVLBghKe6qbw=; b=Fw/OojIRjcN1Khd18loli2fVEoX2eO8BxWvGUV/w/gINHwluL30dSWAh6qrJt3Sd/N ck2xw1Cjj6Trn4wLHz33y3JImni1Q9YLXkE7sUjgdpk8ct76pvt1ScCTaKNhBzT+gpQ7 yeLtQMMQ6yJAPa3ql2QOtP6O4VNaswVNnUKrG1wr4ovsscKI50j+nTmVWepaiariJtvd gpjHPvJbE/fjajNo9/K5fc6ypFNzPL4XP8X2om88xf094zU8oeD0nTw/JHOiQGj0ffv4 xv7HYx02Khp62T8TfM6qak2p3lLGu4VSeqwTonb1ORY/cHgGrOZokparIbPY79QU0aHx tiXA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=hbwZsYD4Q8bJKtEB6fxh/bFBCimZQTVQVLBghKe6qbw=; b=MTHfLmfrWREOo5qxxuuSWfdosvv3jH6tS/0xFP9afvx4jD4iMHRfwPB21MS58Nk9qd KPLTSMFa8mAlh1GCJZFkR2Oq0CtBPpe78dH6XtvTxT61krZXfB7zyELvYyO5/ygsBWLt I4vBM67FEZlJT1/HrjMDGTjzJA5E0pOH91QZiSAxf9eY04YLkhG2dWV0gEiQPFkeSSBJ MFR/egOVdXqLEaz3v2oXREO3vzGQF/CjOu/jFTuHRPKqzKzs9cz0KxfO9pTJqkwMdNJA tj3JEnr+wYvl1IVjVAzdRCBdrWKSJ/oanePu5RlUvqHhIQk/iMqgBHCiXZlAOYuQ+Gpe H64A== X-Gm-Message-State: AOAM533PYa6mP3S7Fnty1DwTlm0KMqmhcgslHs12XT+l/SAKlzNss0lA QUzfJ9E6deI0QTgndmzhBGbC8w== X-Google-Smtp-Source: ABdhPJymVA+bDQYxQA0i9VexjAgCNYrzeQ8+S/1wLYjWYR0LjtgKCLhBt3in1MQJ33b+oqMmOM4lKA== X-Received: by 2002:a5d:6c69:: with SMTP id r9mr549309wrz.11.1615922329510; Tue, 16 Mar 2021 12:18:49 -0700 (PDT) Received: from localhost.localdomain ([2001:1715:4e26:a7e0:116c:c27a:3e7f:5eaf]) by smtp.gmail.com with ESMTPSA id p12sm22690438wrx.28.2021.03.16.12.18.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 16 Mar 2021 12:18:49 -0700 (PDT) From: Jean-Philippe Brucker To: rjw@rjwysocki.net, lenb@kernel.org, joro@8bytes.org, mst@redhat.com Cc: will@kernel.org, linux-acpi@vger.kernel.org, iommu@lists.linux-foundation.org, virtualization@lists.linux-foundation.org, eric.auger@redhat.com, sebastien.boeuf@intel.com, robin.murphy@arm.com, kevin.tian@intel.com, lorenzo.pieralisi@arm.com, jean-philippe@linaro.org Subject: [PATCH 1/3] ACPICA: iASL: Add definitions for the VIOT table Date: Tue, 16 Mar 2021 20:16:52 +0100 Message-Id: <20210316191652.3401335-2-jean-philippe@linaro.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210316191652.3401335-1-jean-philippe@linaro.org> References: <20210316191652.3401335-1-jean-philippe@linaro.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org Just here for reference, don't merge! The actual commits will be pulled from the next ACPICA release. I squashed the three relevant commits: ACPICA commit fc4e33319c1ee08f20f5c44853dd8426643f6dfd ACPICA commit 2197e354fb5dcafaddd2016ffeb0620e5bc3d5e2 ACPICA commit 856a96fdf4b51b2b8da17529df0255e6f51f1b5b Link: https://github.com/acpica/acpica/commit/fc4e3331 Link: https://github.com/acpica/acpica/commit/2197e354 Link: https://github.com/acpica/acpica/commit/856a96fd Signed-off-by: Bob Moore Signed-off-by: Jean-Philippe Brucker Reviewed-by: Eric Auger --- include/acpi/actbl3.h | 67 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/include/acpi/actbl3.h b/include/acpi/actbl3.h index df5f4b27f3aa..09d15898e9a8 100644 --- a/include/acpi/actbl3.h +++ b/include/acpi/actbl3.h @@ -33,6 +33,7 @@ #define ACPI_SIG_TCPA "TCPA" /* Trusted Computing Platform Alliance table */ #define ACPI_SIG_TPM2 "TPM2" /* Trusted Platform Module 2.0 H/W interface table */ #define ACPI_SIG_UEFI "UEFI" /* Uefi Boot Optimization Table */ +#define ACPI_SIG_VIOT "VIOT" /* Virtual I/O Translation Table */ #define ACPI_SIG_WAET "WAET" /* Windows ACPI Emulated devices Table */ #define ACPI_SIG_WDAT "WDAT" /* Watchdog Action Table */ #define ACPI_SIG_WDDT "WDDT" /* Watchdog Timer Description Table */ @@ -483,6 +484,72 @@ struct acpi_table_uefi { u16 data_offset; /* Offset of remaining data in table */ }; +/******************************************************************************* + * + * VIOT - Virtual I/O Translation Table + * Version 1 + * + ******************************************************************************/ + +struct acpi_table_viot { + struct acpi_table_header header; /* Common ACPI table header */ + u16 node_count; + u16 node_offset; + u8 reserved[8]; +}; + +/* VIOT subtable header */ + +struct acpi_viot_header { + u8 type; + u8 reserved; + u16 length; +}; + +/* Values for Type field above */ + +enum acpi_viot_node_type { + ACPI_VIOT_NODE_PCI_RANGE = 0x01, + ACPI_VIOT_NODE_MMIO = 0x02, + ACPI_VIOT_NODE_VIRTIO_IOMMU_PCI = 0x03, + ACPI_VIOT_NODE_VIRTIO_IOMMU_MMIO = 0x04, + ACPI_VIOT_RESERVED = 0x05 +}; + +/* VIOT subtables */ + +struct acpi_viot_pci_range { + struct acpi_viot_header header; + u32 endpoint_start; + u16 segment_start; + u16 segment_end; + u16 bdf_start; + u16 bdf_end; + u16 output_node; + u8 reserved[6]; +}; + +struct acpi_viot_mmio { + struct acpi_viot_header header; + u32 endpoint; + u64 base_address; + u16 output_node; + u8 reserved[6]; +}; + +struct acpi_viot_virtio_iommu_pci { + struct acpi_viot_header header; + u16 segment; + u16 bdf; + u8 reserved[8]; +}; + +struct acpi_viot_virtio_iommu_mmio { + struct acpi_viot_header header; + u8 reserved[4]; + u64 base_address; +}; + /******************************************************************************* * * WAET - Windows ACPI Emulated devices Table From patchwork Tue Mar 16 19:16:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12143579 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B97B8C43331 for ; Tue, 16 Mar 2021 19:19:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8C4456505E for ; Tue, 16 Mar 2021 19:19:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240336AbhCPTTK (ORCPT ); Tue, 16 Mar 2021 15:19:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58282 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236659AbhCPTTB (ORCPT ); Tue, 16 Mar 2021 15:19:01 -0400 Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3B4C9C06174A for ; Tue, 16 Mar 2021 12:18:54 -0700 (PDT) Received: by mail-wm1-x329.google.com with SMTP id u5-20020a7bcb050000b029010e9316b9d5so6570wmj.2 for ; Tue, 16 Mar 2021 12:18:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=j7fHsbHCsxb9JTpWx9KPVJE5bgbo7bptOcR1bleM6iE=; b=egUR7lNjrnc6tSUv5AVi1bwnO2al9gyberumEkUFAl55V+ZtaZKdmm3o+g8WEaeF4z bAbGT+wKKSB5CkCZy/sX5CPGbUnPHuJ7kh3sAhfh4i5iQZurNSbsQFyq8OBwFxkC9Dpg SLJgMQa74xx+ubdiX5fWRXZcbSPHQhjpvkmlKiGn/+JutxpHueR5CmRRONJ7qezGPXiW TRMBD/7ue0jQu1D53T+1ijyHDNLTCseVOZwpGvyAo2ZLKgw7yK8qDeS71JMK7J0cJHnf pUA8Mt1fGRJzcfDDiszNbZyt7vMut4KkFwBXij6QIZe1sSj4cKCpVAD2o1b8Lq9iElcX HqzQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=j7fHsbHCsxb9JTpWx9KPVJE5bgbo7bptOcR1bleM6iE=; b=GrBbqfm1lEZ5lOw0xWt5g6KiGwONGa59uC7pqTt/tsV51bJvySlU1QQ6MVhi30Dn16 CR0yJRc6wrRFF+JZQVNvTbiybi5IfTNKzuXbh3HG2cQPjGBj6UvPycqALvyge8DUkN0S i8u/JbV3oSRTGCveIZhkRkLJ8S1R0KrvrxyaOEbdW0iw5a+Uy+5SaStO4X7hqmE/YFy7 uj6wP6YjgKbaWu2cHd8gwV+1d+SXp2uBW1dOHurDZx5C6iFr4uRF8pIe8mFtZnM2huip 47JXVtbAaNoloZB9P6ghJcs0cI69Hn/mDe+0Be5TVvZLSzF1d4JSvRvZ38e+Xqk8jBG2 IAYQ== X-Gm-Message-State: AOAM533ja4775ZPIOGZVMzCTcem3NOVchAzv0/kevW/a8K4xgBawsgF9 UqSLOVgmgCyS7EPaalEeYuXHUg== X-Google-Smtp-Source: ABdhPJwG+TD06UtsBeiYcKeleBVDSBMPGPtJVVfUJ8NpTeh5ABWwkdCfMb24hyD733G8Mpn8CzNS9g== X-Received: by 2002:a1c:750d:: with SMTP id o13mr358873wmc.76.1615922332814; Tue, 16 Mar 2021 12:18:52 -0700 (PDT) Received: from localhost.localdomain ([2001:1715:4e26:a7e0:116c:c27a:3e7f:5eaf]) by smtp.gmail.com with ESMTPSA id p12sm22690438wrx.28.2021.03.16.12.18.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 16 Mar 2021 12:18:52 -0700 (PDT) From: Jean-Philippe Brucker To: rjw@rjwysocki.net, lenb@kernel.org, joro@8bytes.org, mst@redhat.com Cc: will@kernel.org, linux-acpi@vger.kernel.org, iommu@lists.linux-foundation.org, virtualization@lists.linux-foundation.org, eric.auger@redhat.com, sebastien.boeuf@intel.com, robin.murphy@arm.com, kevin.tian@intel.com, lorenzo.pieralisi@arm.com, jean-philippe@linaro.org Subject: [PATCH 2/3] ACPI: Add driver for the VIOT table Date: Tue, 16 Mar 2021 20:16:53 +0100 Message-Id: <20210316191652.3401335-3-jean-philippe@linaro.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210316191652.3401335-1-jean-philippe@linaro.org> References: <20210316191652.3401335-1-jean-philippe@linaro.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org The ACPI Virtual I/O Translation Table describes topology of para-virtual platforms. For now it describes the relation between virtio-iommu and the endpoints it manages. Supporting that requires three steps: (1) acpi_viot_init(): parse the VIOT table, build a list of endpoints and vIOMMUs. (2) acpi_viot_set_iommu_ops(): when the vIOMMU driver is loaded and the device probed, register it to the VIOT driver. This step is required because unlike similar drivers, VIOT doesn't create the vIOMMU device. (3) acpi_viot_dma_setup(): when the endpoint is initialized, find the vIOMMU and register the endpoint's DMA ops. If step (3) happens before step (2), it is deferred until the IOMMU is initialized, then retried. Signed-off-by: Jean-Philippe Brucker --- drivers/acpi/Kconfig | 3 + drivers/iommu/Kconfig | 1 + drivers/acpi/Makefile | 2 + include/linux/acpi_viot.h | 26 +++ drivers/acpi/bus.c | 2 + drivers/acpi/scan.c | 6 + drivers/acpi/viot.c | 406 +++++++++++++++++++++++++++++++++++ drivers/iommu/virtio-iommu.c | 3 + MAINTAINERS | 8 + 9 files changed, 457 insertions(+) create mode 100644 include/linux/acpi_viot.h create mode 100644 drivers/acpi/viot.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index eedec61e3476..3758c6940ed7 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -526,6 +526,9 @@ endif source "drivers/acpi/pmic/Kconfig" +config ACPI_VIOT + bool + endif # ACPI config X86_PM_TIMER diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 192ef8f61310..2819b5c8ec30 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -403,6 +403,7 @@ config VIRTIO_IOMMU depends on ARM64 select IOMMU_API select INTERVAL_TREE + select ACPI_VIOT if ACPI help Para-virtualised IOMMU driver with virtio. diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 700b41adf2db..a6e644c48987 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -118,3 +118,5 @@ video-objs += acpi_video.o video_detect.o obj-y += dptf/ obj-$(CONFIG_ARM64) += arm64/ + +obj-$(CONFIG_ACPI_VIOT) += viot.o diff --git a/include/linux/acpi_viot.h b/include/linux/acpi_viot.h new file mode 100644 index 000000000000..1f5837595488 --- /dev/null +++ b/include/linux/acpi_viot.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ACPI_VIOT_H__ +#define __ACPI_VIOT_H__ + +#include + +#ifdef CONFIG_ACPI_VIOT +void __init acpi_viot_init(void); +int acpi_viot_dma_setup(struct device *dev, enum dev_dma_attr attr); +int acpi_viot_set_iommu_ops(struct device *dev, struct iommu_ops *ops); +#else +static inline void acpi_viot_init(void) {} +static inline int acpi_viot_dma_setup(struct device *dev, + enum dev_dma_attr attr) +{ + return 0; +} +static inline int acpi_viot_set_iommu_ops(struct device *dev, + struct iommu_ops *ops) +{ + return -ENODEV; +} +#endif + +#endif /* __ACPI_VIOT_H__ */ diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index be7da23fad76..f9a965c6617e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -27,6 +27,7 @@ #include #endif #include +#include #include #include #include @@ -1338,6 +1339,7 @@ static int __init acpi_init(void) pci_mmcfg_late_init(); acpi_iort_init(); + acpi_viot_init(); acpi_scan_init(); acpi_ec_init(); acpi_debugfs_init(); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index a184529d8fa4..4af01fddd94c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -1506,12 +1507,17 @@ int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr, { const struct iommu_ops *iommu; u64 dma_addr = 0, size = 0; + int ret; if (attr == DEV_DMA_NOT_SUPPORTED) { set_dma_ops(dev, &dma_dummy_ops); return 0; } + ret = acpi_viot_dma_setup(dev, attr); + if (ret) + return ret > 0 ? 0 : ret; + iort_dma_setup(dev, &dma_addr, &size); iommu = iort_iommu_configure_id(dev, input_id); diff --git a/drivers/acpi/viot.c b/drivers/acpi/viot.c new file mode 100644 index 000000000000..57a092e8551b --- /dev/null +++ b/drivers/acpi/viot.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Virtual I/O topology + */ +#define pr_fmt(fmt) "ACPI: VIOT: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +struct viot_dev_id { + unsigned int type; +#define VIOT_DEV_TYPE_PCI 1 +#define VIOT_DEV_TYPE_MMIO 2 + union { + /* PCI endpoint or range */ + struct { + u16 segment_start; + u16 segment_end; + u16 bdf_start; + u16 bdf_end; + }; + /* MMIO region */ + u64 base; + }; +}; + +struct viot_iommu { + unsigned int offset; + struct viot_dev_id dev_id; + struct list_head list; + + struct device *dev; /* transport device */ + struct iommu_ops *ops; + bool static_fwnode; +}; + +struct viot_endpoint { + struct viot_dev_id dev_id; + u32 endpoint_id; + struct list_head list; + struct viot_iommu *viommu; +}; + +static struct acpi_table_viot *viot; +static LIST_HEAD(viot_iommus); +static LIST_HEAD(viot_endpoints); +static DEFINE_MUTEX(viommus_lock); + +/* + * VIOT parsing functions + */ + +static int __init viot_check_bounds(const struct acpi_viot_header *hdr) +{ + struct acpi_viot_header *start, *end, *hdr_end; + + start = ACPI_ADD_PTR(struct acpi_viot_header, viot, + max_t(size_t, sizeof(*viot), viot->node_offset)); + end = ACPI_ADD_PTR(struct acpi_viot_header, viot, viot->header.length); + hdr_end = ACPI_ADD_PTR(struct acpi_viot_header, hdr, sizeof(*hdr)); + + if (hdr < start || hdr_end > end) { + pr_err("Node pointer overflows, bad table\n"); + return -EOVERFLOW; + } + if (hdr->length < sizeof(*hdr)) { + pr_err("Empty node, bad table\n"); + return -EINVAL; + } + return 0; +} + +static struct viot_iommu * __init viot_get_iommu(unsigned int offset) +{ + struct viot_iommu *viommu; + struct acpi_viot_header *hdr = ACPI_ADD_PTR(struct acpi_viot_header, + viot, offset); + union { + struct acpi_viot_virtio_iommu_pci pci; + struct acpi_viot_virtio_iommu_mmio mmio; + } *node = (void *)hdr; + + list_for_each_entry(viommu, &viot_iommus, list) + if (viommu->offset == offset) + return viommu; + + if (viot_check_bounds(hdr)) + return NULL; + + viommu = kzalloc(sizeof(*viommu), GFP_KERNEL); + if (!viommu) + return NULL; + + viommu->offset = offset; + switch (hdr->type) { + case ACPI_VIOT_NODE_VIRTIO_IOMMU_PCI: + if (hdr->length < sizeof(node->pci)) + goto err_free; + + viommu->dev_id.type = VIOT_DEV_TYPE_PCI; + viommu->dev_id.segment_start = node->pci.segment; + viommu->dev_id.segment_end = node->pci.segment; + viommu->dev_id.bdf_start = node->pci.bdf; + viommu->dev_id.bdf_end = node->pci.bdf; + break; + case ACPI_VIOT_NODE_VIRTIO_IOMMU_MMIO: + if (hdr->length < sizeof(node->mmio)) + goto err_free; + + viommu->dev_id.type = VIOT_DEV_TYPE_MMIO; + viommu->dev_id.base = node->mmio.base_address; + break; + default: + kfree(viommu); + return NULL; + } + + list_add(&viommu->list, &viot_iommus); + return viommu; + +err_free: + kfree(viommu); + return NULL; +} + +static int __init viot_parse_node(const struct acpi_viot_header *hdr) +{ + int ret = -EINVAL; + struct viot_endpoint *ep; + union { + struct acpi_viot_mmio mmio; + struct acpi_viot_pci_range pci; + } *node = (void *)hdr; + + if (viot_check_bounds(hdr)) + return -EINVAL; + + if (hdr->type == ACPI_VIOT_NODE_VIRTIO_IOMMU_PCI || + hdr->type == ACPI_VIOT_NODE_VIRTIO_IOMMU_MMIO) + return 0; + + ep = kzalloc(sizeof(*ep), GFP_KERNEL); + if (!ep) + return -ENOMEM; + + switch (hdr->type) { + case ACPI_VIOT_NODE_PCI_RANGE: + if (hdr->length < sizeof(node->pci)) + goto err_free; + + ep->dev_id.type = VIOT_DEV_TYPE_PCI; + ep->dev_id.segment_start = node->pci.segment_start; + ep->dev_id.segment_end = node->pci.segment_end; + ep->dev_id.bdf_start = node->pci.bdf_start; + ep->dev_id.bdf_end = node->pci.bdf_end; + ep->endpoint_id = node->pci.endpoint_start; + ep->viommu = viot_get_iommu(node->pci.output_node); + break; + case ACPI_VIOT_NODE_MMIO: + if (hdr->length < sizeof(node->mmio)) + goto err_free; + + ep->dev_id.type = VIOT_DEV_TYPE_MMIO; + ep->dev_id.base = node->mmio.base_address; + ep->endpoint_id = node->mmio.endpoint; + ep->viommu = viot_get_iommu(node->mmio.output_node); + break; + default: + goto err_free; + } + + if (!ep->viommu) { + ret = -ENODEV; + goto err_free; + } + + list_add(&ep->list, &viot_endpoints); + return 0; + +err_free: + kfree(ep); + return ret; +} + +void __init acpi_viot_init(void) +{ + int i; + acpi_status status; + struct acpi_table_header *hdr; + struct acpi_viot_header *node; + + status = acpi_get_table(ACPI_SIG_VIOT, 0, &hdr); + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) { + const char *msg = acpi_format_exception(status); + + pr_err("Failed to get table, %s\n", msg); + } + return; + } + + viot = (void *)hdr; + + node = ACPI_ADD_PTR(struct acpi_viot_header, viot, viot->node_offset); + for (i = 0; i < viot->node_count; i++) { + if (viot_parse_node(node)) + return; + + node = ACPI_ADD_PTR(struct acpi_viot_header, node, + node->length); + } +} + +/* + * VIOT access functions + */ + +static bool viot_device_match(struct device *dev, struct viot_dev_id *id, + u32 *epid_base) +{ + if (id->type == VIOT_DEV_TYPE_PCI && dev_is_pci(dev)) { + struct pci_dev *pdev = to_pci_dev(dev); + u16 dev_id = pci_dev_id(pdev); + u16 domain_nr = pci_domain_nr(pdev->bus); + + if (domain_nr >= id->segment_start && + domain_nr <= id->segment_end && + dev_id >= id->bdf_start && + dev_id <= id->bdf_end) { + *epid_base = ((u32)(domain_nr - id->segment_start) << 16) + + dev_id - id->bdf_start; + return true; + } + } else if (id->type == VIOT_DEV_TYPE_MMIO && dev_is_platform(dev)) { + struct platform_device *plat_dev = to_platform_device(dev); + struct resource *mem; + + mem = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); + if (mem && mem->start == id->base) { + *epid_base = 0; + return true; + } + } + return false; +} + +static const struct iommu_ops *viot_iommu_setup(struct device *dev) +{ + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + struct viot_iommu *viommu = NULL; + struct viot_endpoint *ep; + u32 epid; + int ret; + + /* Already translated? */ + if (fwspec && fwspec->ops) + return NULL; + + mutex_lock(&viommus_lock); + list_for_each_entry(ep, &viot_endpoints, list) { + if (viot_device_match(dev, &ep->dev_id, &epid)) { + epid += ep->endpoint_id; + viommu = ep->viommu; + break; + } + } + mutex_unlock(&viommus_lock); + if (!viommu) + return NULL; + + /* We're not translating ourself */ + if (viot_device_match(dev, &viommu->dev_id, &epid)) + return NULL; + + /* + * If we found a PCI range managed by the viommu, we're the one that has + * to request ACS. + */ + if (dev_is_pci(dev)) + pci_request_acs(); + + if (!viommu->ops || WARN_ON(!viommu->dev)) + return ERR_PTR(-EPROBE_DEFER); + + ret = iommu_fwspec_init(dev, viommu->dev->fwnode, viommu->ops); + if (ret) + return ERR_PTR(ret); + + iommu_fwspec_add_ids(dev, &epid, 1); + + /* + * If we have reason to believe the IOMMU driver missed the initial + * add_device callback for dev, replay it to get things in order. + */ + if (dev->bus && !device_iommu_mapped(dev)) + iommu_probe_device(dev); + + return viommu->ops; +} + +/** + * acpi_viot_dma_setup - Configure DMA for an endpoint described in VIOT + * @dev: the endpoint + * @attr: coherency property of the endpoint + * + * Setup the DMA and IOMMU ops for an endpoint described by the VIOT table. + * + * Return: + * * 0 - @dev doesn't match any VIOT node + * * 1 - ops for @dev were successfully installed + * * -EPROBE_DEFER - ops for @dev aren't yet available + */ +int acpi_viot_dma_setup(struct device *dev, enum dev_dma_attr attr) +{ + const struct iommu_ops *iommu_ops = viot_iommu_setup(dev); + + if (IS_ERR_OR_NULL(iommu_ops)) { + int ret = PTR_ERR(iommu_ops); + + if (ret == -EPROBE_DEFER || ret == 0) + return ret; + dev_err(dev, "error %d while setting up virt IOMMU\n", ret); + return 0; + } + +#ifdef CONFIG_ARCH_HAS_SETUP_DMA_OPS + arch_setup_dma_ops(dev, 0, ~0ULL, iommu_ops, attr == DEV_DMA_COHERENT); +#else + iommu_setup_dma_ops(dev, 0, ~0ULL); +#endif + return 1; +} + +static int viot_set_iommu_ops(struct viot_iommu *viommu, struct device *dev, + struct iommu_ops *ops) +{ + /* + * The IOMMU subsystem relies on fwnode for identifying the IOMMU that + * manages an endpoint. Create one if necessary, because PCI devices + * don't always get a fwnode. + */ + if (!dev->fwnode) { + dev->fwnode = acpi_alloc_fwnode_static(); + if (!dev->fwnode) + return -ENOMEM; + viommu->static_fwnode = true; + } + viommu->dev = dev; + viommu->ops = ops; + + return 0; +} + +static int viot_clear_iommu_ops(struct viot_iommu *viommu) +{ + struct device *dev = viommu->dev; + + viommu->dev = NULL; + viommu->ops = NULL; + if (dev && viommu->static_fwnode) { + acpi_free_fwnode_static(dev->fwnode); + dev->fwnode = NULL; + viommu->static_fwnode = false; + } + return 0; +} + +/** + * acpi_viot_set_iommu_ops - Set the IOMMU ops of a virtual IOMMU device + * @dev: the IOMMU device (transport) + * @ops: the new IOMMU ops or NULL + * + * Once the IOMMU driver is loaded and the device probed, associate the IOMMU + * ops to its VIOT node. Before disabling the IOMMU device, dissociate the ops + * from the VIOT node. + * + * Return 0 on success, an error otherwise + */ +int acpi_viot_set_iommu_ops(struct device *dev, struct iommu_ops *ops) +{ + int ret = -EINVAL; + struct viot_iommu *viommu; + + mutex_lock(&viommus_lock); + list_for_each_entry(viommu, &viot_iommus, list) { + u32 epid; + + if (!viot_device_match(dev, &viommu->dev_id, &epid)) + continue; + + if (ops) + ret = viot_set_iommu_ops(viommu, dev, ops); + else + ret = viot_clear_iommu_ops(viommu); + break; + } + mutex_unlock(&viommus_lock); + return ret; +} +EXPORT_SYMBOL_GPL(acpi_viot_set_iommu_ops); diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c index 2bfdd5734844..054d8405a2db 100644 --- a/drivers/iommu/virtio-iommu.c +++ b/drivers/iommu/virtio-iommu.c @@ -7,6 +7,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -1065,6 +1066,7 @@ static int viommu_probe(struct virtio_device *vdev) if (ret) goto err_free_vqs; + acpi_viot_set_iommu_ops(parent_dev, &viommu_ops); iommu_device_set_ops(&viommu->iommu, &viommu_ops); iommu_device_set_fwnode(&viommu->iommu, parent_dev->fwnode); @@ -1111,6 +1113,7 @@ static void viommu_remove(struct virtio_device *vdev) { struct viommu_dev *viommu = vdev->priv; + acpi_viot_set_iommu_ops(vdev->dev.parent, NULL); iommu_device_sysfs_remove(&viommu->iommu); iommu_device_unregister(&viommu->iommu); diff --git a/MAINTAINERS b/MAINTAINERS index aa84121c5611..799c020fca87 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -432,6 +432,14 @@ W: https://01.org/linux-acpi B: https://bugzilla.kernel.org F: drivers/acpi/acpi_video.c +ACPI VIOT DRIVER +M: Jean-Philippe Brucker +L: linux-acpi@vger.kernel.org +L: iommu@lists.linux-foundation.org +S: Maintained +F: drivers/acpi/viot.c +F: include/linux/acpi_viot.h + ACPI WMI DRIVER L: platform-driver-x86@vger.kernel.org S: Orphan From patchwork Tue Mar 16 19:16:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12143577 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A204CC4332D for ; Tue, 16 Mar 2021 19:19:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 772B665061 for ; Tue, 16 Mar 2021 19:19:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236607AbhCPTTH (ORCPT ); Tue, 16 Mar 2021 15:19:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58296 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236657AbhCPTS5 (ORCPT ); Tue, 16 Mar 2021 15:18:57 -0400 Received: from mail-wm1-x330.google.com (mail-wm1-x330.google.com [IPv6:2a00:1450:4864:20::330]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F195AC061756 for ; Tue, 16 Mar 2021 12:18:56 -0700 (PDT) Received: by mail-wm1-x330.google.com with SMTP id d191so158722wmd.2 for ; Tue, 16 Mar 2021 12:18:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=t5nF/sXmMcwkw/ixJn1wgxDWeReE+TQab+n6/wXS1U0=; b=oaMK9nYnTAZy6ym3HYBmsqWuTVnMYutZ/U+My/vKZTXWBNQa3kUp/CciNiv42oBJY0 sz/3nwTqT77ad0BK6/aNftjxGpd+x5BnQ08enNqXaOj6sYNydPxIwAdUYSmBMMdHknaJ 3lTnRODxiPkto6n3IX3caXRjSWSazO2ZyYuFTmm2Z8jGfNqMpX2X4pzRd4+2GzuiV3at le5h53LvdTcx4ZjtnQNcJlulO36rZ/2LAjIsCcNWdtBEiPFwHj30zOJ9APBb0G7Xy2g9 V3t8uyrFrYicbRxD3jwfVfuIs4jbNaFzW7lHPH02gBcOy9b2DQZMVtEbZKfz0FBvkYvI 3hlA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=t5nF/sXmMcwkw/ixJn1wgxDWeReE+TQab+n6/wXS1U0=; b=rjKC1oqr8H+q5KOC7aV0TTYTUETGmAV9pekMZU6T/LrLTIzJfUhsj/BeabYqiDIPNw ltufcFZSbjw5BBtiPuVv30eYeAKteffDSwBor+YDtoV5y+Vv+x10uel9da9OhqaBq3O0 0Yo5jAwXCBPUTrC6/d9Bi9zVY9GmLZf3fYhl/urYnpYjKpb1oNMgO2gAJYsDUWq5GDxC edb465Bx/RWSFnSapiKzZK11n3Fb+xsUw4Pxkbm3l6niZSN2ee3V2ar268XDDbJQBsR/ fl/xelnrAblMbhDEkIsVfI9dPebXxo0HolYW+eWGXLsaw6QWdp3a6KBDoGdOBRzE2qSk DYaA== X-Gm-Message-State: AOAM530ndk6p5pMsW/UnKrByBjsqlFC8bgXPClmNx/K2IGJ96/VN0H/b 9i6JzFoZONrpj0TQz8r5dl6m8Q== X-Google-Smtp-Source: ABdhPJwrnc/yoYhLqyVbf/ctwV9VfvVZmgZLZUJT5ACgoolGvh6o3uWH6IcGtVOst4Ix4VaYd5EPVQ== X-Received: by 2002:a05:600c:198c:: with SMTP id t12mr308127wmq.183.1615922335734; Tue, 16 Mar 2021 12:18:55 -0700 (PDT) Received: from localhost.localdomain ([2001:1715:4e26:a7e0:116c:c27a:3e7f:5eaf]) by smtp.gmail.com with ESMTPSA id p12sm22690438wrx.28.2021.03.16.12.18.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 16 Mar 2021 12:18:55 -0700 (PDT) From: Jean-Philippe Brucker To: rjw@rjwysocki.net, lenb@kernel.org, joro@8bytes.org, mst@redhat.com Cc: will@kernel.org, linux-acpi@vger.kernel.org, iommu@lists.linux-foundation.org, virtualization@lists.linux-foundation.org, eric.auger@redhat.com, sebastien.boeuf@intel.com, robin.murphy@arm.com, kevin.tian@intel.com, lorenzo.pieralisi@arm.com, jean-philippe@linaro.org Subject: [PATCH 3/3] iommu/virtio: Enable x86 support Date: Tue, 16 Mar 2021 20:16:54 +0100 Message-Id: <20210316191652.3401335-4-jean-philippe@linaro.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210316191652.3401335-1-jean-philippe@linaro.org> References: <20210316191652.3401335-1-jean-philippe@linaro.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org With the VIOT support in place, x86 platforms can now use the virtio-iommu. The arm64 Kconfig selects IOMMU_DMA, while x86 IOMMU drivers select it themselves. Signed-off-by: Jean-Philippe Brucker Acked-by: Joerg Roedel Acked-by: Michael S. Tsirkin --- drivers/iommu/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 2819b5c8ec30..ccca83ef2f06 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -400,8 +400,9 @@ config HYPERV_IOMMU config VIRTIO_IOMMU tristate "Virtio IOMMU driver" depends on VIRTIO - depends on ARM64 + depends on (ARM64 || X86) select IOMMU_API + select IOMMU_DMA if X86 select INTERVAL_TREE select ACPI_VIOT if ACPI help