From patchwork Tue Mar 8 19:28:41 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rita Sinha X-Patchwork-Id: 8538231 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id D326C9F372 for ; Tue, 8 Mar 2016 22:48:45 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id DD18C20142 for ; Tue, 8 Mar 2016 22:48:43 +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 0357320125 for ; Tue, 8 Mar 2016 22:48:42 +0000 (UTC) Received: from localhost ([::1]:37883 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1adQQj-0001CF-2i for patchwork-qemu-devel@patchwork.kernel.org; Tue, 08 Mar 2016 17:48:41 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49882) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1adQQW-0001Ad-1C for qemu-devel@nongnu.org; Tue, 08 Mar 2016 17:48:31 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1adQQS-00009t-KZ for qemu-devel@nongnu.org; Tue, 08 Mar 2016 17:48:27 -0500 Received: from goliath.siemens.de ([192.35.17.28]:57674) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1adQQS-00008U-4A for qemu-devel@nongnu.org; Tue, 08 Mar 2016 17:48:24 -0500 Received: from mail2.siemens.de (mail2.siemens.de [139.25.208.11]) by goliath.siemens.de (8.15.2/8.15.2) with ESMTPS id u28MmLFf027633 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 8 Mar 2016 23:48:21 +0100 Received: from md1f2u6c.ww002.siemens.net ([139.22.45.138]) by mail2.siemens.de (8.15.2/8.15.2) with SMTP id u28MmKnt020754 for ; Tue, 8 Mar 2016 23:48:21 +0100 Resent-From: Jan Kiszka Resent-To: qemu-devel Resent-Date: Tue, 8 Mar 2016 23:48:20 +0100 Resent-Message-ID: <56DF56B4.8040008@siemens.com> Resent-User-Agent: Mozilla/5.0 (X11; U; Linux i686 (x86_64); de; rv:1.8.1.12) Gecko/20080226 SUSE/2.0.0.12-1.1 Thunderbird/2.0.0.12 Mnenhy/0.7.5.666 Received: from DEFTHW99ERHMSX.ww902.siemens.net (139.22.70.133) by DENBGAT9ERBMSX.ww902.siemens.net (139.22.70.93) with Microsoft SMTP Server (TLS) id 14.3.279.2; Tue, 8 Mar 2016 20:28:52 +0100 Received: from mail1.siemens.de (139.23.33.14) by DEFTHW99ERHMSX.ww902.siemens.net (139.22.70.133) with Microsoft SMTP Server (TLS) id 14.3.279.2; Tue, 8 Mar 2016 20:28:51 +0100 Received: from thoth.sbs.de (thoth.sbs.de [192.35.17.2]) by mail1.siemens.de (8.15.2/8.15.2) with ESMTPS id u28JSpBH007772 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 8 Mar 2016 20:28:51 +0100 Received: from meleagros.erlm.siemens.de (meleagros.siemens.com [217.194.35.77]) by thoth.sbs.de (8.15.2/8.15.2) with ESMTPS id u28JSpIw021611 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 8 Mar 2016 20:28:51 +0100 Received: from localhost (localhost [127.0.0.1]) by meleagros.siemens.com (Postfix) with ESMTP id 1C9F396005F for ; Tue, 8 Mar 2016 20:28:51 +0100 (CET) X-CTCH-RefID: str=0001.0A0C0203.56DF27F3.003C, ss=1, re=-2.300, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0 Received: from meleagros.siemens.com ([127.0.0.1]) by localhost (meleagros.erlm.siemens.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id hUUGmKhICrmP for ; Tue, 8 Mar 2016 20:28:49 +0100 (CET) Received: from [209.85.220.68] (helo=meleagros.siemens.com) by localhost with ESMTP (eXpurgate 4.0.2) (envelope-from ) id 56df27f0-c547-7f0000017549-7f000001d778-1 for ; Tue, 08 Mar 2016 20:28:48 +0100 X-MtScore: NO score=-5 [whitelist=-5] Received: from mail-pa0-f68.google.com (mail-pa0-f68.google.com [209.85.220.68]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by meleagros.siemens.com (Postfix) with ESMTPS for ; Tue, 8 Mar 2016 20:28:48 +0100 (CET) Received: by mail-pa0-f68.google.com with SMTP id 1so1742485pal.3 for ; Tue, 08 Mar 2016 11:28:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=mTa7EyzwHZmPewdOG5g2d51fdRuHMiYktFJPEawqc54=; b=PFRCpFKR8ueOdjZfprc2fyaOYKcb+2kAs/eP6emK1C9+S6xPCCu2eGb6lnz877cejB n1mu+tRZ3P0X5inYm+bUI6elMre6QRp28dJYH0E+Fq6lNPu/Ve6WM5A1kgJcSoepQJt/ Yywx+NrqBHsH1SP3tCrNvNdZRbV/w2Lkl2w01EHgD3A6cKU58xuHxQ5otCC6g8K8i+pK raWTGtyFBKAULqIxdCPO/cmNDbp1WJkO+h7Slt3Rb+X88hoGw+vk5Fdpeh5wAKoYRsoi lsBZd5x7mn7jRuGCMK0YNiiMn7myxiZfIs8eDpPY5QCiUcaBkxuBKkMQ8a4QNW1dxhnR wsrQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=mTa7EyzwHZmPewdOG5g2d51fdRuHMiYktFJPEawqc54=; b=A6eQG4EtxnPp778CkDfZyEz4m8tzvrizOs9NN/sr4uqYc58QX1KXwol0akEzVu+48y NgdNs+GVtckgbaPYjbVsMKMPjvEg2KL4Ys5PMRgs8NOooEnhxePbcW2IxAiZPjKSVDNR lFdh3fGh0/vJmfZFJvdr13d2VhxPhJp/EgujT7KUgAJ76VWFExAOz8NiyfqNAB8+/AYy C0GA6XmnB84bFZ6T+kNRKLswhv35Y20lrGgbcT1uEinAfK74PYxUuGw7da3PUbJs19JF QQO4I2q9ftBSYkO/15R39o21lNs2zJhwOB8drO1BNOg94nLYJ53ik7XKQsHyMSPL+9pK 0q/g== X-Gm-Message-State: AD7BkJK/CHx9dvR3DV2IDTh0jQ/aNj7lIDTMIa1hsC70MzZnXvhb/TEwYEgAnmD5HnFvnw== X-Received: by 10.66.132.73 with SMTP id os9mr44323796pab.27.1457465327191; Tue, 08 Mar 2016 11:28:47 -0800 (PST) Received: from localhost.localdomain ([103.18.72.56]) by smtp.googlemail.com with ESMTPSA id 9sm6768474pfm.10.2016.03.08.11.28.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 08 Mar 2016 11:28:46 -0800 (PST) From: Rita Sinha To: Date: Wed, 9 Mar 2016 00:58:41 +0530 Message-ID: <1457465321-15252-1-git-send-email-rita.sinha89@gmail.com> X-Mailer: git-send-email 2.7.2 X-purgate-ID: 149900::1457465329-0000C547-38A68E6A/0/0 X-purgate-type: clean X-purgate-size: 27596 X-purgate-Ad: Categorized by eleven eXpurgate (R) http://www.eleven.de X-purgate: clean X-MS-Exchange-Organization-AVStamp-Mailbox: SMEXutTf; 1238900; 0; This mail has been scanned by Trend Micro ScanMail for Microsoft Exchange; X-MS-Exchange-Organization-SCL: 0 X-MS-Exchange-Organization-AuthSource: DEFTHW99ERHMSX.ww902.siemens.net X-MS-Exchange-Organization-AuthAs: Anonymous MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 192.35.17.28 Cc: Jan Kiszka Subject: [Qemu-devel] [PATCH 1/2] i386: Prepare for interrupt remapping X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham 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 From: Jan Kiszka Introduce a DMA default target address space for PCI devices. Catch all interrupt requests to the front-side bus via an MSI memory region that is part of that address space. Provide separate address spaces for IOAPIC and HPET if the IOMMU is active to prepare for adding remapping logic later on. Deliver the EDID from the IOAPIC for the same reason. Allows to remove the MSI hack from the APIC MMIO write handler. Signed-off-by: Rita Sinha --- hw/i386/intel_iommu.c | 22 ++++++++++------ hw/i386/kvm/apic.c | 24 +++++++++++------- hw/i386/pc.c | 17 +++++++++++++ hw/i386/pc_piix.c | 1 - hw/i386/pc_q35.c | 11 +++++--- hw/i386/xen/xen_apic.c | 24 +++++++++++------- hw/intc/apic.c | 53 +++++++++++++++++++++++---------------- hw/intc/apic_common.c | 2 ++ hw/intc/ioapic.c | 32 ++++++++--------------- hw/pci-host/q35.c | 7 ++++++ hw/pci/pci.c | 8 +++++- hw/timer/hpet.c | 6 ++--- include/hw/i386/apic-msidef.h | 4 +++ include/hw/i386/apic_internal.h | 1 + include/hw/i386/ioapic_internal.h | 1 + include/hw/i386/pc.h | 6 +++++ include/hw/pci-host/q35.h | 4 +++ include/hw/pci/pci.h | 2 ++ target-i386/cpu.c | 7 ++++++ target-i386/cpu.h | 2 +- 20 files changed, 156 insertions(+), 78 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 347718f..c371588 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -24,6 +24,7 @@ #include "exec/address-spaces.h" #include "intel_iommu_internal.h" #include "hw/pci/pci.h" +#include "hw/i386/pc.h" /*#define DEBUG_INTEL_IOMMU*/ #ifdef DEBUG_INTEL_IOMMU @@ -266,6 +267,11 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id, g_hash_table_replace(s->iotlb, key, entry); } +static AddressSpace *get_dma_address_space(void) +{ + return &PC_MACHINE(qdev_get_machine())->dma_address_space; +} + /* Given the reg addr of both the message data and address, generate an * interrupt via MSI. */ @@ -282,7 +288,7 @@ static void vtd_generate_interrupt(IntelIOMMUState *s, hwaddr mesg_addr_reg, data = vtd_get_long_raw(s, mesg_data_reg); VTD_DPRINTF(FLOG, "msi: addr 0x%"PRIx64 " data 0x%"PRIx32, addr, data); - address_space_stl_le(&address_space_memory, addr, data, + address_space_stl_le(get_dma_address_space(), addr, data, MEMTXATTRS_UNSPECIFIED, NULL); } @@ -496,7 +502,7 @@ static int vtd_get_root_entry(IntelIOMMUState *s, uint8_t index, dma_addr_t addr; addr = s->root + index * sizeof(*re); - if (dma_memory_read(&address_space_memory, addr, re, sizeof(*re))) { + if (dma_memory_read(get_dma_address_space(), addr, re, sizeof(*re))) { VTD_DPRINTF(GENERAL, "error: fail to access root-entry at 0x%"PRIx64 " + %"PRIu8, s->root, index); re->val = 0; @@ -521,7 +527,7 @@ static int vtd_get_context_entry_from_root(VTDRootEntry *root, uint8_t index, return -VTD_FR_ROOT_ENTRY_P; } addr = (root->val & VTD_ROOT_ENTRY_CTP) + index * sizeof(*ce); - if (dma_memory_read(&address_space_memory, addr, ce, sizeof(*ce))) { + if (dma_memory_read(get_dma_address_space(), addr, ce, sizeof(*ce))) { VTD_DPRINTF(GENERAL, "error: fail to access context-entry at 0x%"PRIx64 " + %"PRIu8, (uint64_t)(root->val & VTD_ROOT_ENTRY_CTP), index); @@ -555,7 +561,7 @@ static uint64_t vtd_get_slpte(dma_addr_t base_addr, uint32_t index) assert(index < VTD_SL_PT_ENTRY_NR); - if (dma_memory_read(&address_space_memory, + if (dma_memory_read(get_dma_address_space(), base_addr + index * sizeof(slpte), &slpte, sizeof(slpte))) { slpte = (uint64_t)-1; @@ -1227,7 +1233,7 @@ static bool vtd_get_inv_desc(dma_addr_t base_addr, uint32_t offset, VTDInvDesc *inv_desc) { dma_addr_t addr = base_addr + offset * sizeof(*inv_desc); - if (dma_memory_read(&address_space_memory, addr, inv_desc, + if (dma_memory_read(get_dma_address_space(), addr, inv_desc, sizeof(*inv_desc))) { VTD_DPRINTF(GENERAL, "error: fail to fetch Invalidation Descriptor " "base_addr 0x%"PRIx64 " offset %"PRIu32, base_addr, offset); @@ -1262,8 +1268,8 @@ static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) VTD_DPRINTF(INV, "status data 0x%x, status addr 0x%"PRIx64, status_data, status_addr); status_data = cpu_to_le32(status_data); - if (dma_memory_write(&address_space_memory, status_addr, &status_data, - sizeof(status_data))) { + if (dma_memory_write(get_dma_address_space(), status_addr, + &status_data, sizeof(status_data))) { VTD_DPRINTF(GENERAL, "error: fail to perform a coherent write"); return false; } @@ -1845,7 +1851,7 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr, VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); IntelIOMMUState *s = vtd_as->iommu_state; IOMMUTLBEntry ret = { - .target_as = &address_space_memory, + .target_as = get_dma_address_space(), .iova = addr, .translated_addr = 0, .addr_mask = ~(hwaddr)0, diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index 694d398..5f55cf1 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -10,6 +10,7 @@ * See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" +#include "hw/i386/apic-msidef.h" #include "hw/i386/apic_internal.h" #include "hw/pci/msi.h" #include "sysemu/kvm.h" @@ -147,14 +148,13 @@ static void kvm_apic_external_nmi(APICCommonState *s) run_on_cpu(CPU(s->cpu), do_inject_external_nmi, s); } -static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t kvm_msi_region_read(void *opaque, hwaddr addr, unsigned size) { return ~(uint64_t)0; } -static void kvm_apic_mem_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) +static void kvm_msi_region_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) { MSIMessage msg = { .address = addr, .data = data }; int ret; @@ -166,10 +166,14 @@ static void kvm_apic_mem_write(void *opaque, hwaddr addr, } } -static const MemoryRegionOps kvm_apic_io_ops = { - .read = kvm_apic_mem_read, - .write = kvm_apic_mem_write, +static const MemoryRegionOps kvm_msi_region_ops = { + .read = kvm_msi_region_read, + .write = kvm_msi_region_write, .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, }; static void kvm_apic_reset(APICCommonState *s) @@ -182,8 +186,10 @@ static void kvm_apic_realize(DeviceState *dev, Error **errp) { APICCommonState *s = APIC_COMMON(dev); - memory_region_init_io(&s->io_memory, NULL, &kvm_apic_io_ops, s, "kvm-apic-msi", - APIC_SPACE_SIZE); + memory_region_init(&s->io_memory, NULL, "kvm-apic", APIC_SPACE_SIZE); + + memory_region_init_io(&s->msi_region, NULL, &kvm_msi_region_ops, NULL, + "kvm-msi", MSI_REGION_SIZE); if (kvm_has_gsi_routing()) { msi_supported = true; diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 0aeefd2..608d903 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -26,6 +26,7 @@ #include "hw/i386/pc.h" #include "hw/char/serial.h" #include "hw/i386/apic.h" +#include "hw/i386/apic-msidef.h" #include "hw/i386/topology.h" #include "sysemu/cpus.h" #include "hw/block/fdc.h" @@ -1281,6 +1282,7 @@ void pc_memory_init(PCMachineState *pcms, FWCfgState *fw_cfg; MachineState *machine = MACHINE(pcms); PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); + MemoryRegion *dma, *mem_alias; assert(machine->ram_size == pcms->below_4g_mem_size + pcms->above_4g_mem_size); @@ -1360,6 +1362,21 @@ void pc_memory_init(PCMachineState *pcms, &pcms->hotplug_memory.mr); } + /* Initialized DMA address space */ + dma = g_malloc(sizeof(*dma)); + memory_region_init(dma, NULL, "dma-container", + memory_region_size(system_memory)); + address_space_init(&pcms->dma_address_space, dma, "pc-dma"); + + mem_alias = g_malloc(sizeof(*mem_alias)); + memory_region_init_alias(mem_alias, NULL, "system-memory", system_memory, + 0, memory_region_size(system_memory)); + memory_region_add_subregion_overlap(dma, 0, mem_alias, 0); + + pci_set_dma_address_space(&pcms->dma_address_space); + pcms->ioapic_msi_target = &pcms->dma_address_space; + pcms->hpet_msi_target = &pcms->dma_address_space; + /* Initialize PC system firmware */ pc_system_firmware_init(rom_memory, !pcmc->pci_enabled); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 6f8c2cd..21ac546 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -126,7 +126,6 @@ static void pc_init1(MachineState *machine, } pc_cpus_init(pcms); - if (kvm_enabled() && pcmc->kvmclock_enabled) { kvmclock_create(); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 46522c9..13fc647 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -113,10 +113,6 @@ static void pc_q35_init(MachineState *machine) xen_hvm_init(pcms, &ram_memory); } - pc_cpus_init(pcms); - - kvmclock_create(); - /* pci enabled */ if (pcmc->pci_enabled) { pci_memory = g_new(MemoryRegion, 1); @@ -143,6 +139,13 @@ static void pc_q35_init(MachineState *machine) rom_memory, &ram_memory); } + pc_cpus_init(pcms); + if (!pcmc->has_acpi_build) { + /* only machine types 1.7 & older need this */ + pc_acpi_init("q35-acpi-dsdt.aml"); + } + + kvmclock_create(); /* irq lines */ gsi_state = g_malloc0(sizeof(*gsi_state)); if (kvm_irqchip_in_kernel()) { diff --git a/hw/i386/xen/xen_apic.c b/hw/i386/xen/xen_apic.c index 2b8d709..71d52f4 100644 --- a/hw/i386/xen/xen_apic.c +++ b/hw/i386/xen/xen_apic.c @@ -10,18 +10,18 @@ * later. See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" +#include "hw/i386/apic-msidef.h" #include "hw/i386/apic_internal.h" #include "hw/pci/msi.h" #include "hw/xen/xen.h" -static uint64_t xen_apic_mem_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t xen_msi_region_read(void *opaque, hwaddr addr, unsigned size) { return ~(uint64_t)0; } -static void xen_apic_mem_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) +static void xen_msi_region_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) { if (size != sizeof(uint32_t)) { fprintf(stderr, "Xen: APIC write data size = %d, invalid\n", size); @@ -31,10 +31,14 @@ static void xen_apic_mem_write(void *opaque, hwaddr addr, xen_hvm_inject_msi(addr, data); } -static const MemoryRegionOps xen_apic_io_ops = { - .read = xen_apic_mem_read, - .write = xen_apic_mem_write, +static const MemoryRegionOps xen_msi_region_ops = { + .read = xen_msi_region_read, + .write = xen_msi_region_write, .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, }; static void xen_apic_realize(DeviceState *dev, Error **errp) @@ -42,8 +46,10 @@ static void xen_apic_realize(DeviceState *dev, Error **errp) APICCommonState *s = APIC_COMMON(dev); s->vapic_control = 0; - memory_region_init_io(&s->io_memory, OBJECT(s), &xen_apic_io_ops, s, - "xen-apic-msi", APIC_SPACE_SIZE); + memory_region_init(&s->io_memory, NULL, "xen-apic", APIC_SPACE_SIZE); + + memory_region_init_io(&s->msi_region, NULL, &xen_msi_region_ops, NULL, + "xen-msi", MSI_REGION_SIZE); msi_supported = true; } diff --git a/hw/intc/apic.c b/hw/intc/apic.c index a299462..2e99f75 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -732,31 +732,11 @@ static uint32_t apic_mem_readl(void *opaque, hwaddr addr) return val; } -static void apic_send_msi(hwaddr addr, uint32_t data) -{ - uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; - uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; - uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1; - uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1; - uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7; - /* XXX: Ignore redirection hint. */ - apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode); -} - static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val) { DeviceState *dev; APICCommonState *s; int index = (addr >> 4) & 0xff; - if (addr > 0xfff || !index) { - /* MSI and MMIO APIC are at the same memory location, - * but actually not on the global bus: MSI is on PCI bus - * APIC is connected directly to the CPU. - * Mapping them on the global bus happens to work because - * MSI registers are reserved in APIC MMIO and vice versa. */ - apic_send_msi(addr, val); - return; - } dev = cpu_get_current_apic(); if (!dev) { @@ -856,6 +836,34 @@ static void apic_post_load(APICCommonState *s) } } +static void msi_region_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) +{ + uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; + uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; + uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1; + uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1; + uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7; + /* FIXME: Ignoring redirection hint. */ + + apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode); +} + +static uint64_t msi_region_read(void *opaque, hwaddr addr, unsigned size) +{ + return ~(uint64_t)0; +} + +static const MemoryRegionOps msi_region_ops = { + .write = msi_region_write, + .read = msi_region_read, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + static const MemoryRegionOps apic_io_ops = { .old_mmio = { .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, }, @@ -868,9 +876,12 @@ static void apic_realize(DeviceState *dev, Error **errp) { APICCommonState *s = APIC_COMMON(dev); - memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi", + memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic", APIC_SPACE_SIZE); + memory_region_init_io(&s->msi_region, NULL, &msi_region_ops, NULL, "msi", + MSI_REGION_SIZE); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s); local_apics[s->idx] = s; diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 659f377..b54eb7c 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -19,7 +19,9 @@ */ #include "qemu/osdep.h" #include "hw/i386/apic.h" +#include "hw/i386/apic-msidef.h" #include "hw/i386/apic_internal.h" +#include "hw/i386/pc.h" #include "trace.h" #include "sysemu/kvm.h" #include "hw/qdev.h" diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index 378e663..7bc7ee4 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -23,6 +23,7 @@ #include "qemu/osdep.h" #include "monitor/monitor.h" #include "hw/hw.h" +#include "hw/i386/apic-msidef.h" #include "hw/i386/pc.h" #include "hw/i386/ioapic.h" #include "hw/i386/ioapic_internal.h" @@ -49,31 +50,31 @@ extern int ioapic_no; static void ioapic_service(IOAPICCommonState *s) { + AddressSpace *msi_as = PC_MACHINE(qdev_get_machine())->ioapic_msi_target; + uint32_t addr, data; uint8_t i; uint8_t trig_mode; uint8_t vector; uint8_t delivery_mode; uint32_t mask; uint64_t entry; - uint8_t dest; + uint16_t dest_idx; uint8_t dest_mode; for (i = 0; i < IOAPIC_NUM_PINS; i++) { mask = 1 << i; if (s->irr & mask) { - int coalesce = 0; entry = s->ioredtbl[i]; if (!(entry & IOAPIC_LVT_MASKED)) { trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1); - dest = entry >> IOAPIC_LVT_DEST_SHIFT; + dest_idx = entry >> IOAPIC_LVT_DEST_IDX_SHIFT; dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1; delivery_mode = (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK; if (trig_mode == IOAPIC_TRIGGER_EDGE) { s->irr &= ~mask; } else { - coalesce = s->ioredtbl[i] & IOAPIC_LVT_REMOTE_IRR; s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR; } if (delivery_mode == IOAPIC_DM_EXTINT) { @@ -81,23 +82,12 @@ static void ioapic_service(IOAPICCommonState *s) } else { vector = entry & IOAPIC_VECTOR_MASK; } -#ifdef CONFIG_KVM - if (kvm_irqchip_is_split()) { - if (trig_mode == IOAPIC_TRIGGER_EDGE) { - kvm_set_irq(kvm_state, i, 1); - kvm_set_irq(kvm_state, i, 0); - } else { - if (!coalesce) { - kvm_set_irq(kvm_state, i, 1); - } - } - continue; - } -#else - (void)coalesce; -#endif - apic_deliver_irq(dest, dest_mode, delivery_mode, vector, - trig_mode); + addr = MSI_ADDR_BASE | (dest_idx << MSI_ADDR_DEST_IDX_SHIFT) | + (dest_mode << MSI_ADDR_DEST_MODE_SHIFT); + data = (vector << MSI_DATA_VECTOR_SHIFT) | + (trig_mode << MSI_DATA_TRIGGER_SHIFT) | + (delivery_mode << MSI_DATA_DELIVERY_MODE_SHIFT); + stl_le_phys(msi_as, addr, data); } } } diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 115fb8c..566e3d8 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -436,6 +436,7 @@ static AddressSpace *q35_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) static void mch_init_dmar(MCHPCIState *mch) { + PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); PCIBus *pci_bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); mch->iommu = INTEL_IOMMU_DEVICE(qdev_create(NULL, TYPE_INTEL_IOMMU_DEVICE)); @@ -445,6 +446,12 @@ static void mch_init_dmar(MCHPCIState *mch) sysbus_mmio_map(SYS_BUS_DEVICE(mch->iommu), 0, Q35_HOST_BRIDGE_IOMMU_ADDR); pci_setup_iommu(pci_bus, q35_host_dma_iommu, mch->iommu); + + pcms->ioapic_msi_target = q35_host_dma_iommu(pci_bus, mch->iommu, + Q35_PSEUDO_DEVFN_IOAPIC); + + pcms->hpet_msi_target = q35_host_dma_iommu(pci_bus, mch->iommu, + Q35_PSEUDO_DEVFN_HPET); } static void mch_realize(PCIDevice *d, Error **errp) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index e67664d..bad2055 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -52,6 +52,7 @@ static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); static char *pcibus_get_dev_path(DeviceState *dev); static char *pcibus_get_fw_dev_path(DeviceState *dev); static void pcibus_reset(BusState *qbus); +static AddressSpace *pci_dma_address_space = &address_space_memory; static Property pci_props[] = { DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), @@ -2396,6 +2397,11 @@ static void pci_device_class_init(ObjectClass *klass, void *data) pc->realize = pci_default_realize; } +void pci_set_dma_address_space(AddressSpace *dma_address_space) +{ + pci_dma_address_space = dma_address_space; +} + AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) { PCIBus *bus = PCI_BUS(dev->bus); @@ -2407,7 +2413,7 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) if (iommu_bus && iommu_bus->iommu_fn) { return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, dev->devfn); } - return &address_space_memory; + return pci_dma_address_space; } void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque) diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index 0ad5420..f36ae68 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -208,9 +208,9 @@ static void update_irq(struct HPETTimer *timer, int set) } } } else if (timer_fsb_route(timer)) { - address_space_stl_le(&address_space_memory, timer->fsb >> 32, - timer->fsb & 0xffffffff, MEMTXATTRS_UNSPECIFIED, - NULL); + address_space_stl_le(PC_MACHINE(qdev_get_machine())->hpet_msi_target, + timer->fsb >> 32, timer->fsb & 0xffffffff, + MEMTXATTRS_UNSPECIFIED, NULL); } else if (timer->config & HPET_TN_TYPE_LEVEL) { s->isr |= mask; /* fold the ICH PIRQ# pin's internal inversion logic into hpet */ diff --git a/include/hw/i386/apic-msidef.h b/include/hw/i386/apic-msidef.h index 6e2eb71..5052f23 100644 --- a/include/hw/i386/apic-msidef.h +++ b/include/hw/i386/apic-msidef.h @@ -5,6 +5,9 @@ * Intel APIC constants: from include/asm/msidef.h */ +#define MSI_ADDR_BASE 0xfee00000 +#define MSI_REGION_SIZE 0x00100000 + /* * Shifts for MSI data */ @@ -25,6 +28,7 @@ #define MSI_ADDR_REDIRECTION_SHIFT 3 #define MSI_ADDR_DEST_ID_SHIFT 12 +#define MSI_ADDR_DEST_IDX_SHIFT 4 #define MSI_ADDR_DEST_ID_MASK 0x00ffff0 #endif /* HW_APIC_MSIDEF_H */ diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index 74fe935..ad5ffe5 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -154,6 +154,7 @@ struct APICCommonState { /*< public >*/ MemoryRegion io_memory; + MemoryRegion msi_region; X86CPU *cpu; uint32_t apicbase; uint8_t id; diff --git a/include/hw/i386/ioapic_internal.h b/include/hw/i386/ioapic_internal.h index 797ed47..d279f2d 100644 --- a/include/hw/i386/ioapic_internal.h +++ b/include/hw/i386/ioapic_internal.h @@ -31,6 +31,7 @@ #define IOAPIC_VERSION 0x11 #define IOAPIC_LVT_DEST_SHIFT 56 +#define IOAPIC_LVT_DEST_IDX_SHIFT 48 #define IOAPIC_LVT_MASKED_SHIFT 16 #define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15 #define IOAPIC_LVT_REMOTE_IRR_SHIFT 14 diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 8b3546e..1bdabf6 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -36,6 +36,9 @@ /** * PCMachineState: * @acpi_dev: link to ACPI PM device that performs ACPI hotplug handling + * @dma_address_space: target address space for DMA from I/O devices + * @ioapic_msi_target: target address space for IOAPIC interrupt messages + * @hpet_msi_target: target address space for HPET interrupt messages */ struct PCMachineState { /*< private >*/ @@ -65,6 +68,9 @@ struct PCMachineState { /* CPU and apic information: */ bool apic_xrupt_override; unsigned apic_id_limit; + AddressSpace dma_address_space; + AddressSpace *ioapic_msi_target; + AddressSpace *hpet_msi_target; /* NUMA information: */ uint64_t numa_nodes; diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index c5c073d..fc87013 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -74,6 +74,10 @@ typedef struct Q35PCIHost { #define Q35_MASK(bit, ms_bit, ls_bit) \ ((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1))) +#define Q35_PSEUDO_BUS_PLATFORM 0xff +#define Q35_PSEUDO_DEVFN_IOAPIC 0x01 +#define Q35_PSEUDO_DEVFN_HPET 0x02 + /* * gmch part */ diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 0be07c8..d37b546 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -417,6 +417,8 @@ void pci_bus_get_w64_range(PCIBus *bus, Range *range); void pci_device_deassert_intx(PCIDevice *dev); +void pci_set_dma_address_space(AddressSpace *dma_address_space); + typedef AddressSpace *(*PCIIOMMUFunc)(PCIBus *, void *, int); AddressSpace *pci_device_iommu_address_space(PCIDevice *dev); diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 0f38d1e..6ac1382 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -23,6 +23,8 @@ #include "sysemu/cpus.h" #include "kvm_i386.h" +#include "hw/i386/pc.h" +#include "hw/i386/apic-msidef.h" #include "qemu/error-report.h" #include "qemu/option.h" #include "qemu/config-file.h" @@ -2821,6 +2823,7 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) { APICCommonState *apic; static bool apic_mmio_map_once; + AddressSpace *dma_as; if (cpu->apic_state == NULL) { return; @@ -2836,6 +2839,10 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) MSR_IA32_APICBASE_BASE, &apic->io_memory, 0x1000); + + dma_as = &PC_MACHINE(qdev_get_machine())->dma_address_space; + memory_region_add_subregion_overlap(dma_as->root, MSI_ADDR_BASE, + &apic->msi_region, 1); apic_mmio_map_once = true; } } diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 5148c82..fddca76 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1376,7 +1376,7 @@ const char *get_register_name_32(unsigned int reg); void enable_compat_apic_id_mode(void); #define APIC_DEFAULT_ADDRESS 0xfee00000 -#define APIC_SPACE_SIZE 0x100000 +#define APIC_SPACE_SIZE 0x1000 void x86_cpu_dump_local_apic_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, int flags);