From patchwork Thu Apr 28 07:05:41 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Xu X-Patchwork-Id: 8965911 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 24B8EBF29F for ; Thu, 28 Apr 2016 07:13:39 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 53C4E2026C for ; Thu, 28 Apr 2016 07:13:38 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2F5C9200E8 for ; Thu, 28 Apr 2016 07:13:37 +0000 (UTC) Received: from localhost ([::1]:46929 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1avg8m-0000ud-AB for patchwork-qemu-devel@patchwork.kernel.org; Thu, 28 Apr 2016 03:13:36 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41683) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1avg2I-0004T8-8n for qemu-devel@nongnu.org; Thu, 28 Apr 2016 03:06:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1avg2D-0007gk-SM for qemu-devel@nongnu.org; Thu, 28 Apr 2016 03:06:54 -0400 Received: from mx1.redhat.com ([209.132.183.28]:55443) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1avg2D-0007gg-KJ for qemu-devel@nongnu.org; Thu, 28 Apr 2016 03:06:49 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 56F91C049D4F; Thu, 28 Apr 2016 07:06:49 +0000 (UTC) Received: from pxdev.xzpeter.org.com (dhcp-14-238.nay.redhat.com [10.66.14.238]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u3S75nNU007114; Thu, 28 Apr 2016 03:06:45 -0400 From: Peter Xu To: qemu-devel@nongnu.org Date: Thu, 28 Apr 2016 15:05:41 +0800 Message-Id: <1461827144-6937-16-git-send-email-peterx@redhat.com> In-Reply-To: <1461827144-6937-1-git-send-email-peterx@redhat.com> References: <1461827144-6937-1-git-send-email-peterx@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v5 15/18] intel_iommu: introduce IEC notifiers 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: ehabkost@redhat.com, mst@redhat.com, jasowang@redhat.com, rkrcmar@redhat.com, peterx@redhat.com, alex.williamson@redhat.com, jan.kiszka@web.de, wexu@redhat.com, pbonzini@redhat.com, marcel@redhat.com, imammedo@redhat.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch introduces Intel VT-d IEC (Interrupt Entry Cache) invalidation notifier list. When vIOMMU receives IEC invalidate request, all the registered units will be notified with specific invalidation requests. Signed-off-by: Peter Xu --- hw/i386/intel_iommu.c | 56 ++++++++++++++++++++++++++++++++++++------ hw/i386/intel_iommu_internal.h | 24 +++++++++++++++--- include/hw/i386/intel_iommu.h | 22 +++++++++++++++++ 3 files changed, 91 insertions(+), 11 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index a8a57db..7122e5b 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -900,6 +900,22 @@ static void vtd_root_table_setup(IntelIOMMUState *s) (s->root_extended ? "(extended)" : "")); } +static void vtd_iec_notify_all(IntelIOMMUState *s, bool global, + uint32_t index, uint32_t mask) +{ + VTD_IEC_Notifier *notifier; + + VTD_DPRINTF(INV, "notify IEC invalidate: global=%d, index=%u, mask=%u", + global, index, mask); + + QLIST_FOREACH(notifier, &s->iec_notifiers, list) { + if (notifier->iec_notify) { + notifier->iec_notify(notifier->private, global, + index, mask); + } + } +} + static void vtd_interrupt_remap_table_setup(IntelIOMMUState *s) { uint64_t value = 0; @@ -907,7 +923,8 @@ static void vtd_interrupt_remap_table_setup(IntelIOMMUState *s) s->intr_size = 1UL << ((value & VTD_IRTA_SIZE_MASK) + 1); s->intr_root = value & VTD_IRTA_ADDR_MASK; - /* TODO: invalidate interrupt entry cache */ + /* Notify global invalidation */ + vtd_iec_notify_all(s, true, 0, 0); VTD_DPRINTF(CSR, "int remap table addr 0x%"PRIx64 " size %"PRIu32, s->intr_root, s->intr_size); @@ -1409,6 +1426,21 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) return true; } +static bool vtd_process_inv_iec_desc(IntelIOMMUState *s, + VTDInvDesc *inv_desc) +{ + VTD_DPRINTF(INV, "inv ir glob %d index %d mask %d", + inv_desc->iec.granularity, + inv_desc->iec.index, + inv_desc->iec.index_mask); + + vtd_iec_notify_all(s, inv_desc->iec.granularity, + inv_desc->iec.index, + inv_desc->iec.index_mask); + + return true; +} + static bool vtd_process_inv_desc(IntelIOMMUState *s) { VTDInvDesc inv_desc; @@ -1449,12 +1481,12 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s) break; case VTD_INV_DESC_IEC: - VTD_DPRINTF(INV, "Interrupt Entry Cache Invalidation " - "not implemented yet"); - /* - * Since currently we do not cache interrupt entries, we can - * just mark this descriptor as "good" and move on. - */ + VTD_DPRINTF(INV, "Invalidation Interrupt Entry Cache " + "Descriptor hi 0x%"PRIx64 " lo 0x%"PRIx64, + inv_desc.hi, inv_desc.lo); + if (!vtd_process_inv_iec_desc(s, &inv_desc)) { + return false; + } break; default: @@ -2209,6 +2241,15 @@ static const MemoryRegionOps vtd_mem_ir_ops = { }, }; +void vtd_iec_register_notifier(IntelIOMMUState *s, vtd_iec_notify_fn fn, + void *data) +{ + VTD_IEC_Notifier *notifier = g_new0(VTD_IEC_Notifier, 1); + notifier->iec_notify = fn; + notifier->private = data; + QLIST_INSERT_HEAD(&s->iec_notifiers, notifier, list); +} + VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) { uintptr_t key = (uintptr_t)bus; @@ -2371,6 +2412,7 @@ static void vtd_realize(DeviceState *dev, Error **errp) g_free, g_free); s->vtd_as_by_busptr = g_hash_table_new_full(vtd_uint64_hash, vtd_uint64_equal, g_free, g_free); + QLIST_INIT(&s->iec_notifiers); vtd_init(s); } diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index e1a08cb..10c20fe 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -296,12 +296,28 @@ typedef enum VTDFaultReason { #define VTD_CONTEXT_CACHE_GEN_MAX 0xffffffffUL +/* Interrupt Entry Cache Invalidation Descriptor: VT-d 6.5.2.7. */ +struct VTDInvDescIEC { + uint32_t type:4; /* Should always be 0x4 */ + uint32_t granularity:1; /* If set, it's global IR invalidation */ + uint32_t resved_1:22; + uint32_t index_mask:5; /* 2^N for continuous int invalidation */ + uint32_t index:16; /* Start index to invalidate */ + uint32_t reserved_2:16; +}; +typedef struct VTDInvDescIEC VTDInvDescIEC; + /* Queued Invalidation Descriptor */ -struct VTDInvDesc { - uint64_t lo; - uint64_t hi; +union VTDInvDesc { + struct { + uint64_t lo; + uint64_t hi; + }; + union { + VTDInvDescIEC iec; + }; }; -typedef struct VTDInvDesc VTDInvDesc; +typedef union VTDInvDesc VTDInvDesc; /* Masks for struct VTDInvDesc */ #define VTD_INV_DESC_TYPE 0xf diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 5910e6f..4fe92cf 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -203,6 +203,24 @@ struct VTD_MSIMessage { /* When IR is enabled, all MSI/MSI-X data bits should be zero */ #define VTD_IR_MSI_DATA (0) +/** + * vtd_iec_notify_fn - IEC (Interrupt Entry Cache) notifier hook, + * triggered when IR invalidation happens. + * @private: private data + * @global: whether this is a global IEC invalidation + * @index: IRTE index to invalidate (start from) + * @mask: invalidation mask + */ +typedef void (*vtd_iec_notify_fn)(void *private, bool global, + uint32_t index, uint32_t mask); + +struct VTD_IEC_Notifier { + vtd_iec_notify_fn iec_notify; + void *private; + QLIST_ENTRY(VTD_IEC_Notifier) list; +}; +typedef struct VTD_IEC_Notifier VTD_IEC_Notifier; + /* The iommu (DMAR) device state struct */ struct IntelIOMMUState { SysBusDevice busdev; @@ -243,6 +261,7 @@ struct IntelIOMMUState { bool intr_enabled; /* Whether guest enabled IR */ dma_addr_t intr_root; /* Interrupt remapping table pointer */ uint32_t intr_size; /* Number of IR table entries */ + QLIST_HEAD(, VTD_IEC_Notifier) iec_notifiers; /* IEC notify list */ }; /* Find the VTD Address space associated with the given bus pointer, @@ -252,5 +271,8 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn); /* Get default IOMMU object */ IntelIOMMUState *vtd_iommu_get(void); int vtd_int_remap(void *iommu, MSIMessage *src, MSIMessage *dst); +/* Register IEC invalidate notifier */ +void vtd_iec_register_notifier(IntelIOMMUState *s, vtd_iec_notify_fn fn, + void *data); #endif