From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523518870873921.5100960001927; Thu, 12 Apr 2018 00:41:10 -0700 (PDT) Received: from localhost ([::1]:44063 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wqy-0008U9-8G for importer@patchew.org; Thu, 12 Apr 2018 03:41:08 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49183) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6WoX-0006Sv-Nl for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6WoV-000343-W9 for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:37 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34332 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6WoP-0002xp-En; Thu, 12 Apr 2018 03:38:29 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8A68D4075A67; Thu, 12 Apr 2018 07:38:25 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id E6227215CDC6; Thu, 12 Apr 2018 07:38:22 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:37:52 +0200 Message-Id: <1523518688-26674-2-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Thu, 12 Apr 2018 07:38:25 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Thu, 12 Apr 2018 07:38:25 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 01/17] hw/arm/smmu-common: smmu base device and datatypes 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The patch introduces the smmu base device and class for the ARM smmu. Devices for specific versions will be derived from this base device. We also introduce some important datatypes. Signed-off-by: Eric Auger Signed-off-by: Prem Mallappa Reviewed-by: Peter Maydell --- v10 -> v11: - remove hash tables for configs and iotlb which will be introduced later on v9 -> v10: - invoke the parent_realize - use device_class_set_parent_realize - use "" to include headers - fix indent in SMMUTransCfg - rename smmu_as_by_busptr into smmu_pcibus_by_busptr and smmu_as_by_bus_num into smmu_pcibus_by_bus_num - mrtypename becomes const - add Peter's R-b v8 -> v9: - remove page walk callback type from this patch (vhost related) - add a new hash table for caching configuration data - add reset function - add asid v7 -> v8: - add bus_num property - add primary-bus property - add realize and remove instance_init - rename TYPE and related macros to match naming convention using for GIC - add SMMUPageTableWalkEventInfo - tt[2] in translation config v3 -> v4: - added smmu_find_as_from_bus_num - SMMU_PCI_BUS_MAX and SMMU_PCI_DEVFN_MAX in smmu-common header - new fields in SMMUState: - iommu_ops, smmu_as_by_busptr, smmu_as_by_bus_num - add aa64[] field in SMMUTransCfg v3: - moved the base code in a separate patch to ease the review. - clearer separation between base class and smmuv3 class - translate_* only implemented as class methods Conflicts: default-configs/aarch64-softmmu.mak Conflicts: hw/arm/Makefile.objs --- default-configs/aarch64-softmmu.mak | 1 + hw/arm/Makefile.objs | 1 + hw/arm/smmu-common.c | 81 +++++++++++++++++++++++ include/hw/arm/smmu-common.h | 124 ++++++++++++++++++++++++++++++++= ++++ 4 files changed, 207 insertions(+) create mode 100644 hw/arm/smmu-common.c create mode 100644 include/hw/arm/smmu-common.h diff --git a/default-configs/aarch64-softmmu.mak b/default-configs/aarch64-= softmmu.mak index 9ddccf8..6f790f0 100644 --- a/default-configs/aarch64-softmmu.mak +++ b/default-configs/aarch64-softmmu.mak @@ -8,3 +8,4 @@ CONFIG_DDC=3Dy CONFIG_DPCD=3Dy CONFIG_XLNX_ZYNQMP=3Dy CONFIG_XLNX_ZYNQMP_ARM=3Dy +CONFIG_ARM_SMMUV3=3Dy diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 2885e3e..558436f 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -35,3 +35,4 @@ obj-$(CONFIG_MPS2) +=3D mps2-tz.o obj-$(CONFIG_MSF2) +=3D msf2-soc.o msf2-som.o obj-$(CONFIG_IOTKIT) +=3D iotkit.o obj-$(CONFIG_FSL_IMX7) +=3D fsl-imx7.o mcimx7d-sabre.o +obj-$(CONFIG_ARM_SMMUV3) +=3D smmu-common.o diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c new file mode 100644 index 0000000..e086ff5 --- /dev/null +++ b/hw/arm/smmu-common.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014-2016 Broadcom Corporation + * Copyright (c) 2017 Red Hat, Inc. + * Written by Prem Mallappa, Eric Auger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Author: Prem Mallappa + * + */ + +#include "qemu/osdep.h" +#include "sysemu/sysemu.h" +#include "exec/address-spaces.h" +#include "trace.h" +#include "exec/target_page.h" +#include "qom/cpu.h" +#include "hw/qdev-properties.h" +#include "qapi/error.h" + +#include "qemu/error-report.h" +#include "hw/arm/smmu-common.h" + +static void smmu_base_realize(DeviceState *dev, Error **errp) +{ + SMMUBaseClass *sbc =3D ARM_SMMU_GET_CLASS(dev); + Error *local_err =3D NULL; + + sbc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } +} + +static void smmu_base_reset(DeviceState *dev) +{ + /* will be filled later on */ +} + +static Property smmu_dev_properties[] =3D { + DEFINE_PROP_UINT8("bus_num", SMMUState, bus_num, 0), + DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus, "PCI", PCIBus = *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void smmu_base_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + SMMUBaseClass *sbc =3D ARM_SMMU_CLASS(klass); + + dc->props =3D smmu_dev_properties; + device_class_set_parent_realize(dc, smmu_base_realize, + &sbc->parent_realize); + dc->reset =3D smmu_base_reset; +} + +static const TypeInfo smmu_base_info =3D { + .name =3D TYPE_ARM_SMMU, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(SMMUState), + .class_data =3D NULL, + .class_size =3D sizeof(SMMUBaseClass), + .class_init =3D smmu_base_class_init, + .abstract =3D true, +}; + +static void smmu_base_register_types(void) +{ + type_register_static(&smmu_base_info); +} + +type_init(smmu_base_register_types) + diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h new file mode 100644 index 0000000..5910692 --- /dev/null +++ b/include/hw/arm/smmu-common.h @@ -0,0 +1,124 @@ +/* + * ARM SMMU Support + * + * Copyright (C) 2015-2016 Broadcom Corporation + * Copyright (c) 2017 Red Hat, Inc. + * Written by Prem Mallappa, Eric Auger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef HW_ARM_SMMU_COMMON_H +#define HW_ARM_SMMU_COMMON_H + +#include "hw/sysbus.h" +#include "hw/pci/pci.h" + +#define SMMU_PCI_BUS_MAX 256 +#define SMMU_PCI_DEVFN_MAX 256 + +#define SMMU_MAX_VA_BITS 48 + +/* + * Page table walk error types + */ +typedef enum { + SMMU_PTW_ERR_NONE, + SMMU_PTW_ERR_WALK_EABT, /* Translation walk external abort */ + SMMU_PTW_ERR_TRANSLATION, /* Translation fault */ + SMMU_PTW_ERR_ADDR_SIZE, /* Address Size fault */ + SMMU_PTW_ERR_ACCESS, /* Access fault */ + SMMU_PTW_ERR_PERMISSION, /* Permission fault */ +} SMMUPTWEventType; + +typedef struct SMMUPTWEventInfo { + SMMUPTWEventType type; + dma_addr_t addr; /* fetched address that induced an abort, if any */ +} SMMUPTWEventInfo; + +typedef struct SMMUTransTableInfo { + bool disabled; /* is the translation table disabled? */ + uint64_t ttb; /* TT base address */ + uint8_t tsz; /* input range, ie. 2^(64 -tsz)*/ + uint8_t granule_sz; /* granule page shift */ + uint8_t initial_level; /* initial lookup level */ +} SMMUTransTableInfo; + +/* + * Generic structure populated by derived SMMU devices + * after decoding the configuration information and used as + * input to the page table walk + */ +typedef struct SMMUTransCfg { + int stage; /* translation stage */ + bool aa64; /* arch64 or aarch32 translation table */ + bool disabled; /* smmu is disabled */ + bool bypassed; /* translation is bypassed */ + bool aborted; /* translation is aborted */ + uint64_t ttb; /* TT base address */ + uint8_t oas; /* output address width */ + uint8_t tbi; /* Top Byte Ignore */ + uint16_t asid; + SMMUTransTableInfo tt[2]; +} SMMUTransCfg; + +typedef struct SMMUDevice { + void *smmu; + PCIBus *bus; + int devfn; + IOMMUMemoryRegion iommu; + AddressSpace as; +} SMMUDevice; + +typedef struct SMMUNotifierNode { + SMMUDevice *sdev; + QLIST_ENTRY(SMMUNotifierNode) next; +} SMMUNotifierNode; + +typedef struct SMMUPciBus { + PCIBus *bus; + SMMUDevice *pbdev[0]; /* Parent array is sparse, so dynamically allo= c */ +} SMMUPciBus; + +typedef struct SMMUState { + /* */ + SysBusDevice dev; + const char *mrtypename; + MemoryRegion iomem; + + GHashTable *smmu_pcibus_by_busptr; + GHashTable *configs; /* cache for configuration data */ + GHashTable *iotlb; + SMMUPciBus *smmu_pcibus_by_bus_num[SMMU_PCI_BUS_MAX]; + PCIBus *pci_bus; + QLIST_HEAD(, SMMUNotifierNode) notifiers_list; + uint8_t bus_num; + PCIBus *primary_bus; +} SMMUState; + +typedef struct { + /* */ + SysBusDeviceClass parent_class; + + /*< public >*/ + + DeviceRealize parent_realize; + +} SMMUBaseClass; + +#define TYPE_ARM_SMMU "arm-smmu" +#define ARM_SMMU(obj) OBJECT_CHECK(SMMUState, (obj), TYPE_ARM_SMMU) +#define ARM_SMMU_CLASS(klass) \ + OBJECT_CLASS_CHECK(SMMUBaseClass, (klass), TYPE_ARM_SMMU) +#define ARM_SMMU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SMMUBaseClass, (obj), TYPE_ARM_SMMU) + +#endif /* HW_ARM_SMMU_COMMON */ --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523518870972668.4553381213339; Thu, 12 Apr 2018 00:41:10 -0700 (PDT) Received: from localhost ([::1]:44062 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wqu-0008QW-RT for importer@patchew.org; Thu, 12 Apr 2018 03:41:04 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49167) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6WoX-0006SP-4p for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6WoV-00033x-W2 for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:37 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:35922 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6WoP-0002ys-Et; Thu, 12 Apr 2018 03:38:29 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6B3CEEBFE5; Thu, 12 Apr 2018 07:38:28 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id CE960215CDC6; Thu, 12 Apr 2018 07:38:25 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:37:53 +0200 Message-Id: <1523518688-26674-3-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Thu, 12 Apr 2018 07:38:28 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Thu, 12 Apr 2018 07:38:28 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 02/17] hw/arm/smmu-common: IOMMU memory region and address space setup 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" We set up the infrastructure to enumerate all the PCI devices attached to the SMMU and create an associated IOMMU memory region and address space. Those info are stored in SMMUDevice objects. The devices are grouped according to the PCIBus they belong to. A hash table indexed by the PCIBus pointer is used. Also an array indexed by the bus number allows to find the list of SMMUDevices. Signed-off-by: Eric Auger Signed-off-by: Prem Mallappa Reviewed-by: Peter Maydell --- v9 -> v10: - comment functions added to the header - g_free(name) - renamed smmu_find_as_from_bus_num into smmu_find_smmu_pcibus - add a comment about lazy init in smmu_find_smmu_pcibus - add a trace event when creating the smmu iommu mr v8 -> v9: - fix key value for lookup v7 -> v8: - introduce SMMU_MAX_VA_BITS - use PCI bus handle as a key - do not clear s->smmu_as_by_bus_num - use g_new0 instead of g_malloc0 - use primary_bus field --- hw/arm/smmu-common.c | 69 ++++++++++++++++++++++++++++++++++++++++= ++++ hw/arm/trace-events | 3 ++ include/hw/arm/smmu-common.h | 8 +++++ 3 files changed, 80 insertions(+) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index e086ff5..9a966bb 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -28,8 +28,69 @@ #include "qemu/error-report.h" #include "hw/arm/smmu-common.h" =20 +/** + * The bus number is used for lookup when SID based invalidatation occurs. + * In that case we lazily populate the SMMUPciBus array from the bus hash + * table. At the time the SMMUPciBus is created (smmu_find_add_as), the bus + * numbers may not be always initialized yet. + */ +SMMUPciBus *smmu_find_smmu_pcibus(SMMUState *s, uint8_t bus_num) +{ + SMMUPciBus *smmu_pci_bus =3D s->smmu_pcibus_by_bus_num[bus_num]; + + if (!smmu_pci_bus) { + GHashTableIter iter; + + g_hash_table_iter_init(&iter, s->smmu_pcibus_by_busptr); + while (g_hash_table_iter_next(&iter, NULL, (void **)&smmu_pci_bus)= ) { + if (pci_bus_num(smmu_pci_bus->bus) =3D=3D bus_num) { + s->smmu_pcibus_by_bus_num[bus_num] =3D smmu_pci_bus; + return smmu_pci_bus; + } + } + } + return smmu_pci_bus; +} + +static AddressSpace *smmu_find_add_as(PCIBus *bus, void *opaque, int devfn) +{ + SMMUState *s =3D opaque; + SMMUPciBus *sbus =3D g_hash_table_lookup(s->smmu_pcibus_by_busptr, bus= ); + SMMUDevice *sdev; + + if (!sbus) { + sbus =3D g_malloc0(sizeof(SMMUPciBus) + + sizeof(SMMUDevice *) * SMMU_PCI_DEVFN_MAX); + sbus->bus =3D bus; + g_hash_table_insert(s->smmu_pcibus_by_busptr, bus, sbus); + } + + sdev =3D sbus->pbdev[devfn]; + if (!sdev) { + char *name =3D g_strdup_printf("%s-%d-%d", + s->mrtypename, + pci_bus_num(bus), devfn); + sdev =3D sbus->pbdev[devfn] =3D g_new0(SMMUDevice, 1); + + sdev->smmu =3D s; + sdev->bus =3D bus; + sdev->devfn =3D devfn; + + memory_region_init_iommu(&sdev->iommu, sizeof(sdev->iommu), + s->mrtypename, + OBJECT(s), name, 1ULL << SMMU_MAX_VA_BITS= ); + address_space_init(&sdev->as, + MEMORY_REGION(&sdev->iommu), name); + trace_smmu_add_mr(name); + g_free(name); + } + + return &sdev->as; +} + static void smmu_base_realize(DeviceState *dev, Error **errp) { + SMMUState *s =3D ARM_SMMU(dev); SMMUBaseClass *sbc =3D ARM_SMMU_GET_CLASS(dev); Error *local_err =3D NULL; =20 @@ -38,6 +99,14 @@ static void smmu_base_realize(DeviceState *dev, Error **= errp) error_propagate(errp, local_err); return; } + + s->smmu_pcibus_by_busptr =3D g_hash_table_new(NULL, NULL); + + if (s->primary_bus) { + pci_setup_iommu(s->primary_bus, smmu_find_add_as, s); + } else { + error_setg(errp, "SMMU is not attached to any PCI bus!"); + } } =20 static void smmu_base_reset(DeviceState *dev) diff --git a/hw/arm/trace-events b/hw/arm/trace-events index 193063e..8e8b53c 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -2,3 +2,6 @@ =20 # hw/arm/virt-acpi-build.c virt_acpi_setup(void) "No fw cfg or ACPI disabled. Bailing out." + +# hw/arm/smmu-common.c +smmu_add_mr(const char *name) "%s" \ No newline at end of file diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index 5910692..76cf4aa 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -121,4 +121,12 @@ typedef struct { #define ARM_SMMU_GET_CLASS(obj) \ OBJECT_GET_CLASS(SMMUBaseClass, (obj), TYPE_ARM_SMMU) =20 +/* Return the SMMUPciBus handle associated to a PCI bus number */ +SMMUPciBus *smmu_find_smmu_pcibus(SMMUState *s, uint8_t bus_num); + +/* Return the stream ID of an SMMU device */ +static inline uint16_t smmu_get_sid(SMMUDevice *sdev) +{ + return ((pci_bus_num(sdev->bus) & 0xff) << 8) | sdev->devfn; +} #endif /* HW_ARM_SMMU_COMMON */ --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523518870934405.99052845797166; Thu, 12 Apr 2018 00:41:10 -0700 (PDT) Received: from localhost ([::1]:44061 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wqq-0008Lm-8w for importer@patchew.org; Thu, 12 Apr 2018 03:41:00 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49227) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6WoZ-0006Uy-Io for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6WoX-00034u-6c for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:39 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:56770 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6WoS-00030n-0I; Thu, 12 Apr 2018 03:38:32 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 708258DC3E; Thu, 12 Apr 2018 07:38:31 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id AEE39215CDC6; Thu, 12 Apr 2018 07:38:28 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:37:54 +0200 Message-Id: <1523518688-26674-4-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Thu, 12 Apr 2018 07:38:31 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Thu, 12 Apr 2018 07:38:31 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 03/17] hw/arm/smmu-common: VMSAv8-64 page table walk 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This patch implements the page table walk for VMSAv8-64. Signed-off-by: Eric Auger Signed-off-by: Prem Mallappa Reviewed-by: Peter Maydell --- v9 -> v10: - Add 64b single-copy atomicity comment related to PTE fetch - remove checks in get_block_pte_address and use formulae to compute block address offset - remove check_perm - fix select_tt - in trace-events use PRIx64 instead of 0x%lx - commented the fact we cannot discriminate between user and priviledged transactions v8 -> v9: - remove guest error log on PTE fetch fault - rename trace functions - fix smmu_page_walk_level_res_invalid_pte last arg - fix PTE_ADDRESS - turn functions into macros - make sure to return the actual pte access permission into tlbe->perm - change proto of smmu_ptw* v7 -> v8: - rework get_pte - use LOG_LEVEL_ERROR - remove error checking in get_block_pte_address - page table walk simplified (no VFIO replay anymore) - handle PTW error events - use dma_memory_read v6 -> v7: - fix wrong error handling in walk_page_table - check perm in smmu_translate v5 -> v6: - use IOMMUMemoryRegion - remove initial_lookup_level() - fix block replay v4 -> v5: - add initial level in translation config - implement block pte - rename must_translate into nofail - introduce call_entry_hook - small changes to dynamic traces - smmu_page_walk code moved from smmuv3.c to this file - remove smmu_translate* v3 -> v4: - reworked page table walk to prepare for VFIO integration (capability to scan a range of IOVA). Same function is used for translate for a single iova. This is largely inspired from intel_iommu.c - as the translate function was not straightforward to me, I tried to stick more closely to the VMSA spec. - remove support of nested stage (kernel driver does not support it anyway) - use error_report and trace events - add aa64[] field in SMMUTransCfg --- hw/arm/smmu-common.c | 209 +++++++++++++++++++++++++++++++++++++++= ++++ hw/arm/smmu-internal.h | 102 +++++++++++++++++++++ hw/arm/trace-events | 9 +- include/hw/arm/smmu-common.h | 14 +++ 4 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 hw/arm/smmu-internal.h diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 9a966bb..6a58948 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -27,6 +27,215 @@ =20 #include "qemu/error-report.h" #include "hw/arm/smmu-common.h" +#include "smmu-internal.h" + +/* VMSAv8-64 Translation */ + +/** + * get_pte - Get the content of a page table entry located t + * @base_addr[@index] + */ +static int get_pte(dma_addr_t baseaddr, uint32_t index, uint64_t *pte, + SMMUPTWEventInfo *info) +{ + int ret; + dma_addr_t addr =3D baseaddr + index * sizeof(*pte); + + /* TODO: guarantee 64-bit single-copy atomicity */ + ret =3D dma_memory_read(&address_space_memory, addr, + (uint8_t *)pte, sizeof(*pte)); + + if (ret !=3D MEMTX_OK) { + info->type =3D SMMU_PTW_ERR_WALK_EABT; + info->addr =3D addr; + return -EINVAL; + } + trace_smmu_get_pte(baseaddr, index, addr, *pte); + return 0; +} + +/* VMSAv8-64 Translation Table Format Descriptor Decoding */ + +/** + * get_page_pte_address - returns the L3 descriptor output address, + * ie. the page frame + * ARM ARM spec: Figure D4-17 VMSAv8-64 level 3 descriptor format + */ +static inline hwaddr get_page_pte_address(uint64_t pte, int granule_sz) +{ + return PTE_ADDRESS(pte, granule_sz); +} + +/** + * get_table_pte_address - return table descriptor output address, + * ie. address of next level table + * ARM ARM Figure D4-16 VMSAv8-64 level0, level1, and level 2 descriptor f= ormats + */ +static inline hwaddr get_table_pte_address(uint64_t pte, int granule_sz) +{ + return PTE_ADDRESS(pte, granule_sz); +} + +/** + * get_block_pte_address - return block descriptor output address and bloc= k size + * ARM ARM Figure D4-16 VMSAv8-64 level0, level1, and level 2 descriptor f= ormats + */ +static inline hwaddr get_block_pte_address(uint64_t pte, int level, + int granule_sz, uint64_t *bsz) +{ + int n =3D (granule_sz - 3) * (4 - level) + 3; + + *bsz =3D 1 << n; + return PTE_ADDRESS(pte, n); +} + +SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t iova) +{ + bool tbi =3D extract64(iova, 55, 1) ? TBI1(cfg->tbi) : TBI0(cfg->tbi); + uint8_t tbi_byte =3D tbi * 8; + + if (!extract64(iova, 64 - cfg->tt[0].tsz, cfg->tt[0].tsz - tbi_byte)) { + return &cfg->tt[0]; + } else if (!extract64(iova, 64 - cfg->tt[1].tsz, + cfg->tt[1].tsz - tbi_byte)) { + return &cfg->tt[1]; + } + return NULL; +} + +/** + * smmu_ptw_64 - VMSAv8-64 Walk of the page tables for a given IOVA + * @cfg: translation config + * @iova: iova to translate + * @perm: access type + * @tlbe: IOMMUTLBEntry (out) + * @info: handle to an error info + * + * Return 0 on success, < 0 on error. In case of error, @info is filled + * and tlbe->perm is set to IOMMU_NONE. + * Upon success, @tlbe is filled with translated_addr and entry + * permission rights. + */ +static int smmu_ptw_64(SMMUTransCfg *cfg, + dma_addr_t iova, IOMMUAccessFlags perm, + IOMMUTLBEntry *tlbe, SMMUPTWEventInfo *info) +{ + dma_addr_t baseaddr; + int stage =3D cfg->stage; + SMMUTransTableInfo *tt =3D select_tt(cfg, iova); + uint8_t level; + uint8_t granule_sz; + + if (!tt || tt->disabled) { + info->type =3D SMMU_PTW_ERR_TRANSLATION; + goto error; + } + + level =3D tt->initial_level; + granule_sz =3D tt->granule_sz; + baseaddr =3D tt->ttb; + + tlbe->iova =3D iova; + tlbe->addr_mask =3D (1 << granule_sz) - 1; + + while (level <=3D 3) { + uint64_t subpage_size =3D 1ULL << level_shift(level, granule_sz); + uint64_t mask =3D subpage_size - 1; + uint32_t offset =3D iova_level_offset(iova, level, granule_sz); + uint64_t pte; + dma_addr_t pte_addr =3D baseaddr + offset * sizeof(pte); + uint8_t ap; + + if (get_pte(baseaddr, offset, &pte, info)) { + goto error; + } + trace_smmu_ptw_level(level, iova, subpage_size, + baseaddr, offset, pte); + + if (is_invalid_pte(pte) || is_reserved_pte(pte, level)) { + trace_smmu_ptw_invalid_pte(stage, level, baseaddr, + pte_addr, offset, pte); + info->type =3D SMMU_PTW_ERR_TRANSLATION; + goto error; + } + + if (is_page_pte(pte, level)) { + uint64_t gpa =3D get_page_pte_address(pte, granule_sz); + + ap =3D PTE_AP(pte); + if (is_permission_fault(ap, perm)) { + info->type =3D SMMU_PTW_ERR_PERMISSION; + goto error; + } + + tlbe->translated_addr =3D gpa + (iova & mask); + tlbe->perm =3D PTE_AP_TO_PERM(ap); + trace_smmu_ptw_page_pte(stage, level, iova, + baseaddr, pte_addr, pte, gpa); + return 0; + } + if (is_block_pte(pte, level)) { + uint64_t block_size; + hwaddr gpa =3D get_block_pte_address(pte, level, granule_sz, + &block_size); + + ap =3D PTE_AP(pte); + if (is_permission_fault(ap, perm)) { + info->type =3D SMMU_PTW_ERR_PERMISSION; + goto error; + } + + trace_smmu_ptw_block_pte(stage, level, baseaddr, + pte_addr, pte, iova, gpa, + block_size >> 20); + + tlbe->translated_addr =3D gpa + (iova & mask); + tlbe->perm =3D PTE_AP_TO_PERM(ap); + return 0; + } + + /* table pte */ + ap =3D PTE_APTABLE(pte); + + if (is_permission_fault(ap, perm)) { + info->type =3D SMMU_PTW_ERR_PERMISSION; + goto error; + } + baseaddr =3D get_table_pte_address(pte, granule_sz); + level++; + } + + info->type =3D SMMU_PTW_ERR_TRANSLATION; + +error: + tlbe->perm =3D IOMMU_NONE; + return -EINVAL; +} + +/** + * smmu_ptw - Walk the page tables for an IOVA, according to @cfg + * + * @cfg: translation configuration + * @iova: iova to translate + * @perm: tentative access type + * @tlbe: returned entry + * @info: ptw event handle + * + * return 0 on success + */ +inline int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags p= erm, + IOMMUTLBEntry *tlbe, SMMUPTWEventInfo *info) +{ + if (!cfg->aa64) { + /* + * This code path is not entered as we check this while decoding + * the configuration data in the derived SMMU model. + */ + assert(0); + } + + return smmu_ptw_64(cfg, iova, perm, tlbe, info); +} =20 /** * The bus number is used for lookup when SID based invalidatation occurs. diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h new file mode 100644 index 0000000..3a3a9f8 --- /dev/null +++ b/hw/arm/smmu-internal.h @@ -0,0 +1,102 @@ +/* + * ARM SMMU support - Internal API + * + * Copyright (c) 2017 Red Hat, Inc. + * Copyright (C) 2014-2016 Broadcom Corporation + * Written by Prem Mallappa, Eric Auger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef HW_ARM_SMMU_INTERNAL_H +#define HW_ARM_SMMU_INTERNAL_H + +#define TBI0(tbi) ((tbi) & 0x1) +#define TBI1(tbi) ((tbi) & 0x2 >> 1) + +/* PTE Manipulation */ + +#define ARM_LPAE_PTE_TYPE_SHIFT 0 +#define ARM_LPAE_PTE_TYPE_MASK 0x3 + +#define ARM_LPAE_PTE_TYPE_BLOCK 1 +#define ARM_LPAE_PTE_TYPE_TABLE 3 + +#define ARM_LPAE_L3_PTE_TYPE_RESERVED 1 +#define ARM_LPAE_L3_PTE_TYPE_PAGE 3 + +#define ARM_LPAE_PTE_VALID (1 << 0) + +#define PTE_ADDRESS(pte, shift) \ + (extract64(pte, shift, 47 - shift + 1) << shift) + +#define is_invalid_pte(pte) (!(pte & ARM_LPAE_PTE_VALID)) + +#define is_reserved_pte(pte, level) \ + ((level =3D=3D 3) && = \ + ((pte & ARM_LPAE_PTE_TYPE_MASK) =3D=3D ARM_LPAE_L3_PTE_TYPE_RESERVED)) + +#define is_block_pte(pte, level) \ + ((level < 3) && \ + ((pte & ARM_LPAE_PTE_TYPE_MASK) =3D=3D ARM_LPAE_PTE_TYPE_BLOCK)) + +#define is_table_pte(pte, level) \ + ((level < 3) && \ + ((pte & ARM_LPAE_PTE_TYPE_MASK) =3D=3D ARM_LPAE_PTE_TYPE_TABLE)) + +#define is_page_pte(pte, level) \ + ((level =3D=3D 3) && = \ + ((pte & ARM_LPAE_PTE_TYPE_MASK) =3D=3D ARM_LPAE_L3_PTE_TYPE_PAGE)) + +/* access permissions */ + +#define PTE_AP(pte) \ + (extract64(pte, 6, 2)) + +#define PTE_APTABLE(pte) \ + (extract64(pte, 61, 2)) + +/* + * TODO: At the moment all transactions are considered as priviledged (EL1) + * as IOMMU translation callback does not pass user/priv attributes. + */ +#define is_permission_fault(ap, perm) \ + (((perm) & IOMMU_WO) && ((ap) & 0x2)) + +#define PTE_AP_TO_PERM(ap) \ + (IOMMU_ACCESS_FLAG(true, !((ap) & 0x2))) + +/* Level Indexing */ + +static inline int level_shift(int level, int granule_sz) +{ + return granule_sz + (3 - level) * (granule_sz - 3); +} + +static inline uint64_t level_page_mask(int level, int granule_sz) +{ + return ~(MAKE_64BIT_MASK(0, level_shift(level, granule_sz))); +} + +/** + * TODO: handle the case where the level resolves less than + * granule_sz -3 IA bits. + */ +static inline +uint64_t iova_level_offset(uint64_t iova, int level, int granule_sz) +{ + return (iova >> level_shift(level, granule_sz)) & + MAKE_64BIT_MASK(0, granule_sz - 3); +} + +#endif diff --git a/hw/arm/trace-events b/hw/arm/trace-events index 8e8b53c..524964a 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -4,4 +4,11 @@ virt_acpi_setup(void) "No fw cfg or ACPI disabled. Bailing out." =20 # hw/arm/smmu-common.c -smmu_add_mr(const char *name) "%s" \ No newline at end of file +smmu_add_mr(const char *name) "%s" +smmu_page_walk(int stage, uint64_t baseaddr, int first_level, uint64_t sta= rt, uint64_t end) "stage=3D%d, baseaddr=3D0x%"PRIx64", first level=3D%d, st= art=3D0x%"PRIx64", end=3D0x%"PRIx64 +smmu_lookup_table(int level, uint64_t baseaddr, int granule_sz, uint64_t s= tart, uint64_t end, int flags, uint64_t subpage_size) "level=3D%d baseaddr= =3D0x%"PRIx64" granule=3D%d, start=3D0x%"PRIx64" end=3D0x%"PRIx64" flags=3D= %d subpage_size=3D0x%"PRIx64 +smmu_ptw_level(int level, uint64_t iova, size_t subpage_size, uint64_t bas= eaddr, uint32_t offset, uint64_t pte) "level=3D%d iova=3D0x%"PRIx64" subpag= e_sz=3D0x%lx baseaddr=3D0x%"PRIx64" offset=3D%d =3D> pte=3D0x%"PRIx64 +smmu_ptw_invalid_pte(int stage, int level, uint64_t baseaddr, uint64_t pte= addr, uint32_t offset, uint64_t pte) "stage=3D%d level=3D%d base@=3D0x%"PRI= x64" pte@=3D0x%"PRIx64" offset=3D%d pte=3D0x%"PRIx64 +smmu_ptw_page_pte(int stage, int level, uint64_t iova, uint64_t baseaddr,= uint64_t pteaddr, uint64_t pte, uint64_t address) "stage=3D%d level=3D%d i= ova=3D0x%"PRIx64" base@=3D0x%"PRIx64" pte@=3D0x%"PRIx64" pte=3D0x%"PRIx64" = page address =3D 0x%"PRIx64 +smmu_ptw_block_pte(int stage, int level, uint64_t baseaddr, uint64_t ptead= dr, uint64_t pte, uint64_t iova, uint64_t gpa, int bsize_mb) "stage=3D%d le= vel=3D%d base@=3D0x%"PRIx64" pte@=3D0x%"PRIx64" pte=3D0x%"PRIx64" iova=3D0x= %"PRIx64" block address =3D 0x%"PRIx64" block size =3D %d MiB" +smmu_get_pte(uint64_t baseaddr, int index, uint64_t pteaddr, uint64_t pte)= "baseaddr=3D0x%"PRIx64" index=3D0x%x, pteaddr=3D0x%"PRIx64", pte=3D0x%"PRI= x64 diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index 76cf4aa..4ccd131 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -129,4 +129,18 @@ static inline uint16_t smmu_get_sid(SMMUDevice *sdev) { return ((pci_bus_num(sdev->bus) & 0xff) << 8) | sdev->devfn; } + +/** + * smmu_ptw - Perform the page table walk for a given iova / access flags + * pair, according to @cfg translation config + */ +int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm, + IOMMUTLBEntry *tlbe, SMMUPTWEventInfo *info); + +/** + * select_tt - compute which translation table shall be used according + * the input iova and tranlsation config and return the TT specific info + */ +SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t iova); + #endif /* HW_ARM_SMMU_COMMON */ --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523519077667192.12683874344123; Thu, 12 Apr 2018 00:44:37 -0700 (PDT) Received: from localhost ([::1]:44098 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6WuK-0003PO-MF for importer@patchew.org; Thu, 12 Apr 2018 03:44:36 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49292) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wof-0006bB-RL for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:48 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6Wob-00039D-8z for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:45 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:35444 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6WoV-00032v-3d; Thu, 12 Apr 2018 03:38:35 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8AA4781A88A0; Thu, 12 Apr 2018 07:38:34 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id B4A59215CDC6; Thu, 12 Apr 2018 07:38:31 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:37:55 +0200 Message-Id: <1523518688-26674-5-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 12 Apr 2018 07:38:34 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 12 Apr 2018 07:38:34 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 04/17] hw/arm/smmuv3: Skeleton 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Prem Mallappa This patch implements a skeleton for the smmuv3 device. Datatypes and register definitions are introduced. The MMIO region, the interrupts and the queue are initialized. Only the MMIO read operation is implemented here. Signed-off-by: Prem Mallappa Signed-off-by: Eric Auger Reviewed-by: Peter Maydell --- v10 -> v11: - remove irq_ctrl_ack and return irq_ctrl on A_IRQ_CTRL_ACK read v9 -> v10: - s/hwaddr/uint64_t in trace-events - add comments - s->mrtypename =3D TYPE_SMMUV3_IOMMU_MEMORY_REGION - removed iidr and idr from VMState - use VMSTATE_STRUCT for the queues - use qemu_log_mask(LOG_UNIMP,*) for unimplemented regs - added SMMU_CMDQS, SMMU_EVENTQS - use ops with attributes - split readl/readll - put id_regs in an array - removed smmu_read64 - removed SMMU_FEATURE_2LVL_STE and NB_REGS - RAZ when read access at unexpected address v8 -> v9: - add #include "qemu/log.h" - add parent_reset v7 -> v8: - remove __smmu_data structs - revisit struct SMMUQueue - do not advertise stage 2 support anymore - use the register definition API and get rid of REG array - get read of queue structs v6 -> v7: - split into several patches v5 -> v6: - Use IOMMUMemoryregion - regs become uint32_t and fix 64b MMIO access (.impl) - trace_smmuv3_write/read_mmio take the size param v4 -> v5: - change smmuv3_translate proto (IOMMUAccessFlags flag) - has_stagex replaced by is_ste_stagex - smmu_cfg_populate removed - added smmuv3_decode_config and reworked error management - remwork the naming of IOMMU mrs - fix SMMU_CMDQ_CONS offset v3 -> v4 - smmu_irq_update - fix hash key allocation - set smmu_iommu_ops - set SMMU_REG_CR0, - smmuv3_translate: ret.perm not set in bypass mode - use trace events - renamed STM2U64 into L1STD_L2PTR and STMSPAN into L1STD_SPAN - rework smmu_find_ste - fix tg2granule in TT0/0b10 corresponds to 16kB v2 -> v3: - move creation of include/hw/arm/smmuv3.h to this patch to fix compil issue - compilation allowed - fix sbus allocation in smmu_init_pci_iommu - restructure code into headers - misc cleanups Conflicts: hw/arm/Makefile.objs --- hw/arm/Makefile.objs | 2 +- hw/arm/smmuv3-internal.h | 167 ++++++++++++++++++++++ hw/arm/smmuv3.c | 365 +++++++++++++++++++++++++++++++++++++++++++= ++++ hw/arm/trace-events | 3 + include/hw/arm/smmuv3.h | 87 +++++++++++ 5 files changed, 623 insertions(+), 1 deletion(-) create mode 100644 hw/arm/smmuv3-internal.h create mode 100644 hw/arm/smmuv3.c create mode 100644 include/hw/arm/smmuv3.h diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 558436f..d51fcec 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -35,4 +35,4 @@ obj-$(CONFIG_MPS2) +=3D mps2-tz.o obj-$(CONFIG_MSF2) +=3D msf2-soc.o msf2-som.o obj-$(CONFIG_IOTKIT) +=3D iotkit.o obj-$(CONFIG_FSL_IMX7) +=3D fsl-imx7.o mcimx7d-sabre.o -obj-$(CONFIG_ARM_SMMUV3) +=3D smmu-common.o +obj-$(CONFIG_ARM_SMMUV3) +=3D smmu-common.o smmuv3.o diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h new file mode 100644 index 0000000..a6461fe --- /dev/null +++ b/hw/arm/smmuv3-internal.h @@ -0,0 +1,167 @@ +/* + * ARM SMMUv3 support - Internal API + * + * Copyright (C) 2014-2016 Broadcom Corporation + * Copyright (c) 2017 Red Hat, Inc. + * Written by Prem Mallappa, Eric Auger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef HW_ARM_SMMU_V3_INTERNAL_H +#define HW_ARM_SMMU_V3_INTERNAL_H + +#include "qemu/log.h" +#include "trace.h" +#include "qemu/error-report.h" +#include "hw/arm/smmu-common.h" + +/* MMIO Registers */ + +REG32(IDR0, 0x0) + FIELD(IDR0, S1P, 1 , 1) + FIELD(IDR0, TTF, 2 , 2) + FIELD(IDR0, COHACC, 4 , 1) + FIELD(IDR0, ASID16, 12, 1) + FIELD(IDR0, TTENDIAN, 21, 2) + FIELD(IDR0, STALL_MODEL, 24, 2) + FIELD(IDR0, TERM_MODEL, 26, 1) + FIELD(IDR0, STLEVEL, 27, 2) + +REG32(IDR1, 0x4) + FIELD(IDR1, SIDSIZE, 0 , 6) + FIELD(IDR1, EVENTQS, 16, 5) + FIELD(IDR1, CMDQS, 21, 5) + +#define SMMU_IDR1_SIDSIZE 16 +#define SMMU_CMDQS 19 +#define SMMU_EVENTQS 19 + +REG32(IDR2, 0x8) +REG32(IDR3, 0xc) +REG32(IDR4, 0x10) +REG32(IDR5, 0x14) + FIELD(IDR5, OAS, 0, 3); + FIELD(IDR5, GRAN4K, 4, 1); + FIELD(IDR5, GRAN16K, 5, 1); + FIELD(IDR5, GRAN64K, 6, 1); + +#define SMMU_IDR5_OAS 4 + +REG32(IIDR, 0x1c) +REG32(CR0, 0x20) + FIELD(CR0, SMMU_ENABLE, 0, 1) + FIELD(CR0, EVENTQEN, 2, 1) + FIELD(CR0, CMDQEN, 3, 1) + +REG32(CR0ACK, 0x24) +REG32(CR1, 0x28) +REG32(CR2, 0x2c) +REG32(STATUSR, 0x40) +REG32(IRQ_CTRL, 0x50) + FIELD(IRQ_CTRL, GERROR_IRQEN, 0, 1) + FIELD(IRQ_CTRL, PRI_IRQEN, 1, 1) + FIELD(IRQ_CTRL, EVENTQ_IRQEN, 2, 1) + +REG32(IRQ_CTRL_ACK, 0x54) +REG32(GERROR, 0x60) + FIELD(GERROR, CMDQ_ERR, 0, 1) + FIELD(GERROR, EVENTQ_ABT_ERR, 2, 1) + FIELD(GERROR, PRIQ_ABT_ERR, 3, 1) + FIELD(GERROR, MSI_CMDQ_ABT_ERR, 4, 1) + FIELD(GERROR, MSI_EVENTQ_ABT_ERR, 5, 1) + FIELD(GERROR, MSI_PRIQ_ABT_ERR, 6, 1) + FIELD(GERROR, MSI_GERROR_ABT_ERR, 7, 1) + FIELD(GERROR, MSI_SFM_ERR, 8, 1) + +REG32(GERRORN, 0x64) + +#define A_GERROR_IRQ_CFG0 0x68 /* 64b */ +REG32(GERROR_IRQ_CFG1, 0x70) +REG32(GERROR_IRQ_CFG2, 0x74) + +#define A_STRTAB_BASE 0x80 /* 64b */ + +#define SMMU_BASE_ADDR_MASK 0xffffffffffe0 + +REG32(STRTAB_BASE_CFG, 0x88) + FIELD(STRTAB_BASE_CFG, FMT, 16, 2) + FIELD(STRTAB_BASE_CFG, SPLIT, 6 , 5) + FIELD(STRTAB_BASE_CFG, LOG2SIZE, 0 , 6) + +#define A_CMDQ_BASE 0x90 /* 64b */ +REG32(CMDQ_PROD, 0x98) +REG32(CMDQ_CONS, 0x9c) + FIELD(CMDQ_CONS, ERR, 24, 7) + +#define A_EVENTQ_BASE 0xa0 /* 64b */ +REG32(EVENTQ_PROD, 0xa8) +REG32(EVENTQ_CONS, 0xac) + +#define A_EVENTQ_IRQ_CFG0 0xb0 /* 64b */ +REG32(EVENTQ_IRQ_CFG1, 0xb8) +REG32(EVENTQ_IRQ_CFG2, 0xbc) + +#define A_IDREGS 0xfd0 + +static inline int smmu_enabled(SMMUv3State *s) +{ + return FIELD_EX32(s->cr[0], CR0, SMMU_ENABLE); +} + +/* Command Queue Entry */ +typedef struct Cmd { + uint32_t word[4]; +} Cmd; + +/* Event Queue Entry */ +typedef struct Evt { + uint32_t word[8]; +} Evt; + +/** + * smmu_read64 - 64-bit register read utility function supporting + * aligned 32-bit word access to both 32-bit halves and aligned 64-bit + * access. + * + * @r: register address + * @offset: byte offset if 32-bit access + * @size: read byte size + */ +static inline uint64_t smmu_read64(uint64_t r, unsigned offset, + unsigned size) +{ + if (size =3D=3D 8) { + return r; + } + + /* 32 bit access */ + assert(!offset || offset =3D=3D 4); + + return extract64(r, offset << 3, 32); +} + +static inline uint32_t smmuv3_idreg(int regoffset) +{ + /* + * Return the value of the Primecell/Corelink ID registers at the + * specified offset from the first ID register. + * These value indicate an ARM implementation of MMU600 p1 + */ + static const uint8_t smmuv3_ids[] =3D { + 0x4, 0, 0, 0, 0x84, 0xB4, 0xF0, 0x10, 0x0D, 0xF0, 0x05, 0xB1 + }; + return smmuv3_ids[regoffset / 4]; +} + +#endif diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c new file mode 100644 index 0000000..dba4656 --- /dev/null +++ b/hw/arm/smmuv3.c @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2014-2016 Broadcom Corporation + * Copyright (c) 2017 Red Hat, Inc. + * Written by Prem Mallappa, Eric Auger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "qemu/osdep.h" +#include "hw/boards.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" +#include "hw/qdev-core.h" +#include "hw/pci/pci.h" +#include "exec/address-spaces.h" +#include "trace.h" +#include "qemu/error-report.h" +#include "qapi/error.h" + +#include "hw/arm/smmuv3.h" +#include "smmuv3-internal.h" + +static void smmuv3_init_regs(SMMUv3State *s) +{ + /** + * IDR0: stage1 only, AArch64 only, coherent access, 16b ASID, + * multi-level stream table + */ + s->idr[0] =3D FIELD_DP32(s->idr[0], IDR0, S1P, 1); /* stage 1 supporte= d */ + s->idr[0] =3D FIELD_DP32(s->idr[0], IDR0, TTF, 2); /* AArch64 PTW only= */ + s->idr[0] =3D FIELD_DP32(s->idr[0], IDR0, COHACC, 1); /* IO coherent */ + s->idr[0] =3D FIELD_DP32(s->idr[0], IDR0, ASID16, 1); /* 16-bit ASID */ + s->idr[0] =3D FIELD_DP32(s->idr[0], IDR0, TTENDIAN, 2); /* little endi= an */ + s->idr[0] =3D FIELD_DP32(s->idr[0], IDR0, STALL_MODEL, 1); /* No stall= */ + /* terminated transaction will always be aborted/error returned */ + s->idr[0] =3D FIELD_DP32(s->idr[0], IDR0, TERM_MODEL, 1); + /* 2-level stream table supported */ + s->idr[0] =3D FIELD_DP32(s->idr[0], IDR0, STLEVEL, 1); + + s->idr[1] =3D FIELD_DP32(s->idr[1], IDR1, SIDSIZE, SMMU_IDR1_SIDSIZE); + s->idr[1] =3D FIELD_DP32(s->idr[1], IDR1, EVENTQS, SMMU_EVENTQS); + s->idr[1] =3D FIELD_DP32(s->idr[1], IDR1, CMDQS, SMMU_CMDQS); + + /* 4K and 64K granule support */ + s->idr[5] =3D FIELD_DP32(s->idr[5], IDR5, GRAN4K, 1); + s->idr[5] =3D FIELD_DP32(s->idr[5], IDR5, GRAN64K, 1); + s->idr[5] =3D FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS); /* 44 b= its */ + + s->cmdq.base =3D deposit64(s->cmdq.base, 0, 5, SMMU_CMDQS); + s->cmdq.prod =3D 0; + s->cmdq.cons =3D 0; + s->cmdq.entry_size =3D sizeof(struct Cmd); + s->eventq.base =3D deposit64(s->eventq.base, 0, 5, SMMU_EVENTQS); + s->eventq.prod =3D 0; + s->eventq.cons =3D 0; + s->eventq.entry_size =3D sizeof(struct Evt); + + s->features =3D 0; + s->sid_split =3D 0; +} + +static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t d= ata, + unsigned size, MemTxAttrs attrs) +{ + /* not yet implemented */ + return MEMTX_ERROR; +} + +static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset, + uint64_t *data, MemTxAttrs attrs) +{ + switch (offset) { + case A_GERROR_IRQ_CFG0: + *data =3D s->gerror_irq_cfg0; + return MEMTX_OK; + case A_STRTAB_BASE: + *data =3D s->strtab_base; + return MEMTX_OK; + case A_CMDQ_BASE: + *data =3D s->cmdq.base; + return MEMTX_OK; + case A_EVENTQ_BASE: + *data =3D s->eventq.base; + return MEMTX_OK; + default: + *data =3D 0; + qemu_log_mask(LOG_UNIMP, + "%s Unexpected 64-bit access to 0x%"PRIx64" (RAZ)\n", + __func__, offset); + return MEMTX_OK; + } +} + +static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset, + uint64_t *data, MemTxAttrs attrs) +{ + switch (offset) { + case A_IDREGS ... A_IDREGS + 0x1f: + *data =3D smmuv3_idreg(offset - A_IDREGS); + return MEMTX_OK; + case A_IDR0 ... A_IDR5: + *data =3D s->idr[(offset - A_IDR0) / 4]; + return MEMTX_OK; + case A_IIDR: + *data =3D s->iidr; + return MEMTX_OK; + case A_CR0: + *data =3D s->cr[0]; + return MEMTX_OK; + case A_CR0ACK: + *data =3D s->cr0ack; + return MEMTX_OK; + case A_CR1: + *data =3D s->cr[1]; + return MEMTX_OK; + case A_CR2: + *data =3D s->cr[2]; + return MEMTX_OK; + case A_STATUSR: + *data =3D s->statusr; + return MEMTX_OK; + case A_IRQ_CTRL: + case A_IRQ_CTRL_ACK: + *data =3D s->irq_ctrl; + return MEMTX_OK; + case A_GERROR: + *data =3D s->gerror; + return MEMTX_OK; + case A_GERRORN: + *data =3D s->gerrorn; + return MEMTX_OK; + case A_GERROR_IRQ_CFG0: /* 64b */ + *data =3D extract64(s->gerror_irq_cfg0, 0, 32); + return MEMTX_OK; + case A_GERROR_IRQ_CFG0 + 4: + *data =3D extract64(s->gerror_irq_cfg0, 32, 32); + return MEMTX_OK; + case A_GERROR_IRQ_CFG1: + *data =3D s->gerror_irq_cfg1; + return MEMTX_OK; + case A_GERROR_IRQ_CFG2: + *data =3D s->gerror_irq_cfg2; + return MEMTX_OK; + case A_STRTAB_BASE: /* 64b */ + *data =3D extract64(s->strtab_base, 0, 32); + return MEMTX_OK; + case A_STRTAB_BASE + 4: /* 64b */ + *data =3D extract64(s->strtab_base, 32, 32); + return MEMTX_OK; + case A_STRTAB_BASE_CFG: + *data =3D s->strtab_base_cfg; + return MEMTX_OK; + case A_CMDQ_BASE: /* 64b */ + *data =3D extract64(s->cmdq.base, 0, 32); + return MEMTX_OK; + case A_CMDQ_BASE + 4: + *data =3D extract64(s->cmdq.base, 32, 32); + return MEMTX_OK; + case A_CMDQ_PROD: + *data =3D s->cmdq.prod; + return MEMTX_OK; + case A_CMDQ_CONS: + *data =3D s->cmdq.cons; + return MEMTX_OK; + case A_EVENTQ_BASE: /* 64b */ + *data =3D extract64(s->eventq.base, 0, 32); + return MEMTX_OK; + case A_EVENTQ_BASE + 4: /* 64b */ + *data =3D extract64(s->eventq.base, 32, 32); + return MEMTX_OK; + case A_EVENTQ_PROD: + *data =3D s->eventq.prod; + return MEMTX_OK; + case A_EVENTQ_CONS: + *data =3D s->eventq.cons; + return MEMTX_OK; + default: + *data =3D 0; + qemu_log_mask(LOG_UNIMP, + "%s unhandled 32-bit access at 0x%"PRIx64" (RAZ)\n", + __func__, offset); + return MEMTX_OK; + } +} + +static MemTxResult smmu_read_mmio(void *opaque, hwaddr offset, uint64_t *d= ata, + unsigned size, MemTxAttrs attrs) +{ + SMMUState *sys =3D opaque; + SMMUv3State *s =3D ARM_SMMUV3(sys); + MemTxResult r; + + /* CONSTRAINED UNPREDICTABLE choice to have page0/1 be exact aliases */ + offset &=3D ~0x10000; + + switch (size) { + case 8: + r =3D smmu_readll(s, offset, data, attrs); + break; + case 4: + r =3D smmu_readl(s, offset, data, attrs); + break; + default: + r =3D MEMTX_ERROR; + break; + } + + trace_smmuv3_read_mmio(offset, *data, size, r); + return r; +} + +static const MemoryRegionOps smmu_mem_ops =3D { + .read_with_attrs =3D smmu_read_mmio, + .write_with_attrs =3D smmu_write_mmio, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, + .impl =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, +}; + +static void smmu_init_irq(SMMUv3State *s, SysBusDevice *dev) +{ + int i; + + for (i =3D 0; i < ARRAY_SIZE(s->irq); i++) { + sysbus_init_irq(dev, &s->irq[i]); + } +} + +static void smmu_reset(DeviceState *dev) +{ + SMMUv3State *s =3D ARM_SMMUV3(dev); + SMMUv3Class *c =3D ARM_SMMUV3_GET_CLASS(s); + + c->parent_reset(dev); + + smmuv3_init_regs(s); +} + +static void smmu_realize(DeviceState *d, Error **errp) +{ + SMMUState *sys =3D ARM_SMMU(d); + SMMUv3State *s =3D ARM_SMMUV3(sys); + SMMUv3Class *c =3D ARM_SMMUV3_GET_CLASS(s); + SysBusDevice *dev =3D SYS_BUS_DEVICE(d); + Error *local_err =3D NULL; + + c->parent_realize(d, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + memory_region_init_io(&sys->iomem, OBJECT(s), + &smmu_mem_ops, sys, TYPE_ARM_SMMUV3, 0x20000); + + sys->mrtypename =3D TYPE_SMMUV3_IOMMU_MEMORY_REGION; + + sysbus_init_mmio(dev, &sys->iomem); + + smmu_init_irq(s, dev); +} + +static const VMStateDescription vmstate_smmuv3_queue =3D { + .name =3D "smmuv3_queue", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_UINT64(base, SMMUQueue), + VMSTATE_UINT32(prod, SMMUQueue), + VMSTATE_UINT32(cons, SMMUQueue), + VMSTATE_UINT8(log2size, SMMUQueue), + }, +}; + +static const VMStateDescription vmstate_smmuv3 =3D { + .name =3D "smmuv3", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_UINT32(features, SMMUv3State), + VMSTATE_UINT8(sid_size, SMMUv3State), + VMSTATE_UINT8(sid_split, SMMUv3State), + + VMSTATE_UINT32_ARRAY(cr, SMMUv3State, 3), + VMSTATE_UINT32(cr0ack, SMMUv3State), + VMSTATE_UINT32(statusr, SMMUv3State), + VMSTATE_UINT32(irq_ctrl, SMMUv3State), + VMSTATE_UINT32(gerror, SMMUv3State), + VMSTATE_UINT32(gerrorn, SMMUv3State), + VMSTATE_UINT64(gerror_irq_cfg0, SMMUv3State), + VMSTATE_UINT32(gerror_irq_cfg1, SMMUv3State), + VMSTATE_UINT32(gerror_irq_cfg2, SMMUv3State), + VMSTATE_UINT64(strtab_base, SMMUv3State), + VMSTATE_UINT32(strtab_base_cfg, SMMUv3State), + VMSTATE_UINT64(eventq_irq_cfg0, SMMUv3State), + VMSTATE_UINT32(eventq_irq_cfg1, SMMUv3State), + VMSTATE_UINT32(eventq_irq_cfg2, SMMUv3State), + + VMSTATE_STRUCT(cmdq, SMMUv3State, 0, vmstate_smmuv3_queue, SMMUQue= ue), + VMSTATE_STRUCT(eventq, SMMUv3State, 0, vmstate_smmuv3_queue, SMMUQ= ueue), + + VMSTATE_END_OF_LIST(), + }, +}; + +static void smmuv3_instance_init(Object *obj) +{ + /* Nothing much to do here as of now */ +} + +static void smmuv3_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + SMMUv3Class *c =3D ARM_SMMUV3_CLASS(klass); + + dc->vmsd =3D &vmstate_smmuv3; + device_class_set_parent_reset(dc, smmu_reset, &c->parent_reset); + c->parent_realize =3D dc->realize; + dc->realize =3D smmu_realize; +} + +static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, + void *data) +{ +} + +static const TypeInfo smmuv3_type_info =3D { + .name =3D TYPE_ARM_SMMUV3, + .parent =3D TYPE_ARM_SMMU, + .instance_size =3D sizeof(SMMUv3State), + .instance_init =3D smmuv3_instance_init, + .class_size =3D sizeof(SMMUv3Class), + .class_init =3D smmuv3_class_init, +}; + +static const TypeInfo smmuv3_iommu_memory_region_info =3D { + .parent =3D TYPE_IOMMU_MEMORY_REGION, + .name =3D TYPE_SMMUV3_IOMMU_MEMORY_REGION, + .class_init =3D smmuv3_iommu_memory_region_class_init, +}; + +static void smmuv3_register_types(void) +{ + type_register(&smmuv3_type_info); + type_register(&smmuv3_iommu_memory_region_info); +} + +type_init(smmuv3_register_types) + diff --git a/hw/arm/trace-events b/hw/arm/trace-events index 524964a..2f3d74a 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -12,3 +12,6 @@ smmu_ptw_invalid_pte(int stage, int level, uint64_t basea= ddr, uint64_t pteaddr, smmu_ptw_page_pte(int stage, int level, uint64_t iova, uint64_t baseaddr,= uint64_t pteaddr, uint64_t pte, uint64_t address) "stage=3D%d level=3D%d i= ova=3D0x%"PRIx64" base@=3D0x%"PRIx64" pte@=3D0x%"PRIx64" pte=3D0x%"PRIx64" = page address =3D 0x%"PRIx64 smmu_ptw_block_pte(int stage, int level, uint64_t baseaddr, uint64_t ptead= dr, uint64_t pte, uint64_t iova, uint64_t gpa, int bsize_mb) "stage=3D%d le= vel=3D%d base@=3D0x%"PRIx64" pte@=3D0x%"PRIx64" pte=3D0x%"PRIx64" iova=3D0x= %"PRIx64" block address =3D 0x%"PRIx64" block size =3D %d MiB" smmu_get_pte(uint64_t baseaddr, int index, uint64_t pteaddr, uint64_t pte)= "baseaddr=3D0x%"PRIx64" index=3D0x%x, pteaddr=3D0x%"PRIx64", pte=3D0x%"PRI= x64 + +#hw/arm/smmuv3.c +smmuv3_read_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "= addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)" diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h new file mode 100644 index 0000000..23f7036 --- /dev/null +++ b/include/hw/arm/smmuv3.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2014-2016 Broadcom Corporation + * Copyright (c) 2017 Red Hat, Inc. + * Written by Prem Mallappa, Eric Auger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef HW_ARM_SMMUV3_H +#define HW_ARM_SMMUV3_H + +#include "hw/arm/smmu-common.h" +#include "hw/registerfields.h" + +#define TYPE_SMMUV3_IOMMU_MEMORY_REGION "smmuv3-iommu-memory-region" + +typedef struct SMMUQueue { + uint64_t base; /* base register */ + uint32_t prod; + uint32_t cons; + uint8_t entry_size; + uint8_t log2size; +} SMMUQueue; + +typedef struct SMMUv3State { + SMMUState smmu_state; + + uint32_t features; + uint8_t sid_size; + uint8_t sid_split; + + uint32_t idr[6]; + uint32_t iidr; + uint32_t cr[3]; + uint32_t cr0ack; + uint32_t statusr; + uint32_t irq_ctrl; + uint32_t gerror; + uint32_t gerrorn; + uint64_t gerror_irq_cfg0; + uint32_t gerror_irq_cfg1; + uint32_t gerror_irq_cfg2; + uint64_t strtab_base; + uint32_t strtab_base_cfg; + uint64_t eventq_irq_cfg0; + uint32_t eventq_irq_cfg1; + uint32_t eventq_irq_cfg2; + + SMMUQueue eventq, cmdq; + + qemu_irq irq[4]; +} SMMUv3State; + +typedef enum { + SMMU_IRQ_EVTQ, + SMMU_IRQ_PRIQ, + SMMU_IRQ_CMD_SYNC, + SMMU_IRQ_GERROR, +} SMMUIrq; + +typedef struct { + /*< private >*/ + SMMUBaseClass smmu_base_class; + /*< public >*/ + + DeviceRealize parent_realize; + DeviceReset parent_reset; +} SMMUv3Class; + +#define TYPE_ARM_SMMUV3 "arm-smmuv3" +#define ARM_SMMUV3(obj) OBJECT_CHECK(SMMUv3State, (obj), TYPE_ARM_SMMUV3) +#define ARM_SMMUV3_CLASS(klass) \ + OBJECT_CLASS_CHECK(SMMUv3Class, (klass), TYPE_ARM_SMMUV3) +#define ARM_SMMUV3_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SMMUv3Class, (obj), TYPE_ARM_SMMUV3) + +#endif --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523519045773497.3537565581772; Thu, 12 Apr 2018 00:44:05 -0700 (PDT) Received: from localhost ([::1]:44096 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wto-0002sc-SE for importer@patchew.org; Thu, 12 Apr 2018 03:44:04 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49295) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wof-0006bF-V6 for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:47 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6Wob-00038u-1k for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:45 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34336 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6WoX-00035N-Un; Thu, 12 Apr 2018 03:38:38 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6D2D24075A67; Thu, 12 Apr 2018 07:38:37 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id CFD43215CDC6; Thu, 12 Apr 2018 07:38:34 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:37:56 +0200 Message-Id: <1523518688-26674-6-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Thu, 12 Apr 2018 07:38:37 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Thu, 12 Apr 2018 07:38:37 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 05/17] hw/arm/smmuv3: Wired IRQ and GERROR helpers 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" We introduce some helpers to handle wired IRQs and especially GERROR interrupt. SMMU writes GERROR register on GERROR event and SW acks GERROR interrupts by setting GERRORn. The Wired interrupts are edge sensitive hence the pulse usage. Signed-off-by: Eric Auger Signed-off-by: Prem Mallappa Reviewed-by: Peter Maydell --- v9 - v10: - s/hwaddr/uint64_t in trace-events - use qemu_log_mask LOG_UNIMP on PRI IRQ - add a comment saying smmuv3_trigger_irq and smmuv3_write_gerrorn will become static later on - write gerrorn without filtering (ie. even if the guest toggles non active IRQs) - pulse if at least one new IRQ type - smmuv3_eventq_irq_enabled and smmuv3_gerror_irq_enabled become static inline v7 -> v8: - remove SMMU_PENDING_GERRORS macro - properly toggle gerror - properly sanitize gerrorn write --- hw/arm/smmuv3-internal.h | 36 +++++++++++---------------- hw/arm/smmuv3.c | 64 ++++++++++++++++++++++++++++++++++++++++++++= ++++ hw/arm/trace-events | 3 +++ 3 files changed, 81 insertions(+), 22 deletions(-) diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index a6461fe..32f81d4 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h @@ -129,28 +129,6 @@ typedef struct Evt { uint32_t word[8]; } Evt; =20 -/** - * smmu_read64 - 64-bit register read utility function supporting - * aligned 32-bit word access to both 32-bit halves and aligned 64-bit - * access. - * - * @r: register address - * @offset: byte offset if 32-bit access - * @size: read byte size - */ -static inline uint64_t smmu_read64(uint64_t r, unsigned offset, - unsigned size) -{ - if (size =3D=3D 8) { - return r; - } - - /* 32 bit access */ - assert(!offset || offset =3D=3D 4); - - return extract64(r, offset << 3, 32); -} - static inline uint32_t smmuv3_idreg(int regoffset) { /* @@ -164,4 +142,18 @@ static inline uint32_t smmuv3_idreg(int regoffset) return smmuv3_ids[regoffset / 4]; } =20 +static inline bool smmuv3_eventq_irq_enabled(SMMUv3State *s) +{ + return FIELD_EX32(s->irq_ctrl, IRQ_CTRL, EVENTQ_IRQEN); +} + +static inline bool smmuv3_gerror_irq_enabled(SMMUv3State *s) +{ + return FIELD_EX32(s->irq_ctrl, IRQ_CTRL, GERROR_IRQEN); +} + +/* public until callers get introduced */ +void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq, uint32_t gerror_mask); +void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t gerrorn); + #endif diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index dba4656..46683a8 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -30,6 +30,70 @@ #include "hw/arm/smmuv3.h" #include "smmuv3-internal.h" =20 +/** + * smmuv3_trigger_irq - pulse @irq if enabled and update + * GERROR register in case of GERROR interrupt + * + * @irq: irq type + * @gerror_mask: mask of gerrors to toggle (relevant if @irq is GERROR) + */ +void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq, uint32_t gerror_mask) +{ + + bool pulse =3D false; + + switch (irq) { + case SMMU_IRQ_EVTQ: + pulse =3D smmuv3_eventq_irq_enabled(s); + break; + case SMMU_IRQ_PRIQ: + qemu_log_mask(LOG_UNIMP, "PRI not yet supported\n"); + break; + case SMMU_IRQ_CMD_SYNC: + pulse =3D true; + break; + case SMMU_IRQ_GERROR: + { + uint32_t pending =3D s->gerror ^ s->gerrorn; + uint32_t new_gerrors =3D ~pending & gerror_mask; + + if (!new_gerrors) { + /* only toggle non pending errors */ + return; + } + s->gerror ^=3D new_gerrors; + trace_smmuv3_write_gerror(new_gerrors, s->gerror); + + pulse =3D smmuv3_gerror_irq_enabled(s); + break; + } + } + if (pulse) { + trace_smmuv3_trigger_irq(irq); + qemu_irq_pulse(s->irq[irq]); + } +} + +void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t new_gerrorn) +{ + uint32_t pending =3D s->gerror ^ s->gerrorn; + uint32_t toggled =3D s->gerrorn ^ new_gerrorn; + + if (toggled & ~pending) { + qemu_log_mask(LOG_GUEST_ERROR, + "guest toggles non pending errors =3D 0x%x\n", + toggled & ~pending); + } + + /* + * We do not raise any error in case guest toggles bits corresponding + * to not active IRQs (CONSTRAINED UNPREDICTABLE) + */ + s->gerrorn =3D new_gerrorn; + + trace_smmuv3_write_gerrorn(toggled & pending, s->gerrorn); +} + static void smmuv3_init_regs(SMMUv3State *s) { /** diff --git a/hw/arm/trace-events b/hw/arm/trace-events index 2f3d74a..b77f8d2 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -15,3 +15,6 @@ smmu_get_pte(uint64_t baseaddr, int index, uint64_t ptead= dr, uint64_t pte) "base =20 #hw/arm/smmuv3.c smmuv3_read_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "= addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)" +smmuv3_trigger_irq(int irq) "irq=3D%d" +smmuv3_write_gerror(uint32_t toggled, uint32_t gerror) "toggled=3D0x%x, ne= w GERROR=3D0x%x" +smmuv3_write_gerrorn(uint32_t acked, uint32_t gerrorn) "acked=3D0x%x, new = GERRORN=3D0x%x" --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523519313791758.4784530843638; Thu, 12 Apr 2018 00:48:33 -0700 (PDT) Received: from localhost ([::1]:44134 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wy8-0007Go-Ud for importer@patchew.org; Thu, 12 Apr 2018 03:48:32 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49356) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Woj-0006hN-Mt for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:51 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6Woh-0003Dr-Uo for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:49 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34360 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6Wob-00038i-4f; Thu, 12 Apr 2018 03:38:41 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A2A39405728C; Thu, 12 Apr 2018 07:38:40 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id B0E5E215CDC6; Thu, 12 Apr 2018 07:38:37 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:37:57 +0200 Message-Id: <1523518688-26674-7-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Thu, 12 Apr 2018 07:38:40 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Thu, 12 Apr 2018 07:38:40 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 06/17] hw/arm/smmuv3: Queue helpers 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" We introduce helpers to read/write into the command and event circular queues. smmuv3_write_eventq and smmuv3_cmq_consume will become static in subsequent patches. Invalidation commands are not yet dealt with. We do not cache data that need to be invalidated. This will change with vhost integration. Signed-off-by: Eric Auger Signed-off-by: Prem Mallappa Reviewed-by: Peter Maydell --- v9 -> v10: - simplified macros - s/BASE/Q_BASE - use log2size field - static inline functions replacing some macros - simplified queue_prod_incr/queue_cons_incr and use deposit32 - trace for cmdq_consume failure v8 -> v9: - fix CMD_SSID & CMD_ADDR + some renamings - do cons increment after the execution of the command - add Q_INCONSISTENT() v7 -> v8 - use address_space_rw - helpers inspired from spec --- hw/arm/smmuv3-internal.h | 154 +++++++++++++++++++++++++++++++++++++++++++= ++++ hw/arm/smmuv3.c | 136 +++++++++++++++++++++++++++++++++++++++++ hw/arm/trace-events | 5 ++ 3 files changed, 295 insertions(+) diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index 32f81d4..968fa25 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h @@ -156,4 +156,158 @@ static inline bool smmuv3_gerror_irq_enabled(SMMUv3St= ate *s) void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq, uint32_t gerror_mask); void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t gerrorn); =20 +/* Queue Handling */ + +#define Q_BASE(q) ((q)->base & SMMU_BASE_ADDR_MASK) +#define WRAP_MASK(q) (1 << (q)->log2size) +#define INDEX_MASK(q) (((1 << (q)->log2size)) - 1) +#define WRAP_INDEX_MASK(q) ((1 << ((q)->log2size + 1)) - 1) + +#define Q_CONS(q) ((q)->cons & INDEX_MASK(q)) +#define Q_PROD(q) ((q)->prod & INDEX_MASK(q)) + +#define Q_CONS_ENTRY(q) (Q_BASE(q) + (q)->entry_size * Q_CONS(q)) +#define Q_PROD_ENTRY(q) (Q_BASE(q) + (q)->entry_size * Q_PROD(q)) + +#define Q_CONS_WRAP(q) (((q)->cons & WRAP_MASK(q)) >> (q)->log2size) +#define Q_PROD_WRAP(q) (((q)->prod & WRAP_MASK(q)) >> (q)->log2size) + +static inline bool smmuv3_q_full(SMMUQueue *q) +{ + return ((q->cons ^ q->prod) & WRAP_INDEX_MASK(q)) =3D=3D WRAP_MASK(q); +} + +static inline bool smmuv3_q_empty(SMMUQueue *q) +{ + return (q->cons & WRAP_INDEX_MASK(q)) =3D=3D (q->prod & WRAP_INDEX_MAS= K(q)); +} + +static inline void queue_prod_incr(SMMUQueue *q) +{ + q->prod =3D (q->prod + 1) & WRAP_INDEX_MASK(q); +} + +static inline void queue_cons_incr(SMMUQueue *q) +{ + q->cons =3D deposit32(q->cons, 0, q->log2size + 1, q->cons + 1); +} + +static inline bool smmuv3_cmdq_enabled(SMMUv3State *s) +{ + return FIELD_EX32(s->cr[0], CR0, CMDQEN); +} + +static inline bool smmuv3_eventq_enabled(SMMUv3State *s) +{ + return FIELD_EX32(s->cr[0], CR0, EVENTQEN); +} + +static inline void smmu_write_cmdq_err(SMMUv3State *s, uint32_t err_type) +{ + s->cmdq.cons =3D FIELD_DP32(s->cmdq.cons, CMDQ_CONS, ERR, err_type); +} + +void smmuv3_write_eventq(SMMUv3State *s, Evt *evt); + +/* Commands */ + +typedef enum SMMUCommandType { + SMMU_CMD_PREFETCH_CONFIG =3D 0x01, + SMMU_CMD_PREFETCH_ADDR, + SMMU_CMD_CFGI_STE, + SMMU_CMD_CFGI_STE_RANGE, + SMMU_CMD_CFGI_CD, + SMMU_CMD_CFGI_CD_ALL, + SMMU_CMD_CFGI_ALL, + SMMU_CMD_TLBI_NH_ALL =3D 0x10, + SMMU_CMD_TLBI_NH_ASID, + SMMU_CMD_TLBI_NH_VA, + SMMU_CMD_TLBI_NH_VAA, + SMMU_CMD_TLBI_EL3_ALL =3D 0x18, + SMMU_CMD_TLBI_EL3_VA =3D 0x1a, + SMMU_CMD_TLBI_EL2_ALL =3D 0x20, + SMMU_CMD_TLBI_EL2_ASID, + SMMU_CMD_TLBI_EL2_VA, + SMMU_CMD_TLBI_EL2_VAA, /* 0x23 */ + SMMU_CMD_TLBI_S12_VMALL =3D 0x28, + SMMU_CMD_TLBI_S2_IPA =3D 0x2a, + SMMU_CMD_TLBI_NSNH_ALL =3D 0x30, + SMMU_CMD_ATC_INV =3D 0x40, + SMMU_CMD_PRI_RESP, + SMMU_CMD_RESUME =3D 0x44, + SMMU_CMD_STALL_TERM, + SMMU_CMD_SYNC, /* 0x46 */ +} SMMUCommandType; + +static const char *cmd_stringify[] =3D { + [SMMU_CMD_PREFETCH_CONFIG] =3D "SMMU_CMD_PREFETCH_CONFIG", + [SMMU_CMD_PREFETCH_ADDR] =3D "SMMU_CMD_PREFETCH_ADDR", + [SMMU_CMD_CFGI_STE] =3D "SMMU_CMD_CFGI_STE", + [SMMU_CMD_CFGI_STE_RANGE] =3D "SMMU_CMD_CFGI_STE_RANGE", + [SMMU_CMD_CFGI_CD] =3D "SMMU_CMD_CFGI_CD", + [SMMU_CMD_CFGI_CD_ALL] =3D "SMMU_CMD_CFGI_CD_ALL", + [SMMU_CMD_CFGI_ALL] =3D "SMMU_CMD_CFGI_ALL", + [SMMU_CMD_TLBI_NH_ALL] =3D "SMMU_CMD_TLBI_NH_ALL", + [SMMU_CMD_TLBI_NH_ASID] =3D "SMMU_CMD_TLBI_NH_ASID", + [SMMU_CMD_TLBI_NH_VA] =3D "SMMU_CMD_TLBI_NH_VA", + [SMMU_CMD_TLBI_NH_VAA] =3D "SMMU_CMD_TLBI_NH_VAA", + [SMMU_CMD_TLBI_EL3_ALL] =3D "SMMU_CMD_TLBI_EL3_ALL", + [SMMU_CMD_TLBI_EL3_VA] =3D "SMMU_CMD_TLBI_EL3_VA", + [SMMU_CMD_TLBI_EL2_ALL] =3D "SMMU_CMD_TLBI_EL2_ALL", + [SMMU_CMD_TLBI_EL2_ASID] =3D "SMMU_CMD_TLBI_EL2_ASID", + [SMMU_CMD_TLBI_EL2_VA] =3D "SMMU_CMD_TLBI_EL2_VA", + [SMMU_CMD_TLBI_EL2_VAA] =3D "SMMU_CMD_TLBI_EL2_VAA", + [SMMU_CMD_TLBI_S12_VMALL] =3D "SMMU_CMD_TLBI_S12_VMALL", + [SMMU_CMD_TLBI_S2_IPA] =3D "SMMU_CMD_TLBI_S2_IPA", + [SMMU_CMD_TLBI_NSNH_ALL] =3D "SMMU_CMD_TLBI_NSNH_ALL", + [SMMU_CMD_ATC_INV] =3D "SMMU_CMD_ATC_INV", + [SMMU_CMD_PRI_RESP] =3D "SMMU_CMD_PRI_RESP", + [SMMU_CMD_RESUME] =3D "SMMU_CMD_RESUME", + [SMMU_CMD_STALL_TERM] =3D "SMMU_CMD_STALL_TERM", + [SMMU_CMD_SYNC] =3D "SMMU_CMD_SYNC", +}; + +static inline const char *smmu_cmd_string(SMMUCommandType type) +{ + return cmd_stringify[type] ? cmd_stringify[type] : "UNKNOWN"; +} + +/* CMDQ fields */ + +typedef enum { + SMMU_CERROR_NONE =3D 0, + SMMU_CERROR_ILL, + SMMU_CERROR_ABT, + SMMU_CERROR_ATC_INV_SYNC, +} SMMUCmdError; + +enum { /* Command completion notification */ + CMD_SYNC_SIG_NONE, + CMD_SYNC_SIG_IRQ, + CMD_SYNC_SIG_SEV, +}; + +#define CMD_TYPE(x) extract32((x)->word[0], 0 , 8) +#define CMD_SSEC(x) extract32((x)->word[0], 10, 1) +#define CMD_SSV(x) extract32((x)->word[0], 11, 1) +#define CMD_RESUME_AC(x) extract32((x)->word[0], 12, 1) +#define CMD_RESUME_AB(x) extract32((x)->word[0], 13, 1) +#define CMD_SYNC_CS(x) extract32((x)->word[0], 12, 2) +#define CMD_SSID(x) extract32((x)->word[0], 12, 20) +#define CMD_SID(x) ((x)->word[1]) +#define CMD_VMID(x) extract32((x)->word[1], 0 , 16) +#define CMD_ASID(x) extract32((x)->word[1], 16, 16) +#define CMD_RESUME_STAG(x) extract32((x)->word[2], 0 , 16) +#define CMD_RESP(x) extract32((x)->word[2], 11, 2) +#define CMD_LEAF(x) extract32((x)->word[2], 0 , 1) +#define CMD_STE_RANGE(x) extract32((x)->word[2], 0 , 5) +#define CMD_ADDR(x) ({ \ + uint64_t high =3D (uint64_t)(x)->word[3]; \ + uint64_t low =3D extract32((x)->word[2], 12, 20); \ + uint64_t addr =3D high << 32 | (low << 12); \ + addr; \ + }) + +int smmuv3_cmdq_consume(SMMUv3State *s); + #endif diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 46683a8..899f0e0 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -94,6 +94,46 @@ void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t new_g= errorn) trace_smmuv3_write_gerrorn(toggled & pending, s->gerrorn); } =20 +static inline MemTxResult queue_read(SMMUQueue *q, void *data) +{ + dma_addr_t addr =3D Q_CONS_ENTRY(q); + + return dma_memory_read(&address_space_memory, addr, data, q->entry_siz= e); +} + +static MemTxResult queue_write(SMMUQueue *q, void *data) +{ + dma_addr_t addr =3D Q_PROD_ENTRY(q); + MemTxResult ret; + + ret =3D dma_memory_write(&address_space_memory, addr, data, q->entry_s= ize); + if (ret !=3D MEMTX_OK) { + return ret; + } + + queue_prod_incr(q); + return MEMTX_OK; +} + +void smmuv3_write_eventq(SMMUv3State *s, Evt *evt) +{ + SMMUQueue *q =3D &s->eventq; + + if (!smmuv3_eventq_enabled(s)) { + return; + } + + if (smmuv3_q_full(q)) { + return; + } + + queue_write(q, evt); + + if (smmuv3_q_empty(q)) { + smmuv3_trigger_irq(s, SMMU_IRQ_EVTQ, 0); + } +} + static void smmuv3_init_regs(SMMUv3State *s) { /** @@ -133,6 +173,102 @@ static void smmuv3_init_regs(SMMUv3State *s) s->sid_split =3D 0; } =20 +int smmuv3_cmdq_consume(SMMUv3State *s) +{ + SMMUCmdError cmd_error =3D SMMU_CERROR_NONE; + SMMUQueue *q =3D &s->cmdq; + SMMUCommandType type =3D 0; + + if (!smmuv3_cmdq_enabled(s)) { + return 0; + } + /* + * some commands depend on register values, typically CR0. In case tho= se + * register values change while handling the command, spec says it + * is UNPREDICTABLE whether the command is interpreted under the new + * or old value. + */ + + while (!smmuv3_q_empty(q)) { + uint32_t pending =3D s->gerror ^ s->gerrorn; + Cmd cmd; + + trace_smmuv3_cmdq_consume(Q_PROD(q), Q_CONS(q), + Q_PROD_WRAP(q), Q_CONS_WRAP(q)); + + if (FIELD_EX32(pending, GERROR, CMDQ_ERR)) { + break; + } + + if (queue_read(q, &cmd) !=3D MEMTX_OK) { + cmd_error =3D SMMU_CERROR_ABT; + break; + } + + type =3D CMD_TYPE(&cmd); + + trace_smmuv3_cmdq_opcode(smmu_cmd_string(type)); + + switch (type) { + case SMMU_CMD_SYNC: + if (CMD_SYNC_CS(&cmd) & CMD_SYNC_SIG_IRQ) { + smmuv3_trigger_irq(s, SMMU_IRQ_CMD_SYNC, 0); + } + break; + case SMMU_CMD_PREFETCH_CONFIG: + case SMMU_CMD_PREFETCH_ADDR: + case SMMU_CMD_CFGI_STE: + case SMMU_CMD_CFGI_STE_RANGE: /* same as SMMU_CMD_CFGI_ALL */ + case SMMU_CMD_CFGI_CD: + case SMMU_CMD_CFGI_CD_ALL: + case SMMU_CMD_TLBI_NH_ALL: + case SMMU_CMD_TLBI_NH_ASID: + case SMMU_CMD_TLBI_NH_VA: + case SMMU_CMD_TLBI_NH_VAA: + case SMMU_CMD_TLBI_EL3_ALL: + case SMMU_CMD_TLBI_EL3_VA: + case SMMU_CMD_TLBI_EL2_ALL: + case SMMU_CMD_TLBI_EL2_ASID: + case SMMU_CMD_TLBI_EL2_VA: + case SMMU_CMD_TLBI_EL2_VAA: + case SMMU_CMD_TLBI_S12_VMALL: + case SMMU_CMD_TLBI_S2_IPA: + case SMMU_CMD_TLBI_NSNH_ALL: + case SMMU_CMD_ATC_INV: + case SMMU_CMD_PRI_RESP: + case SMMU_CMD_RESUME: + case SMMU_CMD_STALL_TERM: + trace_smmuv3_unhandled_cmd(type); + break; + default: + cmd_error =3D SMMU_CERROR_ILL; + qemu_log_mask(LOG_GUEST_ERROR, + "Illegal command type: %d\n", CMD_TYPE(&cmd)); + break; + } + if (cmd_error) { + break; + } + /* + * We only increment the cons index after the completion of + * the command. We do that because the SYNC returns immediately + * and does not check the completion of previous commands + */ + queue_cons_incr(q); + } + + if (cmd_error) { + trace_smmuv3_cmdq_consume_error(smmu_cmd_string(type), cmd_error); + smmu_write_cmdq_err(s, cmd_error); + smmuv3_trigger_irq(s, SMMU_IRQ_GERROR, R_GERROR_CMDQ_ERR_MASK); + } + + trace_smmuv3_cmdq_consume_out(Q_PROD(q), Q_CONS(q), + Q_PROD_WRAP(q), Q_CONS_WRAP(q)); + + return 0; +} + static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t d= ata, unsigned size, MemTxAttrs attrs) { diff --git a/hw/arm/trace-events b/hw/arm/trace-events index b77f8d2..38b35fa 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -18,3 +18,8 @@ smmuv3_read_mmio(uint64_t addr, uint64_t val, unsigned si= ze, uint32_t r) "addr: smmuv3_trigger_irq(int irq) "irq=3D%d" smmuv3_write_gerror(uint32_t toggled, uint32_t gerror) "toggled=3D0x%x, ne= w GERROR=3D0x%x" smmuv3_write_gerrorn(uint32_t acked, uint32_t gerrorn) "acked=3D0x%x, new = GERRORN=3D0x%x" +smmuv3_unhandled_cmd(uint32_t type) "Unhandled command type=3D%d" +smmuv3_cmdq_consume(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8= _t cons_wrap) "prod=3D%d cons=3D%d prod.wrap=3D%d cons.wrap=3D%d" +smmuv3_cmdq_opcode(const char *opcode) "<--- %s" +smmuv3_cmdq_consume_out(uint32_t prod, uint32_t cons, uint8_t prod_wrap, u= int8_t cons_wrap) "prod:%d, cons:%d, prod_wrap:%d, cons_wrap:%d " +smmuv3_cmdq_consume_error(const char *cmd_name, uint8_t cmd_error) "Error = on %s command execution: %d" --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 152351911727559.78622470710661; Thu, 12 Apr 2018 00:45:17 -0700 (PDT) Received: from localhost ([::1]:44101 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wuy-00047s-C4 for importer@patchew.org; Thu, 12 Apr 2018 03:45:16 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49353) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Woj-0006gw-CX for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:51 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6Woh-0003Df-Q4 for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:49 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:35554 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6Woe-0003BC-18; Thu, 12 Apr 2018 03:38:44 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 84A1981A88A0; Thu, 12 Apr 2018 07:38:43 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id E6AD3215CDC6; Thu, 12 Apr 2018 07:38:40 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:37:58 +0200 Message-Id: <1523518688-26674-8-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 12 Apr 2018 07:38:43 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 12 Apr 2018 07:38:43 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 07/17] hw/arm/smmuv3: Implement MMIO write operations 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Now we have relevant helpers for queue and irq management, let's implement MMIO write operations. Signed-off-by: Eric Auger Signed-off-by: Prem Mallappa Reviewed-by: Peter Maydell --- v9 -> v10: - s/hwaddr/uint64_t in trace-events - added SMMU_FEATURE_2LVL_STE in this patch - removed smmu_write64 and created writel/writell infra - store capped log2size - mask CR0 reserved bits v7 -> v8: - precise in the commit message invalidation commands are not yet treated. - use new queue helpers - do not decode unhandled commands at this stage --- hw/arm/smmuv3-internal.h | 8 +-- hw/arm/smmuv3.c | 172 +++++++++++++++++++++++++++++++++++++++++++= ++-- hw/arm/trace-events | 6 ++ 3 files changed, 175 insertions(+), 11 deletions(-) diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index 968fa25..8550be0 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h @@ -64,6 +64,8 @@ REG32(CR0, 0x20) FIELD(CR0, EVENTQEN, 2, 1) FIELD(CR0, CMDQEN, 3, 1) =20 +#define SMMU_CR0_RESERVED 0xFFFFFC20 + REG32(CR0ACK, 0x24) REG32(CR1, 0x28) REG32(CR2, 0x2c) @@ -152,10 +154,6 @@ static inline bool smmuv3_gerror_irq_enabled(SMMUv3Sta= te *s) return FIELD_EX32(s->irq_ctrl, IRQ_CTRL, GERROR_IRQEN); } =20 -/* public until callers get introduced */ -void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq, uint32_t gerror_mask); -void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t gerrorn); - /* Queue Handling */ =20 #define Q_BASE(q) ((q)->base & SMMU_BASE_ADDR_MASK) @@ -308,6 +306,6 @@ enum { /* Command completion notification */ addr; \ }) =20 -int smmuv3_cmdq_consume(SMMUv3State *s); +#define SMMU_FEATURE_2LVL_STE (1 << 0) =20 #endif diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 899f0e0..82ad1af 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -37,7 +37,8 @@ * @irq: irq type * @gerror_mask: mask of gerrors to toggle (relevant if @irq is GERROR) */ -void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq, uint32_t gerror_mask) +static void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq, + uint32_t gerror_mask) { =20 bool pulse =3D false; @@ -74,7 +75,7 @@ void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq, uint= 32_t gerror_mask) } } =20 -void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t new_gerrorn) +static void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t new_gerrorn) { uint32_t pending =3D s->gerror ^ s->gerrorn; uint32_t toggled =3D s->gerrorn ^ new_gerrorn; @@ -173,7 +174,7 @@ static void smmuv3_init_regs(SMMUv3State *s) s->sid_split =3D 0; } =20 -int smmuv3_cmdq_consume(SMMUv3State *s) +static int smmuv3_cmdq_consume(SMMUv3State *s) { SMMUCmdError cmd_error =3D SMMU_CERROR_NONE; SMMUQueue *q =3D &s->cmdq; @@ -269,11 +270,170 @@ int smmuv3_cmdq_consume(SMMUv3State *s) return 0; } =20 -static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t d= ata, +static MemTxResult smmu_writell(SMMUv3State *s, hwaddr offset, + uint64_t value, MemTxAttrs attrs) +{ + switch (offset) { + case A_GERROR_IRQ_CFG0: + s->gerror_irq_cfg0 =3D value; + return MEMTX_OK; + case A_STRTAB_BASE: + s->strtab_base =3D value; + return MEMTX_OK; + case A_CMDQ_BASE: + s->cmdq.base =3D value; + s->cmdq.log2size =3D extract64(s->cmdq.base, 0, 5); + if (s->cmdq.log2size > SMMU_CMDQS) { + s->cmdq.log2size =3D SMMU_CMDQS; + } + return MEMTX_OK; + case A_EVENTQ_BASE: + s->eventq.base =3D value; + s->eventq.log2size =3D extract64(s->eventq.base, 0, 5); + if (s->eventq.log2size > SMMU_EVENTQS) { + s->eventq.log2size =3D SMMU_EVENTQS; + } + return MEMTX_OK; + case A_EVENTQ_IRQ_CFG0: + s->eventq_irq_cfg0 =3D value; + return MEMTX_OK; + default: + qemu_log_mask(LOG_UNIMP, + "%s Unexpected 64-bit access to 0x%"PRIx64" (WI)\n", + __func__, offset); + return MEMTX_OK; + } +} + +static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset, + uint64_t value, MemTxAttrs attrs) +{ + switch (offset) { + case A_CR0: + s->cr[0] =3D value; + s->cr0ack =3D value & ~SMMU_CR0_RESERVED; + /* in case the command queue has been enabled */ + smmuv3_cmdq_consume(s); + return MEMTX_OK; + case A_CR1: + s->cr[1] =3D value; + return MEMTX_OK; + case A_CR2: + s->cr[2] =3D value; + return MEMTX_OK; + case A_IRQ_CTRL: + s->irq_ctrl =3D value; + return MEMTX_OK; + case A_GERRORN: + smmuv3_write_gerrorn(s, value); + /* + * By acknowledging the CMDQ_ERR, SW may notify cmds can + * be processed again + */ + smmuv3_cmdq_consume(s); + return MEMTX_OK; + case A_GERROR_IRQ_CFG0: /* 64b */ + s->gerror_irq_cfg0 =3D deposit64(s->gerror_irq_cfg0, 0, 32, value); + return MEMTX_OK; + case A_GERROR_IRQ_CFG0 + 4: + s->gerror_irq_cfg0 =3D deposit64(s->gerror_irq_cfg0, 32, 32, value= ); + return MEMTX_OK; + case A_GERROR_IRQ_CFG1: + s->gerror_irq_cfg1 =3D value; + return MEMTX_OK; + case A_GERROR_IRQ_CFG2: + s->gerror_irq_cfg2 =3D value; + return MEMTX_OK; + case A_STRTAB_BASE: /* 64b */ + s->strtab_base =3D deposit64(s->strtab_base, 0, 32, value); + return MEMTX_OK; + case A_STRTAB_BASE + 4: + s->strtab_base =3D deposit64(s->strtab_base, 32, 32, value); + return MEMTX_OK; + case A_STRTAB_BASE_CFG: + s->strtab_base_cfg =3D value; + if (FIELD_EX32(value, STRTAB_BASE_CFG, FMT) =3D=3D 1) { + s->sid_split =3D FIELD_EX32(value, STRTAB_BASE_CFG, SPLIT); + s->features |=3D SMMU_FEATURE_2LVL_STE; + } + return MEMTX_OK; + case A_CMDQ_BASE: /* 64b */ + s->cmdq.base =3D deposit64(s->cmdq.base, 0, 32, value); + s->cmdq.log2size =3D extract64(s->cmdq.base, 0, 5); + if (s->cmdq.log2size > SMMU_CMDQS) { + s->cmdq.log2size =3D SMMU_CMDQS; + } + return MEMTX_OK; + case A_CMDQ_BASE + 4: /* 64b */ + s->cmdq.base =3D deposit64(s->cmdq.base, 32, 32, value); + return MEMTX_OK; + case A_CMDQ_PROD: + s->cmdq.prod =3D value; + smmuv3_cmdq_consume(s); + return MEMTX_OK; + case A_CMDQ_CONS: + s->cmdq.cons =3D value; + return MEMTX_OK; + case A_EVENTQ_BASE: /* 64b */ + s->eventq.base =3D deposit64(s->eventq.base, 0, 32, value); + s->eventq.log2size =3D extract64(s->eventq.base, 0, 5); + if (s->eventq.log2size > SMMU_EVENTQS) { + s->eventq.log2size =3D SMMU_EVENTQS; + } + return MEMTX_OK; + case A_EVENTQ_BASE + 4: + s->eventq.base =3D deposit64(s->eventq.base, 32, 32, value); + return MEMTX_OK; + case A_EVENTQ_PROD: + s->eventq.prod =3D value; + return MEMTX_OK; + case A_EVENTQ_CONS: + s->eventq.cons =3D value; + return MEMTX_OK; + case A_EVENTQ_IRQ_CFG0: /* 64b */ + s->eventq_irq_cfg0 =3D deposit64(s->eventq_irq_cfg0, 0, 32, value); + return MEMTX_OK; + case A_EVENTQ_IRQ_CFG0 + 4: + s->eventq_irq_cfg0 =3D deposit64(s->eventq_irq_cfg0, 32, 32, value= ); + return MEMTX_OK; + case A_EVENTQ_IRQ_CFG1: + s->eventq_irq_cfg1 =3D value; + return MEMTX_OK; + case A_EVENTQ_IRQ_CFG2: + s->eventq_irq_cfg2 =3D value; + return MEMTX_OK; + default: + qemu_log_mask(LOG_UNIMP, + "%s Unexpected 32-bit access to 0x%"PRIx64" (WI)\n", + __func__, offset); + return MEMTX_OK; + } +} + +static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t v= alue, unsigned size, MemTxAttrs attrs) { - /* not yet implemented */ - return MEMTX_ERROR; + SMMUState *sys =3D opaque; + SMMUv3State *s =3D ARM_SMMUV3(sys); + MemTxResult r; + + /* CONSTRAINED UNPREDICTABLE choice to have page0/1 be exact aliases */ + offset &=3D ~0x10000; + + switch (size) { + case 8: + r =3D smmu_writell(s, offset, value, attrs); + break; + case 4: + r =3D smmu_writel(s, offset, value, attrs); + break; + default: + r =3D MEMTX_ERROR; + break; + } + + trace_smmuv3_write_mmio(offset, value, size, r); + return r; } =20 static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset, diff --git a/hw/arm/trace-events b/hw/arm/trace-events index 38b35fa..781542a 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -23,3 +23,9 @@ smmuv3_cmdq_consume(uint32_t prod, uint32_t cons, uint8_t= prod_wrap, uint8_t con smmuv3_cmdq_opcode(const char *opcode) "<--- %s" smmuv3_cmdq_consume_out(uint32_t prod, uint32_t cons, uint8_t prod_wrap, u= int8_t cons_wrap) "prod:%d, cons:%d, prod_wrap:%d, cons_wrap:%d " smmuv3_cmdq_consume_error(const char *cmd_name, uint8_t cmd_error) "Error = on %s command execution: %d" +smmuv3_update(bool is_empty, uint32_t prod, uint32_t cons, uint8_t prod_wr= ap, uint8_t cons_wrap) "q empty:%d prod:%d cons:%d p.wrap:%d p.cons:%d" +smmuv3_update_check_cmd(int error) "cmdq not enabled or error :0x%x" +smmuv3_write_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) = "addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)" +smmuv3_write_mmio_idr(uint64_t addr, uint64_t val) "write to RO/Unimpl reg= 0x%lx val64:0x%lx" +smmuv3_write_mmio_evtq_cons_bef_clear(uint32_t prod, uint32_t cons, uint8_= t prod_wrap, uint8_t cons_wrap) "Before clearing interrupt prod:0x%x cons:0= x%x prod.w:%d cons.w:%d" +smmuv3_write_mmio_evtq_cons_after_clear(uint32_t prod, uint32_t cons, uint= 8_t prod_wrap, uint8_t cons_wrap) "after clearing interrupt prod:0x%x cons:= 0x%x prod.w:%d cons.w:%d" --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523519534385515.712109324737; Thu, 12 Apr 2018 00:52:14 -0700 (PDT) Received: from localhost ([::1]:44335 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6X1g-0002Qm-Dy for importer@patchew.org; Thu, 12 Apr 2018 03:52:12 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49447) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wop-0006qD-SE for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6Wok-0003Fl-Sy for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:55 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:56798 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6Woh-0003D9-8I; Thu, 12 Apr 2018 03:38:47 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BE18C722C3; Thu, 12 Apr 2018 07:38:46 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id C71BD215CDC6; Thu, 12 Apr 2018 07:38:43 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:37:59 +0200 Message-Id: <1523518688-26674-9-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Thu, 12 Apr 2018 07:38:46 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Thu, 12 Apr 2018 07:38:46 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 08/17] hw/arm/smmuv3: Event queue recording helper 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Let's introduce a helper function aiming at recording an event in the event queue. Signed-off-by: Eric Auger Reviewed-by: Peter Maydell --- v9 -> v10: - rework SMMU_EVENT_STRING - trigger a GERROR EVENTQ_ABT_ERR in case of eventq write failure v8 -> v9: - add SMMU_EVENT_STRING v7 -> v8: - use dma_addr_t instead of hwaddr in smmuv3_record_event() - introduce struct SMMUEventInfo - add event_stringify + helpers for all fields --- hw/arm/smmuv3-internal.h | 142 +++++++++++++++++++++++++++++++++++++++++++= +++- hw/arm/smmuv3.c | 108 +++++++++++++++++++++++++++++++++-- hw/arm/trace-events | 1 + 3 files changed, 243 insertions(+), 8 deletions(-) diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index 8550be0..8e546bf 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h @@ -205,8 +205,6 @@ static inline void smmu_write_cmdq_err(SMMUv3State *s, = uint32_t err_type) s->cmdq.cons =3D FIELD_DP32(s->cmdq.cons, CMDQ_CONS, ERR, err_type); } =20 -void smmuv3_write_eventq(SMMUv3State *s, Evt *evt); - /* Commands */ =20 typedef enum SMMUCommandType { @@ -308,4 +306,144 @@ enum { /* Command completion notification */ =20 #define SMMU_FEATURE_2LVL_STE (1 << 0) =20 +/* Events */ + +typedef enum SMMUEventType { + SMMU_EVT_OK =3D 0x00, + SMMU_EVT_F_UUT =3D 0x01, + SMMU_EVT_C_BAD_STREAMID =3D 0x02, + SMMU_EVT_F_STE_FETCH =3D 0x03, + SMMU_EVT_C_BAD_STE =3D 0x04, + SMMU_EVT_F_BAD_ATS_TREQ =3D 0x05, + SMMU_EVT_F_STREAM_DISABLED =3D 0x06, + SMMU_EVT_F_TRANS_FORBIDDEN =3D 0x07, + SMMU_EVT_C_BAD_SUBSTREAMID =3D 0x08, + SMMU_EVT_F_CD_FETCH =3D 0x09, + SMMU_EVT_C_BAD_CD =3D 0x0a, + SMMU_EVT_F_WALK_EABT =3D 0x0b, + SMMU_EVT_F_TRANSLATION =3D 0x10, + SMMU_EVT_F_ADDR_SIZE =3D 0x11, + SMMU_EVT_F_ACCESS =3D 0x12, + SMMU_EVT_F_PERMISSION =3D 0x13, + SMMU_EVT_F_TLB_CONFLICT =3D 0x20, + SMMU_EVT_F_CFG_CONFLICT =3D 0x21, + SMMU_EVT_E_PAGE_REQ =3D 0x24, +} SMMUEventType; + +static const char *event_stringify[] =3D { + [SMMU_EVT_OK] =3D "SMMU_EVT_OK", + [SMMU_EVT_F_UUT] =3D "SMMU_EVT_F_UUT", + [SMMU_EVT_C_BAD_STREAMID] =3D "SMMU_EVT_C_BAD_STREAMID", + [SMMU_EVT_F_STE_FETCH] =3D "SMMU_EVT_F_STE_FETCH", + [SMMU_EVT_C_BAD_STE] =3D "SMMU_EVT_C_BAD_STE", + [SMMU_EVT_F_BAD_ATS_TREQ] =3D "SMMU_EVT_F_BAD_ATS_TREQ", + [SMMU_EVT_F_STREAM_DISABLED] =3D "SMMU_EVT_F_STREAM_DISABLED", + [SMMU_EVT_F_TRANS_FORBIDDEN] =3D "SMMU_EVT_F_TRANS_FORBIDDEN", + [SMMU_EVT_C_BAD_SUBSTREAMID] =3D "SMMU_EVT_C_BAD_SUBSTREAMID", + [SMMU_EVT_F_CD_FETCH] =3D "SMMU_EVT_F_CD_FETCH", + [SMMU_EVT_C_BAD_CD] =3D "SMMU_EVT_C_BAD_CD", + [SMMU_EVT_F_WALK_EABT] =3D "SMMU_EVT_F_WALK_EABT", + [SMMU_EVT_F_TRANSLATION] =3D "SMMU_EVT_F_TRANSLATION", + [SMMU_EVT_F_ADDR_SIZE] =3D "SMMU_EVT_F_ADDR_SIZE", + [SMMU_EVT_F_ACCESS] =3D "SMMU_EVT_F_ACCESS", + [SMMU_EVT_F_PERMISSION] =3D "SMMU_EVT_F_PERMISSION", + [SMMU_EVT_F_TLB_CONFLICT] =3D "SMMU_EVT_F_TLB_CONFLICT", + [SMMU_EVT_F_CFG_CONFLICT] =3D "SMMU_EVT_F_CFG_CONFLICT", + [SMMU_EVT_E_PAGE_REQ] =3D "SMMU_EVT_E_PAGE_REQ", +}; + +static inline const char *smmu_event_string(SMMUEventType type) +{ + return event_stringify[type] ? event_stringify[type] : "UNKNOWN"; +} + +/* Encode an event record */ +typedef struct SMMUEventInfo { + SMMUEventType type; + uint32_t sid; + bool recorded; + bool record_trans_faults; + union { + struct { + uint32_t ssid; + bool ssv; + dma_addr_t addr; + bool rnw; + bool pnu; + bool ind; + } f_uut; + struct ssid_info { + uint32_t ssid; + bool ssv; + } c_bad_streamid; + struct ssid_addr_info { + uint32_t ssid; + bool ssv; + dma_addr_t addr; + } f_ste_fetch; + struct ssid_info c_bad_ste; + struct { + dma_addr_t addr; + bool rnw; + } f_transl_forbidden; + struct { + uint32_t ssid; + } c_bad_substream; + struct ssid_addr_info f_cd_fetch; + struct ssid_info c_bad_cd; + struct full_info { + bool stall; + uint16_t stag; + uint32_t ssid; + bool ssv; + bool s2; + dma_addr_t addr; + bool rnw; + bool pnu; + bool ind; + uint8_t class; + dma_addr_t addr2; + } f_walk_eabt; + struct full_info f_translation; + struct full_info f_addr_size; + struct full_info f_access; + struct full_info f_permission; + struct ssid_info f_cfg_conflict; + /** + * not supported yet: + * F_BAD_ATS_TREQ + * F_BAD_ATS_TREQ + * F_TLB_CONFLICT + * E_PAGE_REQUEST + * IMPDEF_EVENTn + */ + } u; +} SMMUEventInfo; + +/* EVTQ fields */ + +#define EVT_Q_OVERFLOW (1 << 31) + +#define EVT_SET_TYPE(x, v) deposit32((x)->word[0], 0 , 8 , v) +#define EVT_SET_SSV(x, v) deposit32((x)->word[0], 11, 1 , v) +#define EVT_SET_SSID(x, v) deposit32((x)->word[0], 12, 20, v) +#define EVT_SET_SID(x, v) ((x)->word[1] =3D v) +#define EVT_SET_STAG(x, v) deposit32((x)->word[2], 0 , 16, v) +#define EVT_SET_STALL(x, v) deposit32((x)->word[2], 31, 1 , v) +#define EVT_SET_PNU(x, v) deposit32((x)->word[3], 1 , 1 , v) +#define EVT_SET_IND(x, v) deposit32((x)->word[3], 2 , 1 , v) +#define EVT_SET_RNW(x, v) deposit32((x)->word[3], 3 , 1 , v) +#define EVT_SET_S2(x, v) deposit32((x)->word[3], 7 , 1 , v) +#define EVT_SET_CLASS(x, v) deposit32((x)->word[3], 8 , 2 , v) +#define EVT_SET_ADDR(x, addr) ({ \ + (x)->word[5] =3D (uint32_t)(addr >> 32); \ + (x)->word[4] =3D (uint32_t)(addr & 0xffffffff); \ + }) +#define EVT_SET_ADDR2(x, addr) ({ \ + deposit32((x)->word[7], 3, 29, addr >> 16); \ + deposit32((x)->word[7], 0, 16, addr & 0xffff); \ + }) + +void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *event); + #endif diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 82ad1af..2ef1bfc 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -116,23 +116,119 @@ static MemTxResult queue_write(SMMUQueue *q, void *d= ata) return MEMTX_OK; } =20 -void smmuv3_write_eventq(SMMUv3State *s, Evt *evt) +static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt) { SMMUQueue *q =3D &s->eventq; + MemTxResult r; + + if (!smmuv3_eventq_enabled(s)) { + return MEMTX_ERROR; + } + + if (smmuv3_q_full(q)) { + return MEMTX_ERROR; + } + + r =3D queue_write(q, evt); + if (r !=3D MEMTX_OK) { + return r; + } + + if (smmuv3_q_empty(q)) { + smmuv3_trigger_irq(s, SMMU_IRQ_EVTQ, 0); + } + return MEMTX_OK; +} + +void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info) +{ + Evt evt; + MemTxResult r; =20 if (!smmuv3_eventq_enabled(s)) { return; } =20 - if (smmuv3_q_full(q)) { + EVT_SET_TYPE(&evt, info->type); + EVT_SET_SID(&evt, info->sid); + + switch (info->type) { + case SMMU_EVT_OK: return; + case SMMU_EVT_F_UUT: + EVT_SET_SSID(&evt, info->u.f_uut.ssid); + EVT_SET_SSV(&evt, info->u.f_uut.ssv); + EVT_SET_ADDR(&evt, info->u.f_uut.addr); + EVT_SET_RNW(&evt, info->u.f_uut.rnw); + EVT_SET_PNU(&evt, info->u.f_uut.pnu); + EVT_SET_IND(&evt, info->u.f_uut.ind); + break; + case SMMU_EVT_C_BAD_STREAMID: + EVT_SET_SSID(&evt, info->u.c_bad_streamid.ssid); + EVT_SET_SSV(&evt, info->u.c_bad_streamid.ssv); + break; + case SMMU_EVT_F_STE_FETCH: + EVT_SET_SSID(&evt, info->u.f_ste_fetch.ssid); + EVT_SET_SSV(&evt, info->u.f_ste_fetch.ssv); + EVT_SET_ADDR(&evt, info->u.f_ste_fetch.addr); + break; + case SMMU_EVT_C_BAD_STE: + EVT_SET_SSID(&evt, info->u.c_bad_ste.ssid); + EVT_SET_SSV(&evt, info->u.c_bad_ste.ssv); + break; + case SMMU_EVT_F_STREAM_DISABLED: + break; + case SMMU_EVT_F_TRANS_FORBIDDEN: + EVT_SET_ADDR(&evt, info->u.f_transl_forbidden.addr); + EVT_SET_RNW(&evt, info->u.f_transl_forbidden.rnw); + break; + case SMMU_EVT_C_BAD_SUBSTREAMID: + EVT_SET_SSID(&evt, info->u.c_bad_substream.ssid); + break; + case SMMU_EVT_F_CD_FETCH: + EVT_SET_SSID(&evt, info->u.f_cd_fetch.ssid); + EVT_SET_SSV(&evt, info->u.f_cd_fetch.ssv); + EVT_SET_ADDR(&evt, info->u.f_cd_fetch.addr); + break; + case SMMU_EVT_C_BAD_CD: + EVT_SET_SSID(&evt, info->u.c_bad_cd.ssid); + EVT_SET_SSV(&evt, info->u.c_bad_cd.ssv); + break; + case SMMU_EVT_F_WALK_EABT: + case SMMU_EVT_F_TRANSLATION: + case SMMU_EVT_F_ADDR_SIZE: + case SMMU_EVT_F_ACCESS: + case SMMU_EVT_F_PERMISSION: + EVT_SET_STALL(&evt, info->u.f_walk_eabt.stall); + EVT_SET_STAG(&evt, info->u.f_walk_eabt.stag); + EVT_SET_SSID(&evt, info->u.f_walk_eabt.ssid); + EVT_SET_SSV(&evt, info->u.f_walk_eabt.ssv); + EVT_SET_S2(&evt, info->u.f_walk_eabt.s2); + EVT_SET_ADDR(&evt, info->u.f_walk_eabt.addr); + EVT_SET_RNW(&evt, info->u.f_walk_eabt.rnw); + EVT_SET_PNU(&evt, info->u.f_walk_eabt.pnu); + EVT_SET_IND(&evt, info->u.f_walk_eabt.ind); + EVT_SET_CLASS(&evt, info->u.f_walk_eabt.class); + EVT_SET_ADDR2(&evt, info->u.f_walk_eabt.addr2); + break; + case SMMU_EVT_F_CFG_CONFLICT: + EVT_SET_SSID(&evt, info->u.f_cfg_conflict.ssid); + EVT_SET_SSV(&evt, info->u.f_cfg_conflict.ssv); + break; + /* rest is not implemented */ + case SMMU_EVT_F_BAD_ATS_TREQ: + case SMMU_EVT_F_TLB_CONFLICT: + case SMMU_EVT_E_PAGE_REQ: + default: + g_assert_not_reached(); } =20 - queue_write(q, evt); - - if (smmuv3_q_empty(q)) { - smmuv3_trigger_irq(s, SMMU_IRQ_EVTQ, 0); + trace_smmuv3_record_event(smmu_event_string(info->type), info->sid); + r =3D smmuv3_write_eventq(s, &evt); + if (r !=3D MEMTX_OK) { + smmuv3_trigger_irq(s, SMMU_IRQ_GERROR, R_GERROR_EVENTQ_ABT_ERR_MAS= K); } + info->recorded =3D true; } =20 static void smmuv3_init_regs(SMMUv3State *s) diff --git a/hw/arm/trace-events b/hw/arm/trace-events index 781542a..9936e10 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -29,3 +29,4 @@ smmuv3_write_mmio(uint64_t addr, uint64_t val, unsigned s= ize, uint32_t r) "addr: smmuv3_write_mmio_idr(uint64_t addr, uint64_t val) "write to RO/Unimpl reg= 0x%lx val64:0x%lx" smmuv3_write_mmio_evtq_cons_bef_clear(uint32_t prod, uint32_t cons, uint8_= t prod_wrap, uint8_t cons_wrap) "Before clearing interrupt prod:0x%x cons:0= x%x prod.w:%d cons.w:%d" smmuv3_write_mmio_evtq_cons_after_clear(uint32_t prod, uint32_t cons, uint= 8_t prod_wrap, uint8_t cons_wrap) "after clearing interrupt prod:0x%x cons:= 0x%x prod.w:%d cons.w:%d" +smmuv3_record_event(const char *type, uint32_t sid) "%s sid=3D%d" --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523519693238360.18888524728754; Thu, 12 Apr 2018 00:54:53 -0700 (PDT) Received: from localhost ([::1]:44688 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6X4G-0004q8-Bn for importer@patchew.org; Thu, 12 Apr 2018 03:54:52 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49516) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wos-0006rZ-Im for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6Woq-0003Is-3K for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:58 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:35946 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6Wok-0003F2-9c; Thu, 12 Apr 2018 03:38:50 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B3D46EBFE5; Thu, 12 Apr 2018 07:38:49 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0E17E215CDC6; Thu, 12 Apr 2018 07:38:46 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:38:00 +0200 Message-Id: <1523518688-26674-10-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Thu, 12 Apr 2018 07:38:49 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Thu, 12 Apr 2018 07:38:49 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 09/17] hw/arm/smmuv3: Implement translate callback 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This patch implements the IOMMU Memory Region translate() callback. Most of the code relates to the translation configuration decoding and check (STE, CD). Signed-off-by: Eric Auger Signed-off-by: Prem Mallappa --- v10 -> v11: - in case of error, print ret instead of the event.type which may be set to OK if recording is off. This was misleading. - trace point at the output of translate, only in case of sucess v9 -> v10: - s/hwaddr/uint64_t in trace-events - use qemu_log_mask(LOG_UNIMP, in some situations where assert was done - report bad_ste if stage2 is found in STE - check TTB does not exceed IPS - fix oas2bits, CD_TTB - tg2granule handles illegal cases - convert L1STD_L2PTR macro into an inline function - added S1STALLD, CD_A, CD_S, CD_HA, CD_HD checks v8 -> v9: - use SMMU_EVENT_STRING macro - get rid of last erro_report's - decode asid - handle config abort before ptw - add 64-bit single-copy atomic comment v7 -> v8: - use address_space_rw - s/Ste/STE, s/Cd/CD - use dma_memory_read - remove everything related to stage 2 - collect data for both TTx - renamings - pass the event handle all along the config decoding path - decode tbi, ars --- hw/arm/smmuv3-internal.h | 160 +++++++++++++++++++++ hw/arm/smmuv3.c | 359 +++++++++++++++++++++++++++++++++++++++++++= ++++ hw/arm/trace-events | 9 ++ 3 files changed, 528 insertions(+) diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index 8e546bf..ef6dd76 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h @@ -446,4 +446,164 @@ typedef struct SMMUEventInfo { =20 void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *event); =20 +/* Configuration Data */ + +/* STE Level 1 Descriptor */ +typedef struct STEDesc { + uint32_t word[2]; +} STEDesc; + +/* CD Level 1 Descriptor */ +typedef struct CDDesc { + uint32_t word[2]; +} CDDesc; + +/* Stream Table Entry(STE) */ +typedef struct STE { + uint32_t word[16]; +} STE; + +/* Context Descriptor(CD) */ +typedef struct CD { + uint32_t word[16]; +} CD; + +/* STE fields */ + +#define STE_VALID(x) extract32((x)->word[0], 0, 1) + +#define STE_CONFIG(x) extract32((x)->word[0], 1, 3) +#define STE_CFG_S1_ENABLED(config) (config & 0x1) +#define STE_CFG_S2_ENABLED(config) (config & 0x2) +#define STE_CFG_ABORT(config) (!(config & 0x4)) +#define STE_CFG_BYPASS(config) (config =3D=3D 0x4) + +#define STE_S1FMT(x) extract32((x)->word[0], 4 , 2) +#define STE_S1CDMAX(x) extract32((x)->word[1], 27, 5) +#define STE_S1STALLD(x) extract32((x)->word[2], 27, 1) +#define STE_EATS(x) extract32((x)->word[2], 28, 2) +#define STE_STRW(x) extract32((x)->word[2], 30, 2) +#define STE_S2VMID(x) extract32((x)->word[4], 0 , 16) +#define STE_S2T0SZ(x) extract32((x)->word[5], 0 , 6) +#define STE_S2SL0(x) extract32((x)->word[5], 6 , 2) +#define STE_S2TG(x) extract32((x)->word[5], 14, 2) +#define STE_S2PS(x) extract32((x)->word[5], 16, 3) +#define STE_S2AA64(x) extract32((x)->word[5], 19, 1) +#define STE_S2HD(x) extract32((x)->word[5], 24, 1) +#define STE_S2HA(x) extract32((x)->word[5], 25, 1) +#define STE_S2S(x) extract32((x)->word[5], 26, 1) +#define STE_CTXPTR(x) \ + ({ \ + unsigned long addr; \ + addr =3D (uint64_t)extract32((x)->word[1], 0, 16) << 32; \ + addr |=3D (uint64_t)((x)->word[0] & 0xffffffc0); \ + addr; \ + }) + +#define STE_S2TTB(x) \ + ({ \ + unsigned long addr; \ + addr =3D (uint64_t)extract32((x)->word[7], 0, 16) << 32; \ + addr |=3D (uint64_t)((x)->word[6] & 0xfffffff0); \ + addr; \ + }) + +static inline int oas2bits(int oas_field) +{ + switch (oas_field) { + case 0: + return 32; + case 1: + return 36; + case 2: + return 40; + case 3: + return 42; + case 4: + return 44; + case 5: + return 48; + } + return -1; +} + +static inline int pa_range(STE *ste) +{ + int oas_field =3D MIN(STE_S2PS(ste), SMMU_IDR5_OAS); + + if (!STE_S2AA64(ste)) { + return 40; + } + + return oas2bits(oas_field); +} + +#define MAX_PA(ste) ((1 << pa_range(ste)) - 1) + +/* CD fields */ + +#define CD_VALID(x) extract32((x)->word[0], 30, 1) +#define CD_ASID(x) extract32((x)->word[1], 16, 16) +#define CD_TTB(x, sel) \ + ({ \ + uint64_t hi, lo; \ + hi =3D extract32((x)->word[(sel) * 2 + 3], 0, 19); \ + hi <<=3D 32; \ + lo =3D (x)->word[(sel) * 2 + 2] & ~0xfULL; \ + hi | lo; \ + }) + +#define CD_TSZ(x, sel) extract32((x)->word[0], (16 * (sel)) + 0, 6) +#define CD_TG(x, sel) extract32((x)->word[0], (16 * (sel)) + 6, 2) +#define CD_EPD(x, sel) extract32((x)->word[0], (16 * (sel)) + 14, 1) +#define CD_ENDI(x) extract32((x)->word[0], 15, 1) +#define CD_IPS(x) extract32((x)->word[1], 0 , 3) +#define CD_TBI(x) extract32((x)->word[1], 6 , 2) +#define CD_HD(x) extract32((x)->word[1], 10 , 1) +#define CD_HA(x) extract32((x)->word[1], 11 , 1) +#define CD_S(x) extract32((x)->word[1], 12, 1) +#define CD_R(x) extract32((x)->word[1], 13, 1) +#define CD_A(x) extract32((x)->word[1], 14, 1) +#define CD_AARCH64(x) extract32((x)->word[1], 9 , 1) + +#define CDM_VALID(x) ((x)->word[0] & 0x1) + +static inline int is_cd_valid(SMMUv3State *s, STE *ste, CD *cd) +{ + return CD_VALID(cd); +} + +/** + * tg2granule - Decodes the CD translation granule size field according + * to the ttbr in use + * @bits: TG0/1 fields + * @ttbr: ttbr index in use + */ +static inline int tg2granule(int bits, int ttbr) +{ + switch (bits) { + case 0: + return ttbr ? 0 : 12; + case 1: + return ttbr ? 14 : 16; + case 2: + return ttbr ? 12 : 14; + case 3: + return ttbr ? 16 : 0; + default: + return 0; + } +} + +static inline uint64_t l1std_l2ptr(STEDesc *desc) +{ + uint64_t hi, lo; + + hi =3D desc->word[1]; + lo =3D desc->word[0] & ~0x1fULL; + return hi << 32 | lo; +} + +#define L1STD_SPAN(stm) (extract32((stm)->word[0], 0, 4)) + #endif diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 2ef1bfc..4be676b 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -270,6 +270,362 @@ static void smmuv3_init_regs(SMMUv3State *s) s->sid_split =3D 0; } =20 +static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf, + SMMUEventInfo *event) +{ + int ret; + + trace_smmuv3_get_ste(addr); + /* TODO: guarantee 64-bit single-copy atomicity */ + ret =3D dma_memory_read(&address_space_memory, addr, + (void *)buf, sizeof(*buf)); + if (ret !=3D MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, + "Cannot fetch pte at address=3D0x%"PRIx64"\n", addr); + event->type =3D SMMU_EVT_F_STE_FETCH; + event->u.f_ste_fetch.addr =3D addr; + return -EINVAL; + } + return 0; + +} + +/* @ssid > 0 not supported yet */ +static int smmu_get_cd(SMMUv3State *s, STE *ste, uint32_t ssid, + CD *buf, SMMUEventInfo *event) +{ + dma_addr_t addr =3D STE_CTXPTR(ste); + int ret; + + trace_smmuv3_get_cd(addr); + /* TODO: guarantee 64-bit single-copy atomicity */ + ret =3D dma_memory_read(&address_space_memory, addr, + (void *)buf, sizeof(*buf)); + if (ret !=3D MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, + "Cannot fetch pte at address=3D0x%"PRIx64"\n", addr); + event->type =3D SMMU_EVT_F_CD_FETCH; + event->u.f_ste_fetch.addr =3D addr; + return -EINVAL; + } + return 0; +} + +/* Returns <0 if the caller has no need to purse the translation */ +static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg, + STE *ste, SMMUEventInfo *event) +{ + uint32_t config =3D STE_CONFIG(ste); + int ret =3D -EINVAL; + + if (STE_CFG_ABORT(config)) { + cfg->aborted =3D true; /* abort but don't record any event */ + return ret; + } + + if (STE_CFG_BYPASS(config)) { + cfg->bypassed =3D true; + return ret; + } + + if (!STE_VALID(ste)) { + goto bad_ste; + } + + if (STE_CFG_S2_ENABLED(config)) { + qemu_log_mask(LOG_UNIMP, "SMMUv3 does not support stage 2 yet\n"); + goto bad_ste; + } + + if (STE_S1CDMAX(ste) !=3D 0) { + qemu_log_mask(LOG_UNIMP, + "SMMUv3 does not support multiple context descriptor= s yet\n"); + goto bad_ste; + } + + if (STE_S1STALLD(ste)) { + qemu_log_mask(LOG_UNIMP, + "SMMUv3 S1 stalling fault model not allowed yet\n"); + goto bad_ste; + } + return 0; + +bad_ste: + event->type =3D SMMU_EVT_C_BAD_STE; + return -EINVAL; +} + +/** + * smmu_find_ste - Return the stream table entry associated + * to the sid + * + * @s: smmuv3 handle + * @sid: stream ID + * @ste: returned stream table entry + * @event: handle to an event info + * + * Supports linear and 2-level stream table + * Return 0 on success, -EINVAL otherwise + */ +static int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, + SMMUEventInfo *event) +{ + dma_addr_t addr; + int ret; + + trace_smmuv3_find_ste(sid, s->features, s->sid_split); + /* Check SID range */ + if (sid > (1 << SMMU_IDR1_SIDSIZE)) { + event->type =3D SMMU_EVT_C_BAD_STREAMID; + return -EINVAL; + } + if (s->features & SMMU_FEATURE_2LVL_STE) { + int l1_ste_offset, l2_ste_offset, max_l2_ste, span; + dma_addr_t strtab_base, l1ptr, l2ptr; + STEDesc l1std; + + strtab_base =3D s->strtab_base & SMMU_BASE_ADDR_MASK; + l1_ste_offset =3D sid >> s->sid_split; + l2_ste_offset =3D sid & ((1 << s->sid_split) - 1); + l1ptr =3D (dma_addr_t)(strtab_base + l1_ste_offset * sizeof(l1std)= ); + /* TODO: guarantee 64-bit single-copy atomicity */ + ret =3D dma_memory_read(&address_space_memory, l1ptr, + (uint8_t *)&l1std, sizeof(l1std)); + if (ret !=3D MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, + "Could not read L1PTR at 0X%"PRIx64"\n", l1ptr); + event->type =3D SMMU_EVT_F_STE_FETCH; + event->u.f_ste_fetch.addr =3D l1ptr; + return -EINVAL; + } + + span =3D L1STD_SPAN(&l1std); + + if (!span) { + /* l2ptr is not valid */ + qemu_log_mask(LOG_GUEST_ERROR, + "invalid sid=3D%d (L1STD span=3D0)\n", sid); + event->type =3D SMMU_EVT_C_BAD_STREAMID; + return -EINVAL; + } + max_l2_ste =3D (1 << span) - 1; + l2ptr =3D l1std_l2ptr(&l1std); + trace_smmuv3_find_ste_2lvl(s->strtab_base, l1ptr, l1_ste_offset, + l2ptr, l2_ste_offset, max_l2_ste); + if (l2_ste_offset > max_l2_ste) { + qemu_log_mask(LOG_GUEST_ERROR, + "l2_ste_offset=3D%d > max_l2_ste=3D%d\n", + l2_ste_offset, max_l2_ste); + event->type =3D SMMU_EVT_C_BAD_STE; + return -EINVAL; + } + addr =3D l2ptr + l2_ste_offset * sizeof(*ste); + } else { + addr =3D s->strtab_base + sid * sizeof(*ste); + } + + if (smmu_get_ste(s, addr, ste, event)) { + return -EINVAL; + } + + return 0; +} + +static int decode_cd(SMMUTransCfg *cfg, CD *cd, SMMUEventInfo *event) +{ + int ret =3D -EINVAL; + int i; + + if (!CD_VALID(cd) || !CD_AARCH64(cd)) { + goto bad_cd; + } + + /* we support only those at the moment */ + cfg->aa64 =3D true; + cfg->stage =3D 1; + + cfg->oas =3D oas2bits(CD_IPS(cd)); + cfg->oas =3D MIN(oas2bits(SMMU_IDR5_OAS), cfg->oas); + cfg->tbi =3D CD_TBI(cd); + cfg->asid =3D CD_ASID(cd); + + trace_smmuv3_decode_cd(cfg->oas); + + /* decode data dependent on TT */ + for (i =3D 0; i <=3D 1; i++) { + int tg, tsz; + SMMUTransTableInfo *tt =3D &cfg->tt[i]; + + cfg->tt[i].disabled =3D CD_EPD(cd, i); + if (cfg->tt[i].disabled) { + continue; + } + + if (!CD_A(cd)) { + goto bad_cd; /* SMMU_IDR0.TERM_MODEL =3D=3D 1 */ + } + if (CD_S(cd)) { + goto bad_cd; /* !STE_SECURE && SMMU_IDR0.STALL_MODEL =3D=3D 1 = */ + } + if (CD_HA(cd) || CD_HD(cd)) { + goto bad_cd; /* HTTU =3D 0 */ + } + + tsz =3D CD_TSZ(cd, i); + if (tsz < 16 || tsz > 39) { + goto bad_cd; + } + + tg =3D CD_TG(cd, i); + tt->granule_sz =3D tg2granule(tg, i); + if ((tt->granule_sz !=3D 12 && tt->granule_sz !=3D 16) || CD_ENDI(= cd)) { + goto bad_cd; + } + + tt->tsz =3D tsz; + tt->initial_level =3D 4 - (64 - tsz - 4) / (tt->granule_sz - 3); + tt->ttb =3D CD_TTB(cd, i); + if (tt->ttb & ~(MAKE_64BIT_MASK(0, cfg->oas))) { + goto bad_cd; + } + trace_smmuv3_decode_cd_tt(i, tt->tsz, tt->ttb, + tt->granule_sz, tt->initial_level); + } + + event->record_trans_faults =3D CD_R(cd); + + return 0; + +bad_cd: + event->type =3D SMMU_EVT_C_BAD_CD; + return ret; +} + +/** + * smmuv3_decode_config - Prepare the translation configuration + * for the @mr iommu region + * @mr: iommu memory region the translation config must be prepared for + * @cfg: output translation configuration which is populated through + * the different configuration decoding steps + * @event: must be zero'ed by the caller + * + * return < 0 if the translation needs to be aborted (@event is filled + * accordingly). Return 0 otherwise. + */ +static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg, + SMMUEventInfo *event) +{ + SMMUDevice *sdev =3D container_of(mr, SMMUDevice, iommu); + uint32_t sid =3D smmu_get_sid(sdev); + SMMUv3State *s =3D sdev->smmu; + int ret =3D -EINVAL; + STE ste; + CD cd; + + if (smmu_find_ste(s, sid, &ste, event)) { + return ret; + } + + if (decode_ste(s, cfg, &ste, event)) { + return ret; + } + + if (smmu_get_cd(s, &ste, 0 /* ssid */, &cd, event)) { + return ret; + } + + return decode_cd(cfg, &cd, event); +} + +static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr, + IOMMUAccessFlags flag) +{ + SMMUDevice *sdev =3D container_of(mr, SMMUDevice, iommu); + SMMUv3State *s =3D sdev->smmu; + uint32_t sid =3D smmu_get_sid(sdev); + SMMUEventInfo event =3D {.type =3D SMMU_EVT_OK, .sid =3D sid}; + SMMUPTWEventInfo ptw_info =3D {}; + SMMUTransCfg cfg =3D {}; + IOMMUTLBEntry entry =3D { + .target_as =3D &address_space_memory, + .iova =3D addr, + .translated_addr =3D addr, + .addr_mask =3D ~(hwaddr)0, + .perm =3D IOMMU_NONE, + }; + int ret =3D 0; + + if (!smmu_enabled(s)) { + goto out; + } + + ret =3D smmuv3_decode_config(mr, &cfg, &event); + if (ret) { + goto out; + } + + if (cfg.aborted) { + goto out; + } + + ret =3D smmu_ptw(&cfg, addr, flag, &entry, &ptw_info); + if (ret) { + switch (ptw_info.type) { + case SMMU_PTW_ERR_WALK_EABT: + event.type =3D SMMU_EVT_F_WALK_EABT; + event.u.f_walk_eabt.addr =3D addr; + event.u.f_walk_eabt.rnw =3D flag & 0x1; + event.u.f_walk_eabt.class =3D 0x1; + event.u.f_walk_eabt.addr2 =3D ptw_info.addr; + break; + case SMMU_PTW_ERR_TRANSLATION: + if (event.record_trans_faults) { + event.type =3D SMMU_EVT_F_TRANSLATION; + event.u.f_translation.addr =3D addr; + event.u.f_translation.rnw =3D flag & 0x1; + } + break; + case SMMU_PTW_ERR_ADDR_SIZE: + if (event.record_trans_faults) { + event.type =3D SMMU_EVT_F_ADDR_SIZE; + event.u.f_addr_size.addr =3D addr; + event.u.f_addr_size.rnw =3D flag & 0x1; + } + break; + case SMMU_PTW_ERR_ACCESS: + if (event.record_trans_faults) { + event.type =3D SMMU_EVT_F_ACCESS; + event.u.f_access.addr =3D addr; + event.u.f_access.rnw =3D flag & 0x1; + } + break; + case SMMU_PTW_ERR_PERMISSION: + if (event.record_trans_faults) { + event.type =3D SMMU_EVT_F_PERMISSION; + event.u.f_permission.addr =3D addr; + event.u.f_permission.rnw =3D flag & 0x1; + } + break; + default: + g_assert_not_reached(); + } + } +out: + if (ret) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s translation failed for iova=3D0x%"PRIx64"(%d)\n", + mr->parent_obj.name, addr, ret); + entry.perm =3D IOMMU_NONE; + smmuv3_record_event(s, &event); + } else if (!cfg.aborted) { + entry.perm =3D flag; + trace_smmuv3_translate(mr->parent_obj.name, sid, addr, + entry.translated_addr, entry.perm); + } + + return entry; +} + static int smmuv3_cmdq_consume(SMMUv3State *s) { SMMUCmdError cmd_error =3D SMMU_CERROR_NONE; @@ -794,6 +1150,9 @@ static void smmuv3_class_init(ObjectClass *klass, void= *data) static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, void *data) { + IOMMUMemoryRegionClass *imrc =3D IOMMU_MEMORY_REGION_CLASS(klass); + + imrc->translate =3D smmuv3_translate; } =20 static const TypeInfo smmuv3_type_info =3D { diff --git a/hw/arm/trace-events b/hw/arm/trace-events index 9936e10..032de48 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -30,3 +30,12 @@ smmuv3_write_mmio_idr(uint64_t addr, uint64_t val) "writ= e to RO/Unimpl reg 0x%lx smmuv3_write_mmio_evtq_cons_bef_clear(uint32_t prod, uint32_t cons, uint8_= t prod_wrap, uint8_t cons_wrap) "Before clearing interrupt prod:0x%x cons:0= x%x prod.w:%d cons.w:%d" smmuv3_write_mmio_evtq_cons_after_clear(uint32_t prod, uint32_t cons, uint= 8_t prod_wrap, uint8_t cons_wrap) "after clearing interrupt prod:0x%x cons:= 0x%x prod.w:%d cons.w:%d" smmuv3_record_event(const char *type, uint32_t sid) "%s sid=3D%d" +smmuv3_find_ste(uint16_t sid, uint32_t features, uint16_t sid_split) "SID:= 0x%x features:0x%x, sid_split:0x%x" +smmuv3_find_ste_2lvl(uint64_t strtab_base, uint64_t l1ptr, int l1_ste_offs= et, uint64_t l2ptr, int l2_ste_offset, int max_l2_ste) "strtab_base:0x%lx l= 1ptr:0x%"PRIx64" l1_off:0x%x, l2ptr:0x%"PRIx64" l2_off:0x%x max_l2_ste:%d" +smmuv3_get_ste(uint64_t addr) "STE addr: 0x%"PRIx64 +smmuv3_translate_bypass(const char *n, uint16_t sid, uint64_t addr, bool i= s_write) "%s sid=3D%d bypass iova:0x%"PRIx64" is_write=3D%d" +smmuv3_translate_in(uint16_t sid, int pci_bus_num, uint64_t strtab_base) "= SID:0x%x bus:%d strtab_base:0x%"PRIx64 +smmuv3_get_cd(uint64_t addr) "CD addr: 0x%"PRIx64 +smmuv3_translate(const char *n, uint16_t sid, uint64_t iova, uint64_t tran= slated, int perm) "%s sid=3D%d iova=3D0x%"PRIx64" translated=3D0x%"PRIx64" = perm=3D0x%x" +smmuv3_decode_cd(uint32_t oas) "oas=3D%d" +smmuv3_decode_cd_tt(int i, uint32_t tsz, uint64_t ttb, uint32_t granule_sz= , int initial_level) "TT[%d]:tsz:%d ttb:0x%"PRIx64" granule_sz:%d, initial_= level =3D %d" --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523519239870433.311283013334; Thu, 12 Apr 2018 00:47:19 -0700 (PDT) Received: from localhost ([::1]:44121 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wwn-0006FQ-Ho for importer@patchew.org; Thu, 12 Apr 2018 03:47:09 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49488) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wor-0006rW-K5 for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6Woq-0003JO-T5 for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:38:57 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34388 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6Won-0003Go-1V; Thu, 12 Apr 2018 03:38:53 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8CE0D4075A67; Thu, 12 Apr 2018 07:38:52 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id F2DDF215CDC6; Thu, 12 Apr 2018 07:38:49 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:38:01 +0200 Message-Id: <1523518688-26674-11-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Thu, 12 Apr 2018 07:38:52 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Thu, 12 Apr 2018 07:38:52 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 10/17] hw/arm/smmuv3: Abort on vfio or vhost case 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" At the moment, the SMMUv3 does not support notification on TLB invalidation. So let's log an error as soon as such notifier gets enabled. Signed-off-by: Eric Auger Reviewed-by: Peter Maydell --- hw/arm/smmuv3.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 4be676b..6e0d7ad 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -1147,12 +1147,23 @@ static void smmuv3_class_init(ObjectClass *klass, v= oid *data) dc->realize =3D smmu_realize; } =20 +static void smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, + IOMMUNotifierFlag old, + IOMMUNotifierFlag new) +{ + if (old =3D=3D IOMMU_NOTIFIER_NONE) { + warn_report("SMMUV3 does not support vhost/vfio integration yet: " + "devices of those types will not function properly"); + } +} + static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, void *data) { IOMMUMemoryRegionClass *imrc =3D IOMMU_MEMORY_REGION_CLASS(klass); =20 imrc->translate =3D smmuv3_translate; + imrc->notify_flag_changed =3D smmuv3_notify_flag_changed; } =20 static const TypeInfo smmuv3_type_info =3D { --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523519441738487.554846009525; Thu, 12 Apr 2018 00:50:41 -0700 (PDT) Received: from localhost ([::1]:44149 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6X0D-0000qC-1L for importer@patchew.org; Thu, 12 Apr 2018 03:50:41 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49546) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wou-0006uw-8M for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6Wot-0003La-9P for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:00 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:51388 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6Woq-0003IL-0Z; Thu, 12 Apr 2018 03:38:56 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6C5BE4023BAD; Thu, 12 Apr 2018 07:38:55 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id D0C81215CDC6; Thu, 12 Apr 2018 07:38:52 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:38:02 +0200 Message-Id: <1523518688-26674-12-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Thu, 12 Apr 2018 07:38:55 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Thu, 12 Apr 2018 07:38:55 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 11/17] target/arm/kvm: Translate the MSI doorbell in kvm_arch_fixup_msi_route 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" In case the MSI is translated by an IOMMU we need to fixup the MSI route with the translated address. Signed-off-by: Eric Auger Signed-off-by: Bharat Bhushan --- v9 -> v10: - use address_space_translate v5 -> v6: - use IOMMUMemoryRegionClass API --- target/arm/kvm.c | 27 +++++++++++++++++++++++++++ target/arm/trace-events | 3 +++ 2 files changed, 30 insertions(+) diff --git a/target/arm/kvm.c b/target/arm/kvm.c index ecc39ac..c6f6aa8 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -20,8 +20,10 @@ #include "sysemu/kvm.h" #include "kvm_arm.h" #include "cpu.h" +#include "trace.h" #include "internals.h" #include "hw/arm/arm.h" +#include "hw/pci/pci.h" #include "exec/memattrs.h" #include "exec/address-spaces.h" #include "hw/boards.h" @@ -649,6 +651,31 @@ int kvm_arm_vgic_probe(void) int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, uint64_t address, uint32_t data, PCIDevice *d= ev) { + AddressSpace *as =3D pci_device_iommu_address_space(dev); + hwaddr xlat, len, doorbell_gpa; + MemoryRegionSection mrs; + MemoryRegion *mr; + + if (as =3D=3D &address_space_memory) { + return 0; + } + + /* MSI doorbell address is translated by an IOMMU */ + + rcu_read_lock(); + mr =3D address_space_translate(as, address, &xlat, &len, true); + if (!mr) { + return 1; + } + mrs =3D memory_region_find(mr, xlat, 0); + doorbell_gpa =3D mrs.offset_within_address_space; + rcu_read_unlock(); + + route->u.msi.address_lo =3D doorbell_gpa; + route->u.msi.address_hi =3D doorbell_gpa >> 32; + + trace_kvm_arm_fixup_msi_route(address, doorbell_gpa); + return 0; } =20 diff --git a/target/arm/trace-events b/target/arm/trace-events index 9e37131..6b759f9 100644 --- a/target/arm/trace-events +++ b/target/arm/trace-events @@ -8,3 +8,6 @@ arm_gt_tval_write(int timer, uint64_t value) "gt_tval_write= : timer %d value 0x%" arm_gt_ctl_write(int timer, uint64_t value) "gt_ctl_write: timer %d value = 0x%" PRIx64 arm_gt_imask_toggle(int timer, int irqstate) "gt_ctl_write: timer %d IMASK= toggle, new irqstate %d" arm_gt_cntvoff_write(uint64_t value) "gt_cntvoff_write: value 0x%" PRIx64 + +# target/arm/kvm.c +kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova =3D 0x%"PRI= x64" is translated into 0x%"PRIx64 --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523519098868671.1093488893398; Thu, 12 Apr 2018 00:44:58 -0700 (PDT) Received: from localhost ([::1]:44099 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wua-0003h0-Tu for importer@patchew.org; Thu, 12 Apr 2018 03:44:52 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49639) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wp0-00073P-DS for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6Wow-0003Nl-1f for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:06 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34410 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6Wos-0003Ku-Rr; Thu, 12 Apr 2018 03:38:58 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 56DC34075A67; Thu, 12 Apr 2018 07:38:58 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id B10FA215CDC6; Thu, 12 Apr 2018 07:38:55 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:38:03 +0200 Message-Id: <1523518688-26674-13-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Thu, 12 Apr 2018 07:38:58 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Thu, 12 Apr 2018 07:38:58 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 12/17] hw/arm/virt: Add SMMUv3 to the virt board 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Prem Mallappa Add code to instantiate an smmuv3 in virt machine. A new iommu integer member is introduced in VirtMachineState to store the type of the iommu in use. Signed-off-by: Prem Mallappa Signed-off-by: Eric Auger Reviewed-by: Peter Maydell --- v9 -> v10: - add VirtIOMMUType - add Peter's R-b v7 -> v8: - integer iommu member - add primary-bus property v4 -> v5: - add dma-coherent property v2 -> v3: - vbi was removed. Use vms instead - migrate to new smmu binding format (iommu-map) - don't use appendprop anymore - add vms->smmu and guard instantiation with this latter - interrupts type changed to edge --- hw/arm/virt.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++= +++- include/hw/arm/virt.h | 10 ++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 94dcb12..1799702 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -58,6 +58,7 @@ #include "hw/smbios/smbios.h" #include "qapi/visitor.h" #include "standard-headers/linux/input.h" +#include "hw/arm/smmuv3.h" =20 #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ @@ -141,6 +142,7 @@ static const MemMapEntry a15memmap[] =3D { [VIRT_FW_CFG] =3D { 0x09020000, 0x00000018 }, [VIRT_GPIO] =3D { 0x09030000, 0x00001000 }, [VIRT_SECURE_UART] =3D { 0x09040000, 0x00001000 }, + [VIRT_SMMU] =3D { 0x09050000, 0x00020000 }, [VIRT_MMIO] =3D { 0x0a000000, 0x00000200 }, /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that siz= e */ [VIRT_PLATFORM_BUS] =3D { 0x0c000000, 0x02000000 }, @@ -161,6 +163,7 @@ static const int a15irqmap[] =3D { [VIRT_SECURE_UART] =3D 8, [VIRT_MMIO] =3D 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ [VIRT_GIC_V2M] =3D 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */ + [VIRT_SMMU] =3D 74, /* ...to 74 + NUM_SMMU_IRQS - 1 */ [VIRT_PLATFORM_BUS] =3D 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */ }; =20 @@ -942,7 +945,57 @@ static void create_pcie_irq_map(const VirtMachineState= *vms, 0x7 /* PCI irq */); } =20 -static void create_pcie(const VirtMachineState *vms, qemu_irq *pic) +static void create_smmu(const VirtMachineState *vms, qemu_irq *pic, + PCIBus *bus) +{ + char *node; + const char compat[] =3D "arm,smmu-v3"; + int irq =3D vms->irqmap[VIRT_SMMU]; + int i; + hwaddr base =3D vms->memmap[VIRT_SMMU].base; + hwaddr size =3D vms->memmap[VIRT_SMMU].size; + const char irq_names[] =3D "eventq\0priq\0cmdq-sync\0gerror"; + DeviceState *dev; + + if (vms->iommu !=3D VIRT_IOMMU_SMMUV3 || !vms->iommu_phandle) { + return; + } + + dev =3D qdev_create(NULL, "arm-smmuv3"); + + object_property_set_link(OBJECT(dev), OBJECT(bus), "primary-bus", + &error_abort); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + for (i =3D 0; i < NUM_SMMU_IRQS; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); + } + + node =3D g_strdup_printf("/smmuv3@%" PRIx64, base); + qemu_fdt_add_subnode(vms->fdt, node); + qemu_fdt_setprop(vms->fdt, node, "compatible", compat, sizeof(compat)); + qemu_fdt_setprop_sized_cells(vms->fdt, node, "reg", 2, base, 2, size); + + qemu_fdt_setprop_cells(vms->fdt, node, "interrupts", + GIC_FDT_IRQ_TYPE_SPI, irq , GIC_FDT_IRQ_FLAGS_EDGE_LO_HI, + GIC_FDT_IRQ_TYPE_SPI, irq + 1, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI, + GIC_FDT_IRQ_TYPE_SPI, irq + 2, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI, + GIC_FDT_IRQ_TYPE_SPI, irq + 3, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); + + qemu_fdt_setprop(vms->fdt, node, "interrupt-names", irq_names, + sizeof(irq_names)); + + qemu_fdt_setprop_cell(vms->fdt, node, "clocks", vms->clock_phandle); + qemu_fdt_setprop_string(vms->fdt, node, "clock-names", "apb_pclk"); + qemu_fdt_setprop(vms->fdt, node, "dma-coherent", NULL, 0); + + qemu_fdt_setprop_cell(vms->fdt, node, "#iommu-cells", 1); + + qemu_fdt_setprop_cell(vms->fdt, node, "phandle", vms->iommu_phandle); + g_free(node); +} + +static void create_pcie(VirtMachineState *vms, qemu_irq *pic) { hwaddr base_mmio =3D vms->memmap[VIRT_PCIE_MMIO].base; hwaddr size_mmio =3D vms->memmap[VIRT_PCIE_MMIO].size; @@ -1055,6 +1108,15 @@ static void create_pcie(const VirtMachineState *vms,= qemu_irq *pic) qemu_fdt_setprop_cell(vms->fdt, nodename, "#interrupt-cells", 1); create_pcie_irq_map(vms, vms->gic_phandle, irq, nodename); =20 + if (vms->iommu) { + vms->iommu_phandle =3D qemu_fdt_alloc_phandle(vms->fdt); + + create_smmu(vms, pic, pci->bus); + + qemu_fdt_setprop_cells(vms->fdt, nodename, "iommu-map", + 0x0, vms->iommu_phandle, 0x0, 0x10000); + } + g_free(nodename); } =20 diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index ba0c1a4..886372c 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -38,6 +38,7 @@ =20 #define NUM_GICV2M_SPIS 64 #define NUM_VIRTIO_TRANSPORTS 32 +#define NUM_SMMU_IRQS 4 =20 #define ARCH_GICV3_MAINT_IRQ 9 =20 @@ -59,6 +60,7 @@ enum { VIRT_GIC_V2M, VIRT_GIC_ITS, VIRT_GIC_REDIST, + VIRT_SMMU, VIRT_UART, VIRT_MMIO, VIRT_RTC, @@ -74,6 +76,12 @@ enum { VIRT_SECURE_MEM, }; =20 +typedef enum VirtIOMMUType { + VIRT_IOMMU_NONE, + VIRT_IOMMU_SMMUV3, + VIRT_IOMMU_VIRTIO, +} VirtIOMMUType; + typedef struct MemMapEntry { hwaddr base; hwaddr size; @@ -97,6 +105,7 @@ typedef struct { bool its; bool virt; int32_t gic_version; + VirtIOMMUType iommu; struct arm_boot_info bootinfo; const MemMapEntry *memmap; const int *irqmap; @@ -106,6 +115,7 @@ typedef struct { uint32_t clock_phandle; uint32_t gic_phandle; uint32_t msi_phandle; + uint32_t iommu_phandle; int psci_conduit; } VirtMachineState; =20 --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523519305901449.9916001793637; Thu, 12 Apr 2018 00:48:25 -0700 (PDT) Received: from localhost ([::1]:44133 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wy1-00077r-1g for importer@patchew.org; Thu, 12 Apr 2018 03:48:25 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49702) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wp3-00076L-9w for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6Wp1-0003RD-Sz for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:09 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:35588 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6Wov-0003NN-Nr; Thu, 12 Apr 2018 03:39:01 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3683381A88A0; Thu, 12 Apr 2018 07:39:01 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9A2CE215CDC6; Thu, 12 Apr 2018 07:38:58 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:38:04 +0200 Message-Id: <1523518688-26674-14-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 12 Apr 2018 07:39:01 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 12 Apr 2018 07:39:01 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 13/17] hw/arm/virt-acpi-build: Add smmuv3 node in IORT table 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Prem Mallappa This patch builds the smmuv3 node in the ACPI IORT table. The RID space of the root complex, which spans 0x0-0x10000 maps to streamid space 0x0-0x10000 in smmuv3, which in turn maps to deviceid space 0x0-0x10000 in the ITS group. The guest must feature the IOMMU probe deferral series (https://lkml.org/lkml/2017/4/10/214) which fixes streamid multiple lookup. This bug is not related to the SMMU emulation. Signed-off-by: Prem Mallappa Signed-off-by: Eric Auger Reviewed-by: Shannon Zhao --- v9 -> v10: - replaced vms->iommu tests by vms->iommu =3D=3D VIRT_IOMMU_SMMUV3 - Added Shannon's R-b v2 -> v3: - integrate into the existing IORT table made up of ITS, RC nodes - take into account vms->smmu - match linux actbl2.h acpi_iort_smmu_v3 field names --- hw/arm/virt-acpi-build.c | 55 +++++++++++++++++++++++++++++++++++++++--= ---- include/hw/acpi/acpi-defs.h | 15 +++++++++++++ 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index c7c6a57..92ceee9 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -393,19 +393,26 @@ build_rsdp(GArray *rsdp_table, BIOSLinker *linker, un= signed xsdt_tbl_offset) } =20 static void -build_iort(GArray *table_data, BIOSLinker *linker) +build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { - int iort_start =3D table_data->len; + int nb_nodes, iort_start =3D table_data->len; AcpiIortIdMapping *idmap; AcpiIortItsGroup *its; AcpiIortTable *iort; - size_t node_size, iort_length; + AcpiIortSmmu3 *smmu; + size_t node_size, iort_length, smmu_offset =3D 0; AcpiIortRC *rc; =20 iort =3D acpi_data_push(table_data, sizeof(*iort)); =20 + if (vms->iommu =3D=3D VIRT_IOMMU_SMMUV3) { + nb_nodes =3D 3; /* RC, ITS, SMMUv3 */ + } else { + nb_nodes =3D 2; /* RC, ITS */ + } + iort_length =3D sizeof(*iort); - iort->node_count =3D cpu_to_le32(2); /* RC and ITS nodes */ + iort->node_count =3D cpu_to_le32(nb_nodes); iort->node_offset =3D cpu_to_le32(sizeof(*iort)); =20 /* ITS group node */ @@ -418,6 +425,34 @@ build_iort(GArray *table_data, BIOSLinker *linker) its->its_count =3D cpu_to_le32(1); its->identifiers[0] =3D 0; /* MADT translation_id */ =20 + if (vms->iommu =3D=3D VIRT_IOMMU_SMMUV3) { + int irq =3D vms->irqmap[VIRT_SMMU]; + + /* SMMUv3 node */ + smmu_offset =3D iort->node_offset + node_size; + node_size =3D sizeof(*smmu) + sizeof(*idmap); + iort_length +=3D node_size; + smmu =3D acpi_data_push(table_data, node_size); + + smmu->type =3D ACPI_IORT_NODE_SMMU_V3; + smmu->length =3D cpu_to_le16(node_size); + smmu->mapping_count =3D cpu_to_le32(1); + smmu->mapping_offset =3D cpu_to_le32(sizeof(*smmu)); + smmu->base_address =3D cpu_to_le64(vms->memmap[VIRT_SMMU].base); + smmu->event_gsiv =3D cpu_to_le32(irq); + smmu->pri_gsiv =3D cpu_to_le32(irq + 1); + smmu->gerr_gsiv =3D cpu_to_le32(irq + 2); + smmu->sync_gsiv =3D cpu_to_le32(irq + 3); + + /* Identity RID mapping covering the whole input RID range */ + idmap =3D &smmu->id_mapping_array[0]; + idmap->input_base =3D 0; + idmap->id_count =3D cpu_to_le32(0xFFFF); + idmap->output_base =3D 0; + /* output IORT node is the ITS group node (the first node) */ + idmap->output_reference =3D cpu_to_le32(iort->node_offset); + } + /* Root Complex Node */ node_size =3D sizeof(*rc) + sizeof(*idmap); iort_length +=3D node_size; @@ -438,8 +473,14 @@ build_iort(GArray *table_data, BIOSLinker *linker) idmap->input_base =3D 0; idmap->id_count =3D cpu_to_le32(0xFFFF); idmap->output_base =3D 0; - /* output IORT node is the ITS group node (the first node) */ - idmap->output_reference =3D cpu_to_le32(iort->node_offset); + + if (vms->iommu =3D=3D VIRT_IOMMU_SMMUV3) { + /* output IORT node is the smmuv3 node */ + idmap->output_reference =3D cpu_to_le32(smmu_offset); + } else { + /* output IORT node is the ITS group node (the first node) */ + idmap->output_reference =3D cpu_to_le32(iort->node_offset); + } =20 iort->length =3D cpu_to_le32(iort_length); =20 @@ -777,7 +818,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTa= bles *tables) =20 if (its_class_name() && !vmc->no_its) { acpi_add_table(table_offsets, tables_blob); - build_iort(tables_blob, tables->linker); + build_iort(tables_blob, tables->linker, vms); } =20 /* XSDT is pointed to by RSDP */ diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index 5955eb4..af8e023 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -628,6 +628,21 @@ struct AcpiIortItsGroup { } QEMU_PACKED; typedef struct AcpiIortItsGroup AcpiIortItsGroup; =20 +struct AcpiIortSmmu3 { + ACPI_IORT_NODE_HEADER_DEF + uint64_t base_address; + uint32_t flags; + uint32_t reserved2; + uint64_t vatos_address; + uint32_t model; + uint32_t event_gsiv; + uint32_t pri_gsiv; + uint32_t gerr_gsiv; + uint32_t sync_gsiv; + AcpiIortIdMapping id_mapping_array[0]; +} QEMU_PACKED; +typedef struct AcpiIortSmmu3 AcpiIortSmmu3; + struct AcpiIortRC { ACPI_IORT_NODE_HEADER_DEF AcpiIortMemoryAccess memory_properties; --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523519948547851.7950704612779; Thu, 12 Apr 2018 00:59:08 -0700 (PDT) Received: from localhost ([::1]:45053 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6X8I-0008Qm-Qo for importer@patchew.org; Thu, 12 Apr 2018 03:59:02 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49696) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wp3-000764-0m for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6Wp2-0003RT-5q for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:09 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:35648 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6Woy-0003P7-S9; Thu, 12 Apr 2018 03:39:04 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 55B1281A88CD; Thu, 12 Apr 2018 07:39:04 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id 79704215CDC6; Thu, 12 Apr 2018 07:39:01 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:38:05 +0200 Message-Id: <1523518688-26674-15-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 12 Apr 2018 07:39:04 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 12 Apr 2018 07:39:04 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 14/17] hw/arm/virt: Introduce the iommu option 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" ARM virt machine now exposes a new "iommu" option. The SMMUv3 IOMMU is instantiated using -machine virt,iommu=3Dsmmuv3. Signed-off-by: Eric Auger Signed-off-by: Prem Mallappa Reviewed-by: Peter Maydell --- v9 -> v10: - remove no_iommu v7 -> v8: - Revert to machine option, now dubbed "iommu", preparing for virtio instantiation. v5 -> v6: machine 2_11 --- hw/arm/virt.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 1799702..a3398d6 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1560,6 +1560,34 @@ static void virt_set_gic_version(Object *obj, const = char *value, Error **errp) } } =20 +static char *virt_get_iommu(Object *obj, Error **errp) +{ + VirtMachineState *vms =3D VIRT_MACHINE(obj); + + switch (vms->iommu) { + case VIRT_IOMMU_NONE: + return g_strdup("none"); + case VIRT_IOMMU_SMMUV3: + return g_strdup("smmuv3"); + default: + g_assert_not_reached(); + } +} + +static void virt_set_iommu(Object *obj, const char *value, Error **errp) +{ + VirtMachineState *vms =3D VIRT_MACHINE(obj); + + if (!strcmp(value, "smmuv3")) { + vms->iommu =3D VIRT_IOMMU_SMMUV3; + } else if (!strcmp(value, "none")) { + vms->iommu =3D VIRT_IOMMU_NONE; + } else { + error_setg(errp, "Invalid iommu value"); + error_append_hint(errp, "Valid values are none, smmuv3.\n"); + } +} + static CpuInstanceProperties virt_cpu_index_to_props(MachineState *ms, unsigned cpu_index) { @@ -1692,6 +1720,14 @@ static void virt_2_12_instance_init(Object *obj) NULL); } =20 + /* Default disallows iommu instantiation */ + vms->iommu =3D VIRT_IOMMU_NONE; + object_property_add_str(obj, "iommu", virt_get_iommu, virt_set_iommu, = NULL); + object_property_set_description(obj, "iommu", + "Set the IOMMU model among " + "none, smmuv3 (default none)", + NULL); + vms->memmap =3D a15memmap; vms->irqmap =3D a15irqmap; } --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523519383389451.5824658514547; Thu, 12 Apr 2018 00:49:43 -0700 (PDT) Received: from localhost ([::1]:44137 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6WzG-0008CM-Ho for importer@patchew.org; Thu, 12 Apr 2018 03:49:42 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49780) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6Wp6-00079p-Q2 for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:17 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6Wp5-0003UF-90 for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:12 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:56830 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6Wp1-0003Qr-Mb; Thu, 12 Apr 2018 03:39:07 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 355AD722C3; Thu, 12 Apr 2018 07:39:07 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id 99678215CDC6; Thu, 12 Apr 2018 07:39:04 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:38:06 +0200 Message-Id: <1523518688-26674-16-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Thu, 12 Apr 2018 07:39:07 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Thu, 12 Apr 2018 07:39:07 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 15/17] hw/arm/smmuv3: Cache/invalidate config data 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Let's cache config data to avoid fetching and parsing STE/CD structures on each translation. We invalidate them on data structure invalidation commands. Signed-off-by: Eric Auger --- hw/arm/smmu-common.c | 24 +++++++- hw/arm/smmuv3.c | 129 +++++++++++++++++++++++++++++++++++++++= +--- hw/arm/trace-events | 6 ++ include/hw/arm/smmu-common.h | 3 + include/hw/arm/smmuv3.h | 1 + 5 files changed, 152 insertions(+), 11 deletions(-) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 6a58948..c271a28 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -297,6 +297,24 @@ static AddressSpace *smmu_find_add_as(PCIBus *bus, voi= d *opaque, int devfn) return &sdev->as; } =20 +IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid) +{ + uint8_t bus_n, devfn; + SMMUPciBus *smmu_bus; + SMMUDevice *smmu; + + bus_n =3D PCI_BUS_NUM(sid); + smmu_bus =3D smmu_find_smmu_pcibus(s, bus_n); + if (smmu_bus) { + devfn =3D sid & 0x7; + smmu =3D smmu_bus->pbdev[devfn]; + if (smmu) { + return &smmu->iommu; + } + } + return NULL; +} + static void smmu_base_realize(DeviceState *dev, Error **errp) { SMMUState *s =3D ARM_SMMU(dev); @@ -308,7 +326,7 @@ static void smmu_base_realize(DeviceState *dev, Error *= *errp) error_propagate(errp, local_err); return; } - + s->configs =3D g_hash_table_new_full(NULL, NULL, NULL, g_free); s->smmu_pcibus_by_busptr =3D g_hash_table_new(NULL, NULL); =20 if (s->primary_bus) { @@ -320,7 +338,9 @@ static void smmu_base_realize(DeviceState *dev, Error *= *errp) =20 static void smmu_base_reset(DeviceState *dev) { - /* will be filled later on */ + SMMUState *s =3D ARM_SMMU(dev); + + g_hash_table_remove_all(s->configs); } =20 static Property smmu_dev_properties[] =3D { diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 6e0d7ad..938052e 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -537,6 +537,38 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr,= SMMUTransCfg *cfg, return decode_cd(cfg, &cd, event); } =20 +static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *ev= ent) +{ + SMMUv3State *s =3D sdev->smmu; + SMMUState *bc =3D &s->smmu_state; + SMMUTransCfg *cfg; + + cfg =3D g_hash_table_lookup(bc->configs, sdev); + trace_smmuv3_config_cache_hit(((pci_bus_num(sdev->bus) & 0xff) << 8) | + sdev->devfn); + if (!cfg) { + trace_smmuv3_config_cache_miss(((pci_bus_num(sdev->bus) & 0xff) <<= 8) | + sdev->devfn); + cfg =3D g_new0(SMMUTransCfg, 1); + g_hash_table_insert(bc->configs, sdev, cfg); + + if (smmuv3_decode_config(&sdev->iommu, cfg, event)) { + g_hash_table_remove(bc->configs, sdev); + } + } + return cfg; +} + +static void smmuv3_put_config(SMMUDevice *sdev) +{ + SMMUv3State *s =3D sdev->smmu; + SMMUState *bc =3D &s->smmu_state; + + trace_smmuv3_config_cache_inv(((pci_bus_num(sdev->bus) & 0xff) << 8) | + sdev->devfn); + g_hash_table_remove(bc->configs, sdev); +} + static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr, IOMMUAccessFlags flag) { @@ -545,7 +577,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion= *mr, hwaddr addr, uint32_t sid =3D smmu_get_sid(sdev); SMMUEventInfo event =3D {.type =3D SMMU_EVT_OK, .sid =3D sid}; SMMUPTWEventInfo ptw_info =3D {}; - SMMUTransCfg cfg =3D {}; + SMMUTransCfg *cfg =3D NULL; IOMMUTLBEntry entry =3D { .target_as =3D &address_space_memory, .iova =3D addr, @@ -556,19 +588,26 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegi= on *mr, hwaddr addr, int ret =3D 0; =20 if (!smmu_enabled(s)) { + return entry; + } + + /* + * the lock is held to sequentialize invalidation commands and + * translation operations + */ + qemu_mutex_lock(&s->mutex); + + cfg =3D smmuv3_get_config(sdev, &event); + if (!cfg) { + ret =3D -EINVAL; goto out; } =20 - ret =3D smmuv3_decode_config(mr, &cfg, &event); - if (ret) { + if (cfg->aborted) { goto out; } =20 - if (cfg.aborted) { - goto out; - } - - ret =3D smmu_ptw(&cfg, addr, flag, &entry, &ptw_info); + ret =3D smmu_ptw(cfg, addr, flag, &entry, &ptw_info); if (ret) { switch (ptw_info.type) { case SMMU_PTW_ERR_WALK_EABT: @@ -617,17 +656,20 @@ out: mr->parent_obj.name, addr, ret); entry.perm =3D IOMMU_NONE; smmuv3_record_event(s, &event); - } else if (!cfg.aborted) { + } else if (!cfg->aborted) { entry.perm =3D flag; trace_smmuv3_translate(mr->parent_obj.name, sid, addr, entry.translated_addr, entry.perm); } =20 + qemu_mutex_unlock(&s->mutex); + return entry; } =20 static int smmuv3_cmdq_consume(SMMUv3State *s) { + SMMUState *bs =3D ARM_SMMU(s); SMMUCmdError cmd_error =3D SMMU_CERROR_NONE; SMMUQueue *q =3D &s->cmdq; SMMUCommandType type =3D 0; @@ -662,6 +704,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) =20 trace_smmuv3_cmdq_opcode(smmu_cmd_string(type)); =20 + qemu_mutex_lock(&s->mutex); switch (type) { case SMMU_CMD_SYNC: if (CMD_SYNC_CS(&cmd) & CMD_SYNC_SIG_IRQ) { @@ -670,10 +713,74 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) break; case SMMU_CMD_PREFETCH_CONFIG: case SMMU_CMD_PREFETCH_ADDR: + break; case SMMU_CMD_CFGI_STE: + { + uint32_t sid =3D CMD_SID(&cmd); + IOMMUMemoryRegion *mr =3D smmu_iommu_mr(bs, sid); + SMMUDevice *sdev; + + if (CMD_SSEC(&cmd)) { + cmd_error =3D SMMU_CERROR_ILL; + break; + } + + if (!mr) { + break; + } + + trace_smmuv3_cmdq_cfgi_ste(sid); + sdev =3D container_of(mr, SMMUDevice, iommu); + smmuv3_put_config(sdev); + + break; + } case SMMU_CMD_CFGI_STE_RANGE: /* same as SMMU_CMD_CFGI_ALL */ + { + uint32_t start =3D CMD_SID(&cmd), end, i; + uint8_t range =3D CMD_STE_RANGE(&cmd); + + if (CMD_SSEC(&cmd)) { + cmd_error =3D SMMU_CERROR_ILL; + break; + } + + end =3D start + (1 << (range + 1)) - 1; + trace_smmuv3_cmdq_cfgi_ste_range(start, end); + + for (i =3D start; i <=3D end; i++) { + IOMMUMemoryRegion *mr =3D smmu_iommu_mr(bs, i); + SMMUDevice *sdev; + + if (!mr) { + continue; + } + sdev =3D container_of(mr, SMMUDevice, iommu); + smmuv3_put_config(sdev); + } + break; + } case SMMU_CMD_CFGI_CD: case SMMU_CMD_CFGI_CD_ALL: + { + uint32_t sid =3D CMD_SID(&cmd); + IOMMUMemoryRegion *mr =3D smmu_iommu_mr(bs, sid); + SMMUDevice *sdev; + + if (CMD_SSEC(&cmd)) { + cmd_error =3D SMMU_CERROR_ILL; + break; + } + + if (!mr) { + break; + } + + trace_smmuv3_cmdq_cfgi_cd(sid); + sdev =3D container_of(mr, SMMUDevice, iommu); + smmuv3_put_config(sdev); + break; + } case SMMU_CMD_TLBI_NH_ALL: case SMMU_CMD_TLBI_NH_ASID: case SMMU_CMD_TLBI_NH_VA: @@ -700,6 +807,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) break; } if (cmd_error) { + qemu_mutex_unlock(&s->mutex); break; } /* @@ -708,6 +816,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) * and does not check the completion of previous commands */ queue_cons_incr(q); + qemu_mutex_unlock(&s->mutex); } =20 if (cmd_error) { @@ -1078,6 +1187,8 @@ static void smmu_realize(DeviceState *d, Error **errp) return; } =20 + qemu_mutex_init(&s->mutex); + memory_region_init_io(&sys->iomem, OBJECT(s), &smmu_mem_ops, sys, TYPE_ARM_SMMUV3, 0x20000); =20 diff --git a/hw/arm/trace-events b/hw/arm/trace-events index 032de48..ecc30be 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -39,3 +39,9 @@ smmuv3_get_cd(uint64_t addr) "CD addr: 0x%"PRIx64 smmuv3_translate(const char *n, uint16_t sid, uint64_t iova, uint64_t tran= slated, int perm) "%s sid=3D%d iova=3D0x%"PRIx64" translated=3D0x%"PRIx64" = perm=3D0x%x" smmuv3_decode_cd(uint32_t oas) "oas=3D%d" smmuv3_decode_cd_tt(int i, uint32_t tsz, uint64_t ttb, uint32_t granule_sz= , int initial_level) "TT[%d]:tsz:%d ttb:0x%"PRIx64" granule_sz:%d, initial_= level =3D %d" +smmuv3_cmdq_cfgi_ste(int streamid) " |_ streamid =3D%d" +smmuv3_cmdq_cfgi_ste_range(int start, int end) " |_ start=3D0x%d - end= =3D0x%d" +smmuv3_cmdq_cfgi_cd(uint32_t sid) " |_ streamid =3D %d" +smmuv3_config_cache_hit(uint32_t sid) "Config cache HIT for sid %d" +smmuv3_config_cache_miss(uint32_t sid) "Config cache MISS for sid %d" +smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid %d" diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index 4ccd131..ff07734 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -143,4 +143,7 @@ int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUA= ccessFlags perm, */ SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t iova); =20 +/* Return the iommu mr associated to @sid, or NULL if none */ +IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid); + #endif /* HW_ARM_SMMU_COMMON */ diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h index 23f7036..36b2f45 100644 --- a/include/hw/arm/smmuv3.h +++ b/include/hw/arm/smmuv3.h @@ -59,6 +59,7 @@ typedef struct SMMUv3State { SMMUQueue eventq, cmdq; =20 qemu_irq irq[4]; + QemuMutex mutex; } SMMUv3State; =20 typedef enum { --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523519524131726.9268790177417; Thu, 12 Apr 2018 00:52:04 -0700 (PDT) Received: from localhost ([::1]:44321 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6X1X-0002K6-9s for importer@patchew.org; Thu, 12 Apr 2018 03:52:03 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49844) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6WpD-0007Ej-SM for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:21 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6WpB-0003XJ-VL for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:19 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:35686 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6Wp4-0003TS-JZ; Thu, 12 Apr 2018 03:39:10 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1565681A88A0; Thu, 12 Apr 2018 07:39:10 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id 78E95215CDC6; Thu, 12 Apr 2018 07:39:07 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:38:07 +0200 Message-Id: <1523518688-26674-17-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 12 Apr 2018 07:39:10 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 12 Apr 2018 07:39:10 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 16/17] hw/arm/smmuv3: IOTLB emulation 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" We emulate a TLB cache of size SMMU_IOTLB_MAX_SIZE=3D256. It is implemented as a hash table whose key is a combination of the 16b asid and 48b IOVA. Entries are invalidated on TLB invalidation commands, either globally, or per asid, or per asid/iova. One peculiarity is the NH_VA invalidation command does not convey any information about the size to be invalidated (as opposed to what Intel does, for instance, with the am field). Hence, when NH_VA arrives we both invalidate the 4K and 64K entries, the both granules that we support. Signed-off-by: Eric Auger --- Credit to Tomasz Nowicki who did the first implementation of this IOTLB implementation, inspired of intel_iommu implemtation. --- hw/arm/smmu-common.c | 33 ++++++++++++++ hw/arm/smmuv3.c | 105 +++++++++++++++++++++++++++++++++++++++= ++-- hw/arm/trace-events | 9 ++++ include/hw/arm/smmu-common.h | 11 +++++ 4 files changed, 154 insertions(+), 4 deletions(-) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index c271a28..3d25339 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -29,6 +29,36 @@ #include "hw/arm/smmu-common.h" #include "smmu-internal.h" =20 +/* IOTLB Management */ + +inline void smmu_iotlb_inv_all(SMMUState *s) +{ + trace_smmu_iotlb_inv_all(); + g_hash_table_remove_all(s->iotlb); +} + +static gboolean smmu_hash_remove_by_asid(gpointer key, gpointer value, + gpointer user_data) +{ + uint16_t asid =3D *(uint16_t *)user_data; + + return ((*(uint64_t *)key) >> IOTLB_KEY_ASID_SHIFT) =3D=3D asid; +} + +inline void smmu_iotlb_inv_iova(SMMUState *s, uint16_t asid, dma_addr_t io= va) +{ + uint64_t key =3D SMMU_IOTLB_KEY(asid, iova); + + trace_smmu_iotlb_inv_iova(asid, iova); + g_hash_table_remove(s->iotlb, &key); +} + +inline void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid) +{ + trace_smmu_iotlb_inv_asid(asid); + g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid); +} + /* VMSAv8-64 Translation */ =20 /** @@ -327,6 +357,8 @@ static void smmu_base_realize(DeviceState *dev, Error *= *errp) return; } s->configs =3D g_hash_table_new_full(NULL, NULL, NULL, g_free); + s->iotlb =3D g_hash_table_new_full(g_int64_hash, g_int64_equal, + g_free, g_free); s->smmu_pcibus_by_busptr =3D g_hash_table_new(NULL, NULL); =20 if (s->primary_bus) { @@ -341,6 +373,7 @@ static void smmu_base_reset(DeviceState *dev) SMMUState *s =3D ARM_SMMU(dev); =20 g_hash_table_remove_all(s->configs); + g_hash_table_remove_all(s->iotlb); } =20 static Property smmu_dev_properties[] =3D { diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 938052e..081f0fb 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -551,6 +551,8 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev= , SMMUEventInfo *event) sdev->devfn); cfg =3D g_new0(SMMUTransCfg, 1); g_hash_table_insert(bc->configs, sdev, cfg); + cfg->iotlb_miss =3D 0; + cfg->iotlb_hit =3D 0; =20 if (smmuv3_decode_config(&sdev->iommu, cfg, event)) { g_hash_table_remove(bc->configs, sdev); @@ -575,8 +577,12 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegio= n *mr, hwaddr addr, SMMUDevice *sdev =3D container_of(mr, SMMUDevice, iommu); SMMUv3State *s =3D sdev->smmu; uint32_t sid =3D smmu_get_sid(sdev); + SMMUState *bs =3D ARM_SMMU(s); SMMUEventInfo event =3D {.type =3D SMMU_EVT_OK, .sid =3D sid}; + uint64_t key_val, page_mask, aligned_addr; + IOMMUTLBEntry *cached_entry =3D NULL; SMMUPTWEventInfo ptw_info =3D {}; + SMMUTransTableInfo *tt; SMMUTransCfg *cfg =3D NULL; IOMMUTLBEntry entry =3D { .target_as =3D &address_space_memory, @@ -585,6 +591,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion= *mr, hwaddr addr, .addr_mask =3D ~(hwaddr)0, .perm =3D IOMMU_NONE, }; + uint64_t *key; int ret =3D 0; =20 if (!smmu_enabled(s)) { @@ -607,7 +614,56 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegio= n *mr, hwaddr addr, goto out; } =20 - ret =3D smmu_ptw(cfg, addr, flag, &entry, &ptw_info); + tt =3D select_tt(cfg, addr); + if (!tt) { + if (event.record_trans_faults) { + event.type =3D SMMU_EVT_F_TRANSLATION; + event.u.f_translation.addr =3D addr; + event.u.f_translation.rnw =3D flag & 0x1; + } + ret =3D -EINVAL; + goto out; + } + + page_mask =3D (1ULL << (tt->granule_sz)) - 1; + aligned_addr =3D addr & ~page_mask; + + key_val =3D SMMU_IOTLB_KEY(cfg->asid, aligned_addr); + + cached_entry =3D g_hash_table_lookup(bs->iotlb, &key_val); + if (cached_entry) { + cfg->iotlb_hit +=3D 1; + trace_smmu_iotlb_cache_hit(cfg->asid, aligned_addr, + cfg->iotlb_hit, cfg->iotlb_miss, + 100 * cfg->iotlb_hit / + (cfg->iotlb_hit + cfg->iotlb_miss)); + if ((flag & IOMMU_WO) && !(cached_entry->perm & IOMMU_WO)) { + ret =3D -EFAULT; + if (event.record_trans_faults) { + event.type =3D SMMU_EVT_F_PERMISSION; + event.u.f_permission.addr =3D addr; + event.u.f_permission.rnw =3D flag & 0x1; + } + } + goto out; + } + + cfg->iotlb_miss +=3D 1; + trace_smmu_iotlb_cache_miss(cfg->asid, addr & ~page_mask, + cfg->iotlb_hit, cfg->iotlb_miss, + 100 * cfg->iotlb_hit / + (cfg->iotlb_hit + cfg->iotlb_miss)); + + if (g_hash_table_size(bs->iotlb) >=3D SMMU_IOTLB_MAX_SIZE) { + smmu_iotlb_inv_all(bs); + } + + cached_entry =3D g_new0(IOMMUTLBEntry, 1); + key =3D g_new0(uint64_t, 1); + *key =3D key_val; + g_hash_table_insert(bs->iotlb, key, cached_entry); + + ret =3D smmu_ptw(cfg, aligned_addr, flag, cached_entry, &ptw_info); if (ret) { switch (ptw_info.type) { case SMMU_PTW_ERR_WALK_EABT: @@ -656,8 +712,14 @@ out: mr->parent_obj.name, addr, ret); entry.perm =3D IOMMU_NONE; smmuv3_record_event(s, &event); + if (cached_entry) { + smmu_iotlb_inv_iova(bs, cfg->asid, aligned_addr); + } } else if (!cfg->aborted) { entry.perm =3D flag; + entry.translated_addr =3D cached_entry->translated_addr + + (addr & page_mask); + entry.addr_mask =3D cached_entry->addr_mask; trace_smmuv3_translate(mr->parent_obj.name, sid, addr, entry.translated_addr, entry.perm); } @@ -781,10 +843,46 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) smmuv3_put_config(sdev); break; } - case SMMU_CMD_TLBI_NH_ALL: case SMMU_CMD_TLBI_NH_ASID: - case SMMU_CMD_TLBI_NH_VA: + { + uint16_t asid =3D CMD_ASID(&cmd); + + trace_smmuv3_cmdq_tlbi_nh_asid(asid); + /* TODO: be more precise and invalidate for @asid */ + smmu_iotlb_inv_asid(bs, asid); + break; + } + case SMMU_CMD_TLBI_NH_ALL: + case SMMU_CMD_TLBI_NSNH_ALL: + trace_smmuv3_cmdq_tlbi_nh(); + smmu_iotlb_inv_all(bs); + break; case SMMU_CMD_TLBI_NH_VAA: + { + dma_addr_t addr =3D CMD_ADDR(&cmd); + uint16_t vmid =3D CMD_VMID(&cmd); + + trace_smmuv3_cmdq_tlbi_nh_vaa(vmid, addr); + smmu_iotlb_inv_all(bs); + break; + } + case SMMU_CMD_TLBI_NH_VA: + { + uint16_t asid =3D CMD_ASID(&cmd); + uint16_t vmid =3D CMD_VMID(&cmd); + dma_addr_t addr =3D CMD_ADDR(&cmd); + bool leaf =3D CMD_LEAF(&cmd); + + trace_smmuv3_cmdq_tlbi_nh_va(vmid, asid, addr, leaf); + /** + * we don't know the size of the granule so + * let's invalidate both 4K entry and 64kB entry. + * The spec allow to invalidate more than necessary. + */ + smmu_iotlb_inv_iova(bs, asid, addr & ~0xFFF); + smmu_iotlb_inv_iova(bs, asid, addr & ~0xFFFF); + break; + } case SMMU_CMD_TLBI_EL3_ALL: case SMMU_CMD_TLBI_EL3_VA: case SMMU_CMD_TLBI_EL2_ALL: @@ -793,7 +891,6 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) case SMMU_CMD_TLBI_EL2_VAA: case SMMU_CMD_TLBI_S12_VMALL: case SMMU_CMD_TLBI_S2_IPA: - case SMMU_CMD_TLBI_NSNH_ALL: case SMMU_CMD_ATC_INV: case SMMU_CMD_PRI_RESP: case SMMU_CMD_RESUME: diff --git a/hw/arm/trace-events b/hw/arm/trace-events index ecc30be..7fdc08e 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -12,6 +12,11 @@ smmu_ptw_invalid_pte(int stage, int level, uint64_t base= addr, uint64_t pteaddr, smmu_ptw_page_pte(int stage, int level, uint64_t iova, uint64_t baseaddr,= uint64_t pteaddr, uint64_t pte, uint64_t address) "stage=3D%d level=3D%d i= ova=3D0x%"PRIx64" base@=3D0x%"PRIx64" pte@=3D0x%"PRIx64" pte=3D0x%"PRIx64" = page address =3D 0x%"PRIx64 smmu_ptw_block_pte(int stage, int level, uint64_t baseaddr, uint64_t ptead= dr, uint64_t pte, uint64_t iova, uint64_t gpa, int bsize_mb) "stage=3D%d le= vel=3D%d base@=3D0x%"PRIx64" pte@=3D0x%"PRIx64" pte=3D0x%"PRIx64" iova=3D0x= %"PRIx64" block address =3D 0x%"PRIx64" block size =3D %d MiB" smmu_get_pte(uint64_t baseaddr, int index, uint64_t pteaddr, uint64_t pte)= "baseaddr=3D0x%"PRIx64" index=3D0x%x, pteaddr=3D0x%"PRIx64", pte=3D0x%"PRI= x64 +smmu_iotlb_cache_hit(uint16_t asid, uint64_t addr, uint32_t hit, uint32_t = miss, float p) "IOTLB cache HIT asid=3D%d addr=3D0x%"PRIx64" hit=3D%d miss= =3D%d hit rate=3D%.1f" +smmu_iotlb_cache_miss(uint16_t asid, uint64_t addr, uint32_t hit, uint32_t= miss, float p) "IOTLB cache MISS asid=3D%d addr=3D0x%"PRIx64" hit=3D%d mis= s=3D%d hit rate=3D%.1f" +smmu_iotlb_inv_all(void) "IOTLB invalidate all" +smmu_iotlb_inv_asid(uint16_t asid) "IOTLB invalidate asid=3D%d" +smmu_iotlb_inv_iova(uint16_t asid, uint64_t addr) "IOTLB invalidate asid= =3D%d addr=3D0x%"PRIx64 =20 #hw/arm/smmuv3.c smmuv3_read_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "= addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)" @@ -41,6 +46,10 @@ smmuv3_decode_cd(uint32_t oas) "oas=3D%d" smmuv3_decode_cd_tt(int i, uint32_t tsz, uint64_t ttb, uint32_t granule_sz= , int initial_level) "TT[%d]:tsz:%d ttb:0x%"PRIx64" granule_sz:%d, initial_= level =3D %d" smmuv3_cmdq_cfgi_ste(int streamid) " |_ streamid =3D%d" smmuv3_cmdq_cfgi_ste_range(int start, int end) " |_ start=3D0x%d - end= =3D0x%d" +smmuv3_cmdq_tlbi_nh_va(int vmid, int asid, uint64_t addr, bool leaf) " = |_ vmid =3D%d asid =3D%d addr=3D0x%"PRIx64" leaf=3D%d" +smmuv3_cmdq_tlbi_nh_vaa(int vmid, uint64_t addr) " |_ vmid =3D%d addr= =3D0x%"PRIx64 +smmuv3_cmdq_tlbi_nh(void) "" +smmuv3_cmdq_tlbi_nh_asid(uint16_t asid) "asid=3D%d" smmuv3_cmdq_cfgi_cd(uint32_t sid) " |_ streamid =3D %d" smmuv3_config_cache_hit(uint32_t sid) "Config cache HIT for sid %d" smmuv3_config_cache_miss(uint32_t sid) "Config cache MISS for sid %d" diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index ff07734..1c9c648 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -68,6 +68,8 @@ typedef struct SMMUTransCfg { uint8_t tbi; /* Top Byte Ignore */ uint16_t asid; SMMUTransTableInfo tt[2]; + uint32_t iotlb_hit; + uint32_t iotlb_miss; } SMMUTransCfg; =20 typedef struct SMMUDevice { @@ -146,4 +148,13 @@ SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_a= ddr_t iova); /* Return the iommu mr associated to @sid, or NULL if none */ IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid); =20 +#define SMMU_IOTLB_MAX_SIZE 256 +#define IOTLB_KEY_ASID_SHIFT SMMU_MAX_VA_BITS +#define SMMU_IOTLB_KEY(asid, iova) \ + (iova | (uint64_t)(asid) << IOTLB_KEY_ASID_SHIFT); + +void smmu_iotlb_inv_all(SMMUState *s); +void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid); +void smmu_iotlb_inv_iova(SMMUState *s, uint16_t asid, dma_addr_t iova); + #endif /* HW_ARM_SMMU_COMMON */ --=20 2.5.5 From nobody Sat May 4 16:43:42 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1523520048320904.287014697635; Thu, 12 Apr 2018 01:00:48 -0700 (PDT) Received: from localhost ([::1]:45126 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6X9q-0001ZE-Pi for importer@patchew.org; Thu, 12 Apr 2018 04:00:38 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49865) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f6WpE-0007FF-HG for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:22 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f6WpD-0003Xo-B6 for qemu-devel@nongnu.org; Thu, 12 Apr 2018 03:39:20 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:35964 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f6Wp7-0003VI-T3; Thu, 12 Apr 2018 03:39:13 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 68532EBFE5; Thu, 12 Apr 2018 07:39:13 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id 598FE215CDC6; Thu, 12 Apr 2018 07:39:10 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, prem.mallappa@gmail.com Date: Thu, 12 Apr 2018 09:38:08 +0200 Message-Id: <1523518688-26674-18-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> References: <1523518688-26674-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Thu, 12 Apr 2018 07:39:13 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Thu, 12 Apr 2018 07:39:13 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v11 17/17] hw/arm/smmuv3: Add notifications on invalidation 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: cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, tn@semihalf.com, peterx@redhat.com, alex.williamson@redhat.com, linuc.decode@gmail.com, bharat.bhushan@nxp.com, jintack@cs.columbia.edu Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" On TLB invalidation commands, let's call registered IOMMU notifiers. Those can only be UNMAP notifiers. SMMUv3 does not support notification on MAP (VFIO). This patch allows vhost use case where IOTLB API is notified on each guest IOTLB invalidation. Signed-off-by: Eric Auger --- hw/arm/smmu-common.c | 34 +++++++++++++++ hw/arm/smmuv3.c | 99 ++++++++++++++++++++++++++++++++++++++++= +++- hw/arm/trace-events | 5 +++ include/hw/arm/smmu-common.h | 6 +++ 4 files changed, 142 insertions(+), 2 deletions(-) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 3d25339..c50ad20 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -345,6 +345,40 @@ IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_= t sid) return NULL; } =20 +/* Unmap the whole notifier's range */ +static void smmu_unmap_notifier_range(IOMMUNotifier *n) +{ + IOMMUTLBEntry entry; + + entry.target_as =3D &address_space_memory; + entry.iova =3D n->start; + entry.perm =3D IOMMU_NONE; + entry.addr_mask =3D n->end - n->start; + + memory_region_notify_one(n, &entry); +} + +/* Unmap all notifiers attached to @mr */ +inline void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr) +{ + IOMMUNotifier *n; + + trace_smmu_inv_notifiers_mr(mr->parent_obj.name); + IOMMU_NOTIFIER_FOREACH(n, mr) { + smmu_unmap_notifier_range(n); + } +} + +/* Unmap all notifiers of all mr's */ +void smmu_inv_notifiers_all(SMMUState *s) +{ + SMMUNotifierNode *node; + + QLIST_FOREACH(node, &s->notifiers_list, next) { + smmu_inv_notifiers_mr(&node->sdev->iommu); + } +} + static void smmu_base_realize(DeviceState *dev, Error **errp) { SMMUState *s =3D ARM_SMMU(dev); diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 081f0fb..ac1e72d 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -729,6 +729,68 @@ out: return entry; } =20 +/** + * smmuv3_notify_iova - call the notifier @n for a given + * @asid and @iova tuple. + * + * @mr: IOMMU mr region handle + * @n: notifier to be called + * @asid: address space ID or negative value if we don't care + * @iova: iova + */ +static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, + IOMMUNotifier *n, + int asid, + dma_addr_t iova) +{ + SMMUDevice *sdev =3D container_of(mr, SMMUDevice, iommu); + SMMUEventInfo event =3D {}; + SMMUTransTableInfo *tt; + SMMUTransCfg *cfg; + IOMMUTLBEntry entry; + + cfg =3D smmuv3_get_config(sdev, &event); + if (!cfg) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s error decoding the configuration for iommu mr=3D= %s\n", + __func__, mr->parent_obj.name); + return; + } + + if (asid >=3D 0 && cfg->asid !=3D asid) { + return; + } + + tt =3D select_tt(cfg, iova); + if (!tt) { + return; + } + + entry.target_as =3D &address_space_memory; + entry.iova =3D iova; + entry.addr_mask =3D (1 << tt->granule_sz) - 1; + entry.perm =3D IOMMU_NONE; + + memory_region_notify_one(n, &entry); +} + +/* invalidate an asid/iova tuple in all mr's */ +static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t i= ova) +{ + SMMUNotifierNode *node; + + QLIST_FOREACH(node, &s->notifiers_list, next) { + IOMMUMemoryRegion *mr =3D &node->sdev->iommu; + IOMMUNotifier *n; + + trace_smmuv3_inv_notifiers_iova(mr->parent_obj.name, asid, iova); + + IOMMU_NOTIFIER_FOREACH(n, mr) { + smmuv3_notify_iova(mr, n, asid, iova); + } + } +} + static int smmuv3_cmdq_consume(SMMUv3State *s) { SMMUState *bs =3D ARM_SMMU(s); @@ -849,12 +911,14 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) =20 trace_smmuv3_cmdq_tlbi_nh_asid(asid); /* TODO: be more precise and invalidate for @asid */ + smmu_inv_notifiers_all(&s->smmu_state); smmu_iotlb_inv_asid(bs, asid); break; } case SMMU_CMD_TLBI_NH_ALL: case SMMU_CMD_TLBI_NSNH_ALL: trace_smmuv3_cmdq_tlbi_nh(); + smmu_inv_notifiers_all(&s->smmu_state); smmu_iotlb_inv_all(bs); break; case SMMU_CMD_TLBI_NH_VAA: @@ -863,6 +927,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) uint16_t vmid =3D CMD_VMID(&cmd); =20 trace_smmuv3_cmdq_tlbi_nh_vaa(vmid, addr); + smmuv3_inv_notifiers_iova(bs, -1, addr); smmu_iotlb_inv_all(bs); break; } @@ -874,6 +939,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) bool leaf =3D CMD_LEAF(&cmd); =20 trace_smmuv3_cmdq_tlbi_nh_va(vmid, asid, addr, leaf); + smmuv3_inv_notifiers_iova(bs, asid, addr); /** * we don't know the size of the granule so * let's invalidate both 4K entry and 64kB entry. @@ -1359,9 +1425,38 @@ static void smmuv3_notify_flag_changed(IOMMUMemoryRe= gion *iommu, IOMMUNotifierFlag old, IOMMUNotifierFlag new) { + SMMUDevice *sdev =3D container_of(iommu, SMMUDevice, iommu); + SMMUv3State *s3 =3D sdev->smmu; + SMMUState *s =3D &(s3->smmu_state); + SMMUNotifierNode *node =3D NULL; + SMMUNotifierNode *next_node =3D NULL; + + if (new =3D=3D IOMMU_NOTIFIER_MAP) { + int bus_num =3D pci_bus_num(sdev->bus); + PCIDevice *pcidev =3D pci_find_device(sdev->bus, bus_num, sdev->de= vfn); + + warn_report("SMMUv3 does not support notification on MAP: " + "device %s will not function properly", pcidev->name); + } + if (old =3D=3D IOMMU_NOTIFIER_NONE) { - warn_report("SMMUV3 does not support vhost/vfio integration yet: " - "devices of those types will not function properly"); + trace_smmuv3_notify_flag_add(iommu->parent_obj.name); + node =3D g_malloc0(sizeof(*node)); + node->sdev =3D sdev; + QLIST_INSERT_HEAD(&s->notifiers_list, node, next); + return; + } + + /* update notifier node with new flags */ + QLIST_FOREACH_SAFE(node, &s->notifiers_list, next, next_node) { + if (node->sdev =3D=3D sdev) { + if (new =3D=3D IOMMU_NOTIFIER_NONE) { + trace_smmuv3_notify_flag_del(iommu->parent_obj.name); + QLIST_REMOVE(node, next); + g_free(node); + } + return; + } } } =20 diff --git a/hw/arm/trace-events b/hw/arm/trace-events index 7fdc08e..0f0ace5 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -17,6 +17,7 @@ smmu_iotlb_cache_miss(uint16_t asid, uint64_t addr, uint3= 2_t hit, uint32_t miss, smmu_iotlb_inv_all(void) "IOTLB invalidate all" smmu_iotlb_inv_asid(uint16_t asid) "IOTLB invalidate asid=3D%d" smmu_iotlb_inv_iova(uint16_t asid, uint64_t addr) "IOTLB invalidate asid= =3D%d addr=3D0x%"PRIx64 +smmu_inv_notifiers_mr(const char *name) "iommu mr=3D%s" =20 #hw/arm/smmuv3.c smmuv3_read_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "= addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)" @@ -54,3 +55,7 @@ smmuv3_cmdq_cfgi_cd(uint32_t sid) " |_ streamid =3D %= d" smmuv3_config_cache_hit(uint32_t sid) "Config cache HIT for sid %d" smmuv3_config_cache_miss(uint32_t sid) "Config cache MISS for sid %d" smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid %d" +smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu= mr=3D%s" +smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu= mr=3D%s" +smmuv3_inv_notifiers_iova(const char *name, uint16_t asid, uint64_t iova) = "iommu mr=3D%s asid=3D%d iova=3D0x%"PRIx64 + diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index 1c9c648..5b604e1 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -157,4 +157,10 @@ void smmu_iotlb_inv_all(SMMUState *s); void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid); void smmu_iotlb_inv_iova(SMMUState *s, uint16_t asid, dma_addr_t iova); =20 +/* Unmap the range of all the notifiers registered to any IOMMU mr */ +void smmu_inv_notifiers_all(SMMUState *s); + +/* Unmap the range of all the notifiers registered to @mr */ +void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr); + #endif /* HW_ARM_SMMU_COMMON */ --=20 2.5.5