From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528386934622167.39977260099988; Thu, 7 Jun 2018 08:55:34 -0700 (PDT) Received: from localhost ([::1]:58775 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxG9-0005uI-Sx for importer@patchew.org; Thu, 07 Jun 2018 11:55:33 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38529) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxBE-0001SZ-NL for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxBA-0003Ai-1B for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:28 -0400 Received: from 9.mo179.mail-out.ovh.net ([46.105.76.148]:47310) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxB9-00039v-Gs for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:23 -0400 Received: from player169.ha.ovh.net (unknown [10.109.120.18]) by mo179.mail-out.ovh.net (Postfix) with ESMTP id 8D51BCEA88 for ; Thu, 7 Jun 2018 17:50:21 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id EC57E58009D; Thu, 7 Jun 2018 17:50:15 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:36 +0200 Message-Id: <20180607155003.1580-2-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6070007875059878739 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.76.148 Subject: [Qemu-devel] [PATCH v4 01/28] sparp_pci: simplify how the PCI LSIs are allocated 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" PCI LSIs are today allocated one by one using the IRQ alloc_block routine. Change the code sequence to first allocate a PCI_NUM_PINS block. It will help us providing a generic IRQ framework to the machine. Signed-off-by: C=C3=A9dric Le Goater Reviewed-by: Greg Kurz Signed-off-by: C=C3=A9dric Le Goater --- hw/ppc/spapr_pci.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 39a14980d397..4fd97ffe4c6e 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1546,6 +1546,8 @@ static void spapr_phb_realize(DeviceState *dev, Error= **errp) sPAPRTCETable *tcet; const unsigned windows_supported =3D sphb->ddw_enabled ? SPAPR_PCI_DMA_MAX_WINDOWS : 1; + uint32_t irq; + Error *local_err =3D NULL; =20 if (!spapr) { error_setg(errp, TYPE_SPAPR_PCI_HOST_BRIDGE " needs a pseries mach= ine"); @@ -1694,18 +1696,15 @@ static void spapr_phb_realize(DeviceState *dev, Err= or **errp) QLIST_INSERT_HEAD(&spapr->phbs, sphb, list); =20 /* Initialize the LSI table */ - for (i =3D 0; i < PCI_NUM_PINS; i++) { - uint32_t irq; - Error *local_err =3D NULL; - - irq =3D spapr_irq_alloc_block(spapr, 1, true, false, &local_err); - if (local_err) { - error_propagate(errp, local_err); - error_prepend(errp, "can't allocate LSIs: "); - return; - } + irq =3D spapr_irq_alloc_block(spapr, PCI_NUM_PINS, true, false, &local= _err); + if (local_err) { + error_propagate(errp, local_err); + error_prepend(errp, "can't allocate LSIs: "); + return; + } =20 - sphb->lsi_table[i].irq =3D irq; + for (i =3D 0; i < PCI_NUM_PINS; i++) { + sphb->lsi_table[i].irq =3D irq + i; } =20 /* allocate connectors for child PCI devices */ --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528386781075215.9312179083928; Thu, 7 Jun 2018 08:53:01 -0700 (PDT) Received: from localhost ([::1]:58759 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxDg-00034g-7N for importer@patchew.org; Thu, 07 Jun 2018 11:53:00 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38584) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxBM-0001bi-Aj for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxBH-0003MC-7k for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:36 -0400 Received: from 9.mo177.mail-out.ovh.net ([46.105.72.238]:51231) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxBG-0003JS-MM for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:31 -0400 Received: from player169.ha.ovh.net (unknown [10.109.122.40]) by mo177.mail-out.ovh.net (Postfix) with ESMTP id 28891B5995 for ; Thu, 7 Jun 2018 17:50:27 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 681F3580091; Thu, 7 Jun 2018 17:50:21 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:37 +0200 Message-Id: <20180607155003.1580-3-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6071415250584505171 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.72.238 Subject: [Qemu-devel] [PATCH v4 02/28] spapr: introduce a generic IRQ frontend to the machine 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" This proposal moves all the related IRQ routines of the sPAPR machine behind a sPAPR IRQ backend interface 'spapr_irq' to prepare for future changes in the sPAPR IRQ controller modeling. First of which is a reorganization of the sPAPR IRQ number space layout and a second, coming later, will be to integrate the support for the new POWER9 XIVE IRQ controller. The new interface defines a set of fixed IRQ number ranges, for each IRQ type, in which devices allocate the IRQ numbers they need depending on a unique device index. The layout is : SPAPR_IRQ_IPI 0x0 /* 1 IRQ per CPU */ SPAPR_IRQ_EPOW 0x1000 /* 1 IRQ per device */ SPAPR_IRQ_HOTPLUG 0x1001 /* 1 IRQ per device */ SPAPR_IRQ_VIO 0x1100 /* 1 IRQ per device */ SPAPR_IRQ_PCI_LSI 0x1200 /* 4 IRQs per device */ SPAPR_IRQ_PCI_MSI 0x1400 /* 1K IRQs per device */ The IPI range is reserved for future use when XIVE support comes in. The 'spapr_irq' handlers encompass the previous needs and the new ones and seem complex but the provided sPAPR IRQ backend for XICS should implement what we have today without any functional changes. Each device model is modified to take the new interface into account using the IRQ range/type definitions and a device index. A part from the VIO devices, lacking an id, the changes are relatively simple. Signed-off-by: C=C3=A9dric Le Goater Reviewed-by: Greg Kurz Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/spapr.h | 11 +- include/hw/ppc/spapr_irq.h | 50 ++++++++ hw/ppc/spapr.c | 196 +----------------------------- hw/ppc/spapr_events.c | 8 +- hw/ppc/spapr_irq.c | 291 +++++++++++++++++++++++++++++++++++++++++= ++++ hw/ppc/spapr_pci.c | 21 +++- hw/ppc/spapr_vio.c | 17 ++- hw/ppc/Makefile.objs | 2 +- 8 files changed, 384 insertions(+), 212 deletions(-) create mode 100644 include/hw/ppc/spapr_irq.h create mode 100644 hw/ppc/spapr_irq.c diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 3388750fc795..aba1892f2bd0 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -3,10 +3,10 @@ =20 #include "sysemu/dma.h" #include "hw/boards.h" -#include "hw/ppc/xics.h" #include "hw/ppc/spapr_drc.h" #include "hw/mem/pc-dimm.h" #include "hw/ppc/spapr_ovec.h" +#include "hw/ppc/spapr_irq.h" =20 struct VIOsPAPRBus; struct sPAPRPHBState; @@ -104,6 +104,7 @@ struct sPAPRMachineClass { unsigned n_dma, uint32_t *liobns, Error **errp); sPAPRResizeHPT resize_hpt_default; sPAPRCapabilities default_caps; + sPAPRIrq *irq; }; =20 /** @@ -772,14 +773,6 @@ int spapr_get_vcpu_id(PowerPCCPU *cpu); void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp); PowerPCCPU *spapr_find_cpu(int vcpu_id); =20 -int spapr_irq_alloc(sPAPRMachineState *spapr, int irq_hint, bool lsi, - Error **errp); -int spapr_irq_alloc_block(sPAPRMachineState *spapr, int num, bool lsi, - bool align, Error **errp); -void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num); -qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq); - - int spapr_caps_pre_load(void *opaque); int spapr_caps_pre_save(void *opaque); =20 diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h new file mode 100644 index 000000000000..67ec7ff162a6 --- /dev/null +++ b/include/hw/ppc/spapr_irq.h @@ -0,0 +1,50 @@ +/* + * QEMU PowerPC sPAPR IRQ backend definitions + * + * Copyright (c) 2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ +#ifndef HW_SPAPR_IRQ_H +#define HW_SPAPR_IRQ_H + +#include "hw/ppc/xics.h" + +/* + * IRQ ranges per type + */ +#define SPAPR_IRQ_IPI 0x0 /* 1 IRQ per CPU */ +#define SPAPR_IRQ_EPOW 0x1000 /* 1 IRQ per device */ +#define SPAPR_IRQ_HOTPLUG 0x1001 /* 1 IRQ per device */ +#define SPAPR_IRQ_VIO 0x1100 /* 1 IRQ per device */ +#define SPAPR_IRQ_PCI_LSI 0x1200 /* 4 IRQs per device */ +#define SPAPR_IRQ_PCI_MSI 0x1400 /* 1K IRQs per device covered by + * a bitmap allocator */ +typedef struct sPAPRIrq { + uint32_t nr_irqs; + + void (*init)(sPAPRMachineState *spapr, Error **errp); + int (*assign)(sPAPRMachineState *spapr, uint32_t range, uint32_t irq, + Error **errp); + int (*alloc)(sPAPRMachineState *spapr, uint32_t range, uint32_t index, + Error **errp); + int (*alloc_block)(sPAPRMachineState *spapr, uint32_t range, + uint32_t index, int num, bool align, Error **errp); + void (*free)(sPAPRMachineState *spapr, int irq, int num, Error **errp); + qemu_irq (*qirq)(sPAPRMachineState *spapr, int irq); + void (*print_info)(sPAPRMachineState *spapr, Monitor *mon); +} sPAPRIrq; + +extern sPAPRIrq spapr_irq_xics; + +int spapr_irq_assign(sPAPRMachineState *spapr, uint32_t range, uint32_t ir= q, + Error **errp); +int spapr_irq_alloc(sPAPRMachineState *spapr, uint32_t range, uint32_t ind= ex, + Error **errp); +int spapr_irq_alloc_block(sPAPRMachineState *spapr, uint32_t range, + uint32_t index, int num, bool align, Error **err= p); +void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num, Error **er= rp); +qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq); + +#endif /* HW_SPAPR_IRQ_H */ diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 2375cbee1208..fd37ca4803eb 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -116,33 +116,6 @@ static bool spapr_is_thread0_in_vcore(sPAPRMachineStat= e *spapr, return spapr_get_vcpu_id(cpu) % spapr->vsmt =3D=3D 0; } =20 -static ICSState *spapr_ics_create(sPAPRMachineState *spapr, - const char *type_ics, - int nr_irqs, Error **errp) -{ - Error *local_err =3D NULL; - Object *obj; - - obj =3D object_new(type_ics); - object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort); - object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), - &error_abort); - object_property_set_int(obj, nr_irqs, "nr-irqs", &local_err); - if (local_err) { - goto error; - } - object_property_set_bool(obj, true, "realized", &local_err); - if (local_err) { - goto error; - } - - return ICS_SIMPLE(obj); - -error: - error_propagate(errp, local_err); - return NULL; -} - static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque) { /* Dummy entries correspond to unused ICPState objects in older QEMUs, @@ -183,32 +156,6 @@ static int xics_max_server_number(sPAPRMachineState *s= papr) return DIV_ROUND_UP(max_cpus * spapr->vsmt, smp_threads); } =20 -static void xics_system_init(MachineState *machine, int nr_irqs, Error **e= rrp) -{ - sPAPRMachineState *spapr =3D SPAPR_MACHINE(machine); - - if (kvm_enabled()) { - if (machine_kernel_irqchip_allowed(machine) && - !xics_kvm_init(spapr, errp)) { - spapr->icp_type =3D TYPE_KVM_ICP; - spapr->ics =3D spapr_ics_create(spapr, TYPE_ICS_KVM, nr_irqs, = errp); - } - if (machine_kernel_irqchip_required(machine) && !spapr->ics) { - error_prepend(errp, "kernel_irqchip requested but unavailable:= "); - return; - } - } - - if (!spapr->ics) { - xics_spapr_init(spapr); - spapr->icp_type =3D TYPE_ICP; - spapr->ics =3D spapr_ics_create(spapr, TYPE_ICS_SIMPLE, nr_irqs, e= rrp); - if (!spapr->ics) { - return; - } - } -} - static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu, int smt_threads) { @@ -2582,7 +2529,7 @@ static void spapr_machine_init(MachineState *machine) load_limit =3D MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD; =20 /* Set up Interrupt Controller before we create the VCPUs */ - xics_system_init(machine, XICS_IRQS_SPAPR, &error_fatal); + smc->irq->init(spapr, &error_fatal); =20 /* Set up containers for ibm,client-architecture-support negotiated op= tions */ @@ -3768,149 +3715,13 @@ static ICPState *spapr_icp_get(XICSFabric *xi, int= vcpu_id) return cpu ? ICP(cpu->intc) : NULL; } =20 -#define ICS_IRQ_FREE(ics, srcno) \ - (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) - -static int ics_find_free_block(ICSState *ics, int num, int alignnum) -{ - int first, i; - - for (first =3D 0; first < ics->nr_irqs; first +=3D alignnum) { - if (num > (ics->nr_irqs - first)) { - return -1; - } - for (i =3D first; i < first + num; ++i) { - if (!ICS_IRQ_FREE(ics, i)) { - break; - } - } - if (i =3D=3D (first + num)) { - return first; - } - } - - return -1; -} - -/* - * Allocate the IRQ number and set the IRQ type, LSI or MSI - */ -static void spapr_irq_set_lsi(sPAPRMachineState *spapr, int irq, bool lsi) -{ - ics_set_irq_type(spapr->ics, irq - spapr->ics->offset, lsi); -} - -int spapr_irq_alloc(sPAPRMachineState *spapr, int irq_hint, bool lsi, - Error **errp) -{ - ICSState *ics =3D spapr->ics; - int irq; - - assert(ics); - - if (irq_hint) { - if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) { - error_setg(errp, "can't allocate IRQ %d: already in use", irq_= hint); - return -1; - } - irq =3D irq_hint; - } else { - irq =3D ics_find_free_block(ics, 1, 1); - if (irq < 0) { - error_setg(errp, "can't allocate IRQ: no IRQ left"); - return -1; - } - irq +=3D ics->offset; - } - - spapr_irq_set_lsi(spapr, irq, lsi); - trace_spapr_irq_alloc(irq); - - return irq; -} - -/* - * Allocate block of consecutive IRQs, and return the number of the first = IRQ in - * the block. If align=3D=3Dtrue, aligns the first IRQ number to num. - */ -int spapr_irq_alloc_block(sPAPRMachineState *spapr, int num, bool lsi, - bool align, Error **errp) -{ - ICSState *ics =3D spapr->ics; - int i, first =3D -1; - - assert(ics); - - /* - * MSIMesage::data is used for storing VIRQ so - * it has to be aligned to num to support multiple - * MSI vectors. MSI-X is not affected by this. - * The hint is used for the first IRQ, the rest should - * be allocated continuously. - */ - if (align) { - assert((num =3D=3D 1) || (num =3D=3D 2) || (num =3D=3D 4) || - (num =3D=3D 8) || (num =3D=3D 16) || (num =3D=3D 32)); - first =3D ics_find_free_block(ics, num, num); - } else { - first =3D ics_find_free_block(ics, num, 1); - } - if (first < 0) { - error_setg(errp, "can't find a free %d-IRQ block", num); - return -1; - } - - first +=3D ics->offset; - for (i =3D first; i < first + num; ++i) { - spapr_irq_set_lsi(spapr, i, lsi); - } - - trace_spapr_irq_alloc_block(first, num, lsi, align); - - return first; -} - -void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num) -{ - ICSState *ics =3D spapr->ics; - int srcno =3D irq - ics->offset; - int i; - - if (ics_valid_irq(ics, irq)) { - trace_spapr_irq_free(0, irq, num); - for (i =3D srcno; i < srcno + num; ++i) { - if (ICS_IRQ_FREE(ics, i)) { - trace_spapr_irq_free_warn(0, i + ics->offset); - } - memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); - } - } -} - -qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq) -{ - ICSState *ics =3D spapr->ics; - - if (ics_valid_irq(ics, irq)) { - return ics->qirqs[irq - ics->offset]; - } - - return NULL; -} - static void spapr_pic_print_info(InterruptStatsProvider *obj, Monitor *mon) { sPAPRMachineState *spapr =3D SPAPR_MACHINE(obj); - CPUState *cs; - - CPU_FOREACH(cs) { - PowerPCCPU *cpu =3D POWERPC_CPU(cs); - - icp_pic_print_info(ICP(cpu->intc), mon); - } + sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(spapr); =20 - ics_pic_print_info(spapr->ics, mon); + smc->irq->print_info(spapr, mon); } =20 int spapr_get_vcpu_id(PowerPCCPU *cpu) @@ -4019,6 +3830,7 @@ static void spapr_machine_class_init(ObjectClass *oc,= void *data) smc->default_caps.caps[SPAPR_CAP_SBBC] =3D SPAPR_CAP_BROKEN; smc->default_caps.caps[SPAPR_CAP_IBS] =3D SPAPR_CAP_BROKEN; spapr_caps_add_properties(smc, &error_abort); + smc->irq =3D &spapr_irq_xics; } =20 static const TypeInfo spapr_machine_info =3D { diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index 86836f0626dc..f131b8c6fd1b 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -712,8 +712,8 @@ void spapr_events_init(sPAPRMachineState *spapr) spapr->event_sources =3D spapr_event_sources_new(); =20 spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_EPOW, - spapr_irq_alloc(spapr, 0, false, - &error_fatal)); + spapr_irq_alloc(spapr, SPAPR_IRQ_EPOW, + 0, &error_fatal)); =20 /* NOTE: if machine supports modern/dedicated hotplug event source, * we add it to the device-tree unconditionally. This means we may @@ -725,8 +725,8 @@ void spapr_events_init(sPAPRMachineState *spapr) */ if (spapr->use_hotplug_event_source) { spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_HOT= _PLUG, - spapr_irq_alloc(spapr, 0, false, - &error_fatal)); + spapr_irq_alloc(spapr, SPAPR_IRQ_HOTP= LUG, + 0, &error_fatal)); } =20 spapr->epow_notifier.notify =3D spapr_powerdown_req; diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c new file mode 100644 index 000000000000..1efccf590899 --- /dev/null +++ b/hw/ppc/spapr_irq.c @@ -0,0 +1,291 @@ +/* + * QEMU PowerPC sPAPR IRQ interface + * + * Copyright (c) 2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "hw/pci/pci.h" +#include "hw/ppc/spapr.h" +#include "sysemu/kvm.h" +#include "trace.h" + +/* + * Legacy XICS IRQ backend. + * + * The device IRQ 'range' is used to identify LSIs, and the device + * 'index' is unused + */ +static ICSState *spapr_ics_create(sPAPRMachineState *spapr, + const char *type_ics, + int nr_irqs, Error **errp) +{ + Error *local_err =3D NULL; + Object *obj; + + obj =3D object_new(type_ics); + object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort); + object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), + &error_abort); + object_property_set_int(obj, nr_irqs, "nr-irqs", &local_err); + if (local_err) { + goto error; + } + object_property_set_bool(obj, true, "realized", &local_err); + if (local_err) { + goto error; + } + + return ICS_SIMPLE(obj); + +error: + error_propagate(errp, local_err); + return NULL; +} + +static void spapr_irq_init_legacy(sPAPRMachineState *spapr, Error **errp) +{ + MachineState *machine =3D MACHINE(spapr); + sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(machine); + uint32_t nr_irqs =3D smc->irq->nr_irqs; + + if (kvm_enabled()) { + if (machine_kernel_irqchip_allowed(machine) && + !xics_kvm_init(spapr, errp)) { + spapr->icp_type =3D TYPE_KVM_ICP; + spapr->ics =3D spapr_ics_create(spapr, TYPE_ICS_KVM, nr_irqs, = errp); + } + if (machine_kernel_irqchip_required(machine) && !spapr->ics) { + error_prepend(errp, "kernel_irqchip requested but unavailable:= "); + return; + } + } + + if (!spapr->ics) { + xics_spapr_init(spapr); + spapr->icp_type =3D TYPE_ICP; + spapr->ics =3D spapr_ics_create(spapr, TYPE_ICS_SIMPLE, nr_irqs, e= rrp); + if (!spapr->ics) { + return; + } + } +} + +#define ICS_IRQ_FREE(ics, srcno) \ + (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) + +static int ics_find_free_block(ICSState *ics, int num, int alignnum) +{ + int first, i; + + for (first =3D 0; first < ics->nr_irqs; first +=3D alignnum) { + if (num > (ics->nr_irqs - first)) { + return -1; + } + for (i =3D first; i < first + num; ++i) { + if (!ICS_IRQ_FREE(ics, i)) { + break; + } + } + if (i =3D=3D (first + num)) { + return first; + } + } + + return -1; +} + +/* + * The 'irq' assignment is only used by the sPAPR VIO devices and it + * has been deprecated in QEMU 3.0. This handler should be removed + * soon. + */ +static int spapr_irq_assign_legacy(sPAPRMachineState *spapr, uint32_t rang= e, + uint32_t irq, Error **errp) +{ + ICSState *ics =3D spapr->ics; + + assert(ics); + assert(range =3D=3D SPAPR_IRQ_VIO); + + if (!ics_valid_irq(ics, irq)) { + error_setg(errp, "IRQ hint %d is invalid", irq); + return -1; + } + + if (!ICS_IRQ_FREE(ics, irq - ics->offset)) { + error_setg(errp, "can't allocate IRQ %d: already in use", + irq); + return -1; + } + + ics_set_irq_type(ics, irq - ics->offset, false); + trace_spapr_irq_alloc(irq); + + return irq; +} + +static int spapr_irq_alloc_legacy(sPAPRMachineState *spapr, uint32_t range, + uint32_t index, Error **errp) +{ + ICSState *ics =3D spapr->ics; + bool lsi =3D (range =3D=3D SPAPR_IRQ_PCI_LSI); + int srcno; + + assert(ics); + + srcno =3D ics_find_free_block(ics, 1, 1); + if (srcno < 0) { + error_setg(errp, "can't allocate IRQ: no IRQ left"); + return -1; + } + + ics_set_irq_type(ics, srcno, lsi); + trace_spapr_irq_alloc(srcno); + + return srcno + ics->offset; +} + +/* + * Allocate block of consecutive IRQs, and return the number of the + * first IRQ in the block. If align=3D=3Dtrue, aligns the first IRQ number + * to num. + */ +static int spapr_irq_alloc_block_legacy(sPAPRMachineState *spapr, + uint32_t range, uint32_t index, in= t num, + bool align, Error **errp) +{ + ICSState *ics =3D spapr->ics; + bool lsi =3D (range =3D=3D SPAPR_IRQ_PCI_LSI); + int i, srcno; + + assert(ics); + + /* + * MSIMessage::data is used for storing VIRQ so it has to be + * aligned to num to support multiple MSI vectors. MSI-X is not + * affected by this. + */ + if (align) { + assert((num =3D=3D 1) || (num =3D=3D 2) || (num =3D=3D 4) || + (num =3D=3D 8) || (num =3D=3D 16) || (num =3D=3D 32)); + srcno =3D ics_find_free_block(ics, num, num); + } else { + srcno =3D ics_find_free_block(ics, num, 1); + } + + if (srcno < 0) { + error_setg(errp, "can't find a free %d-IRQ block", num); + return -1; + } + + for (i =3D srcno; i < srcno + num; ++i) { + ics_set_irq_type(ics, i, lsi); + } + + trace_spapr_irq_alloc_block(srcno, num, lsi, align); + + return ics->offset + srcno; +} + +static void spapr_irq_free_legacy(sPAPRMachineState *spapr, int irq, int n= um, + Error **errp) +{ + ICSState *ics =3D spapr->ics; + uint32_t srcno =3D irq - ics->offset; + int i; + + if (ics_valid_irq(ics, irq)) { + trace_spapr_irq_free(0, irq, num); + for (i =3D srcno; i < srcno + num; ++i) { + if (ICS_IRQ_FREE(ics, i)) { + trace_spapr_irq_free_warn(0, i); + } + memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); + } + } +} + +static qemu_irq spapr_qirq_legacy(sPAPRMachineState *spapr, int irq) +{ + ICSState *ics =3D spapr->ics; + uint32_t srcno =3D irq - ics->offset; + + if (ics_valid_irq(ics, irq)) { + return ics->qirqs[srcno]; + } + + return NULL; +} + +static void spapr_irq_print_info_legacy(sPAPRMachineState *spapr, + Monitor *mon) +{ + CPUState *cs; + + CPU_FOREACH(cs) { + PowerPCCPU *cpu =3D POWERPC_CPU(cs); + + icp_pic_print_info(ICP(cpu->intc), mon); + } + + ics_pic_print_info(spapr->ics, mon); +} + +sPAPRIrq spapr_irq_xics =3D { + .nr_irqs =3D XICS_IRQS_SPAPR, + .init =3D spapr_irq_init_legacy, + .assign =3D spapr_irq_assign_legacy, + .alloc =3D spapr_irq_alloc_legacy, + .alloc_block =3D spapr_irq_alloc_block_legacy, + .free =3D spapr_irq_free_legacy, + .qirq =3D spapr_qirq_legacy, + .print_info =3D spapr_irq_print_info_legacy, +}; + +/* + * sPAPR IRQ frontend routines for devices + */ +int spapr_irq_assign(sPAPRMachineState *spapr, uint32_t range, uint32_t ir= q, + Error **errp) +{ + sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(spapr); + + return smc->irq->assign(spapr, range, irq, errp); +} + +int spapr_irq_alloc(sPAPRMachineState *spapr, uint32_t range, uint32_t ind= ex, + Error **errp) +{ + sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(spapr); + + return smc->irq->alloc(spapr, range, index, errp); +} + +int spapr_irq_alloc_block(sPAPRMachineState *spapr, uint32_t range, + uint32_t index, int num, bool align, Error **err= p) +{ + sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(spapr); + + return smc->irq->alloc_block(spapr, range, index, num, align, errp); +} + +void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num, + Error **errp) +{ + sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(spapr); + + smc->irq->free(spapr, irq, num, errp); +} + +qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq) +{ + sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(spapr); + + return smc->irq->qirq(spapr, irq); +} diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 4fd97ffe4c6e..cca4169fa10b 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -333,7 +333,12 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPR= MachineState *spapr, return; } =20 - spapr_irq_free(spapr, msi->first_irq, msi->num); + spapr_irq_free(spapr, msi->first_irq, msi->num, &err); + if (err) { + error_reportf_err(err, "Can't remove MSIs for device %x: ", + config_addr); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); + } if (msi_present(pdev)) { spapr_msi_setmsg(pdev, 0, false, 0, 0); } @@ -371,8 +376,8 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRM= achineState *spapr, } =20 /* Allocate MSIs */ - irq =3D spapr_irq_alloc_block(spapr, req_num, false, - ret_intr_type =3D=3D RTAS_TYPE_MSI, &err); + irq =3D spapr_irq_alloc_block(spapr, SPAPR_IRQ_PCI_MSI, phb->index, re= q_num, + ret_intr_type =3D=3D RTAS_TYPE_MSI, &err); if (err) { error_reportf_err(err, "Can't allocate MSIs for device %x: ", config_addr); @@ -382,7 +387,11 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPR= MachineState *spapr, =20 /* Release previous MSIs */ if (msi) { - spapr_irq_free(spapr, msi->first_irq, msi->num); + spapr_irq_free(spapr, msi->first_irq, msi->num, &err); + if (err) { + error_reportf_err(err, "Can't remove MSIs for device %x: ", + config_addr); + } g_hash_table_remove(phb->msi, &config_addr); } =20 @@ -1696,7 +1705,8 @@ static void spapr_phb_realize(DeviceState *dev, Error= **errp) QLIST_INSERT_HEAD(&spapr->phbs, sphb, list); =20 /* Initialize the LSI table */ - irq =3D spapr_irq_alloc_block(spapr, PCI_NUM_PINS, true, false, &local= _err); + irq =3D spapr_irq_alloc_block(spapr, SPAPR_IRQ_PCI_LSI, sphb->index, + PCI_NUM_PINS, false, &local_err); if (local_err) { error_propagate(errp, local_err); error_prepend(errp, "can't allocate LSIs: "); @@ -2112,6 +2122,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof_ranges)); _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg))); _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1)); + /* TODO: fix the total count of allocatable MSIs per PHB */ _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", XICS_IRQS_SPA= PR)); =20 /* Dynamic DMA window */ diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 28bb3b849b9b..d19b28142a13 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -433,6 +433,9 @@ static void spapr_vio_busdev_reset(DeviceState *qdev) } } =20 +/* TODO : poor VIO device indexing ... */ +static uint32_t vio_index; + static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) { sPAPRMachineState *spapr =3D SPAPR_MACHINE(qdev_get_machine()); @@ -472,7 +475,19 @@ static void spapr_vio_busdev_realize(DeviceState *qdev= , Error **errp) dev->qdev.id =3D id; } =20 - dev->irq =3D spapr_irq_alloc(spapr, dev->irq, false, &local_err); + /* + * The "irq" property has been deprecated. IRQ assignment is soon + * to be removed + */ + if (dev->irq) { + spapr_irq_assign(spapr, SPAPR_IRQ_VIO, dev->irq, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + } + + dev->irq =3D spapr_irq_alloc(spapr, SPAPR_IRQ_VIO, vio_index++, &loca= l_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 86d82a6ec3ac..4fe3b7804d43 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -4,7 +4,7 @@ obj-y +=3D ppc.o ppc_booke.o fdt.o obj-$(CONFIG_PSERIES) +=3D spapr.o spapr_caps.o spapr_vio.o spapr_events.o obj-$(CONFIG_PSERIES) +=3D spapr_hcall.o spapr_iommu.o spapr_rtas.o obj-$(CONFIG_PSERIES) +=3D spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o -obj-$(CONFIG_PSERIES) +=3D spapr_cpu_core.o spapr_ovec.o +obj-$(CONFIG_PSERIES) +=3D spapr_cpu_core.o spapr_ovec.o spapr_irq.o # IBM PowerNV obj-$(CONFIG_POWERNV) +=3D pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o pnv_psi.= o pnv_occ.o pnv_bmc.o ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 152838710238812.859207711354316; Thu, 7 Jun 2018 08:58:22 -0700 (PDT) Received: from localhost ([::1]:58794 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxIr-0008NR-JT for importer@patchew.org; Thu, 07 Jun 2018 11:58:21 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38606) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxBP-0001eP-4H for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxBK-0003Q4-CD for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:39 -0400 Received: from 5.mo177.mail-out.ovh.net ([46.105.39.154]:46743) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxBK-0003OW-1C for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:34 -0400 Received: from player169.ha.ovh.net (unknown [10.109.108.88]) by mo177.mail-out.ovh.net (Postfix) with ESMTP id 79C30B59EE for ; Thu, 7 Jun 2018 17:50:32 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 04D0A58009D; Thu, 7 Jun 2018 17:50:26 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:38 +0200 Message-Id: <20180607155003.1580-4-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6073104101608622931 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.39.154 Subject: [Qemu-devel] [PATCH v4 03/28] spapr: introduce a new IRQ backend using fixed IRQ number ranges 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The proposed layout of the IRQ number space is organized as follow : RANGES DEVICES 0x0000 - 0x0FFF Reserved for future use (IPI =3D 2) 0x1000 - 0x1000 1 EPOW 0x1001 - 0x1001 1 HOTPLUG 0x1002 - 0x10FF unused 0x1100 - 0x11FF 256 VIO devices (1 IRQ each) 0x1200 - 0x1283 32 PCI LSI devices (4 IRQs each) 0x1284 - 0x13FF unused 0x1400 - 0x17FF PCI MSI device 1 (1024 IRQs each) 0x1800 - 0x1BFF PCI MSI device 2 0x1c00 - 0x1FFF PCI MSI device 3 The MSI range is a bit more complex to handle as the IRQs are dynamically allocated by the guest OS. We use a bitmap allocator under the sPAPR IRQ backend for these. The XICS IRQ number space is increased to 4K, which gives three MSI ranges of 1K per PHB device. If more PHB devices are needed, the total number of IRQs in the backend should be increased. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/spapr.h | 2 + include/hw/ppc/spapr_irq.h | 12 +++ hw/ppc/spapr.c | 22 ++++ hw/ppc/spapr_irq.c | 253 +++++++++++++++++++++++++++++++++++++++++= +++- 4 files changed, 288 insertions(+), 1 deletion(-) diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index aba1892f2bd0..bd256fbc9158 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -164,6 +164,8 @@ struct sPAPRMachineState { /*< public >*/ char *kvm_type; =20 + int32_t nr_irqs; + unsigned long *irq_map; const char *icp_type; =20 bool cmd_line_caps[SPAPR_CAP_NUM]; diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index 67ec7ff162a6..dd9c4038d5b6 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -21,8 +21,16 @@ #define SPAPR_IRQ_PCI_LSI 0x1200 /* 4 IRQs per device */ #define SPAPR_IRQ_PCI_MSI 0x1400 /* 1K IRQs per device covered by * a bitmap allocator */ +typedef struct sPAPRPIrqRange { + const char *name; + uint32_t offset; + uint32_t width; + uint32_t max_index; +} sPAPRPIrqRange; + typedef struct sPAPRIrq { uint32_t nr_irqs; + const sPAPRPIrqRange *ranges; =20 void (*init)(sPAPRMachineState *spapr, Error **errp); int (*assign)(sPAPRMachineState *spapr, uint32_t range, uint32_t irq, @@ -36,8 +44,12 @@ typedef struct sPAPRIrq { void (*print_info)(sPAPRMachineState *spapr, Monitor *mon); } sPAPRIrq; =20 +extern sPAPRIrq spapr_irq_legacy; extern sPAPRIrq spapr_irq_xics; =20 +const sPAPRPIrqRange *spapr_irq_get_range(sPAPRMachineState *spapr, + uint32_t offset); + int spapr_irq_assign(sPAPRMachineState *spapr, uint32_t range, uint32_t ir= q, Error **errp); int spapr_irq_alloc(sPAPRMachineState *spapr, uint32_t range, uint32_t ind= ex, diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index fd37ca4803eb..c097a7093e62 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1850,6 +1850,24 @@ static const VMStateDescription vmstate_spapr_patb_e= ntry =3D { }, }; =20 +static bool spapr_irq_map_needed(void *opaque) +{ + sPAPRMachineState *spapr =3D opaque; + + return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->nr_irqs); +} + +static const VMStateDescription vmstate_spapr_irq_map =3D { + .name =3D "spapr_irq_map", + .version_id =3D 1, + .minimum_version_id =3D 1, + .needed =3D spapr_irq_map_needed, + .fields =3D (VMStateField[]) { + VMSTATE_BITMAP(irq_map, sPAPRMachineState, 0, nr_irqs), + VMSTATE_END_OF_LIST() + }, +}; + static const VMStateDescription vmstate_spapr =3D { .name =3D "spapr", .version_id =3D 3, @@ -1877,6 +1895,7 @@ static const VMStateDescription vmstate_spapr =3D { &vmstate_spapr_cap_cfpc, &vmstate_spapr_cap_sbbc, &vmstate_spapr_cap_ibs, + &vmstate_spapr_irq_map, NULL } }; @@ -3913,7 +3932,10 @@ static void spapr_machine_2_12_instance_options(Mach= ineState *machine) =20 static void spapr_machine_2_12_class_options(MachineClass *mc) { + sPAPRMachineClass *smc =3D SPAPR_MACHINE_CLASS(mc); + spapr_machine_3_0_class_options(mc); + smc->irq =3D &spapr_irq_legacy; SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_12); } =20 diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 1efccf590899..6bd3dd7e01d7 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -237,7 +237,7 @@ static void spapr_irq_print_info_legacy(sPAPRMachineSta= te *spapr, ics_pic_print_info(spapr->ics, mon); } =20 -sPAPRIrq spapr_irq_xics =3D { +sPAPRIrq spapr_irq_legacy =3D { .nr_irqs =3D XICS_IRQS_SPAPR, .init =3D spapr_irq_init_legacy, .assign =3D spapr_irq_assign_legacy, @@ -249,6 +249,257 @@ sPAPRIrq spapr_irq_xics =3D { }; =20 /* + * IRQ range helpers for new IRQ backends + */ +const sPAPRPIrqRange *spapr_irq_get_range(sPAPRMachineState *spapr, + uint32_t range) +{ + sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(spapr); + const sPAPRPIrqRange *irq_range =3D smc->irq->ranges; + + if (irq_range) { + /* + * The range identifier is also its offset in the IRQ number + * space. May be introduce a enum instead. + */ + while (irq_range->name && irq_range->offset !=3D range) { + irq_range++; + } + + if (!irq_range->name) { + return NULL; + } + } + + return irq_range; +} + +static int spapr_irq_range_base(sPAPRMachineState *spapr, uint32_t range, + uint32_t index, Error **errp) +{ + const sPAPRPIrqRange *irq_range =3D spapr_irq_get_range(spapr, range); + + if (!irq_range) { + error_setg(errp, "Invalid IRQ range %x", range); + return -1; + } + + if (index > irq_range->max_index) { + error_setg(errp, "Index %d too big for IRQ range %s", index, + irq_range->name); + return -1; + } + + return irq_range->offset + index * irq_range->width; +} + +static int spapr_irq_range_alloc(sPAPRMachineState *spapr, + uint32_t range, uint32_t index, Error **e= rrp) +{ + return spapr_irq_range_base(spapr, range, index, errp); +} + +static int spapr_irq_range_alloc_msi(sPAPRMachineState *spapr, uint32_t ra= nge, + uint32_t index, int num, bool align, + Error **errp) +{ + int msi_base; + int irq; + + msi_base =3D spapr_irq_range_base(spapr, SPAPR_IRQ_PCI_MSI, index, err= p); + if (msi_base =3D=3D -1) { + return -1; + } + + /* + * The 'align_mask' parameter of bitmap_find_next_zero_area() + * should be one less than a power of 2; 0 means no + * alignment. Adapt the 'align' value of the former allocator + * to fit the requirements of bitmap_find_next_zero_area() + */ + align -=3D 1; + + irq =3D bitmap_find_next_zero_area(spapr->irq_map, spapr->nr_irqs, + msi_base, num, align); + if (irq =3D=3D spapr->nr_irqs) { + error_setg(errp, "can't find a free MSI %d-IRQ block", num); + return -1; + } + + bitmap_set(spapr->irq_map, irq, num); + return irq; +} + +static void spapr_irq_range_free_msi(sPAPRMachineState *spapr, int irq, in= t num) +{ + bitmap_clear(spapr->irq_map, irq, num); +} + +/* + * New XICS IRQ backend + * + * using the IRQ ranges and device indexes + */ +static void spapr_irq_init_xics(sPAPRMachineState *spapr, Error **errp) +{ + MachineState *machine =3D MACHINE(spapr); + sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(machine); + + spapr_irq_init_legacy(spapr, errp); + + /* + * Initialize the MSI IRQ allocator. The full XICS IRQ number + * space is covered even though the bottow IRQ numbers below the + * XICS source number offset (4K) are unused and that only MSI IRQ + * numbers can be allocated. It does waste some bytes but it makes + * things easier. We will optimize later. + */ + spapr->nr_irqs =3D smc->irq->nr_irqs + spapr->ics->offset; + spapr->irq_map =3D bitmap_new(spapr->nr_irqs); +} + +/* + * The 'irq' assignment is only used by the sPAPR VIO devices and it + * has been deprecated in QEMU 3.0. This handler should be removed + * soon. + */ +static int spapr_irq_assign_xics(sPAPRMachineState *spapr, uint32_t range, + uint32_t irq, Error **errp) +{ + assert(range =3D=3D SPAPR_IRQ_VIO); + + error_setg(errp, "IRQ assignment is not available on the new " + " XICS IRQ backend"); + return -1; +} + +static int spapr_irq_alloc_xics(sPAPRMachineState *spapr, uint32_t range, + uint32_t index, Error **errp) +{ + ICSState *ics =3D spapr->ics; + bool lsi =3D (range =3D=3D SPAPR_IRQ_PCI_LSI); + int irq =3D spapr_irq_range_alloc(spapr, range, index, errp); + + if (irq < 0) { + return irq; + } + + /* Update the IRQState in the XICS source */ + ics_set_irq_type(ics, irq - ics->offset, lsi); + + return irq; +} + +static int spapr_irq_alloc_block_xics(sPAPRMachineState *spapr, uint32_t r= ange, + uint32_t index, int num, bool align, + Error **errp) +{ + ICSState *ics =3D spapr->ics; + bool lsi =3D (range =3D=3D SPAPR_IRQ_PCI_LSI); + int irq; + int i; + + if (range =3D=3D SPAPR_IRQ_PCI_MSI) { + irq =3D spapr_irq_range_alloc_msi(spapr, range, index, num, align,= errp); + } else { + /* TODO: check IRQ range width vs. required block size */ + irq =3D spapr_irq_range_alloc(spapr, range, index, errp); + } + + if (irq < 0) { + return irq; + } + + /* Update the IRQState in the XICS source */ + for (i =3D irq; i < irq + num; ++i) { + ics_set_irq_type(ics, i - ics->offset, lsi); + } + + return irq; +} + +static void spapr_irq_free_xics(sPAPRMachineState *spapr, int irq, int num, + Error **errp) +{ + ICSState *ics =3D spapr->ics; + int msi_base =3D spapr_irq_range_base(spapr, SPAPR_IRQ_PCI_MSI, 0, NUL= L); + int i; + + /* Any IRQ below MSI base should not be freed */ + if (irq < msi_base) { + error_setg(errp, "IRQs %x-%x can not be freed", irq, irq + num); + return; + } + + spapr_irq_range_free_msi(spapr, irq, num); + + /* Clear out the IRQState from the XICS source */ + for (i =3D irq; i < irq + num; ++i) { + if (ics_valid_irq(ics, i)) { + uint32_t srcno =3D i - ics->offset; + memset(&ics->irqs[srcno], 0, sizeof(ICSIRQState)); + } + } +} + +static qemu_irq spapr_qirq_xics(sPAPRMachineState *spapr, int irq) +{ + return spapr_qirq_legacy(spapr, irq); +} + +static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, + Monitor *mon) +{ + spapr_irq_print_info_legacy(spapr, mon); +} + +/* + * XICS IRQ number space + * + * RANGES DEVICES + * + * 0x0000 - 0x0FFF Reserved for future use (IPI =3D 2) + * + * 0x1000 - 0x1000 1 EPOW + * 0x1001 - 0x1001 1 HOTPLUG + * 0x1002 - 0x10FF unused + * 0x1100 - 0x11FF 256 VIO devices (1 IRQ each) + * 0x1200 - 0x1283 32 PCI LSI devices (4 IRQs each) + * 0x1284 - 0x13FF unused + * 0x1400 - 0x17FF PCI MSI device 1 (1024 IRQs each) + * 0x1800 - 0x1BFF PCI MSI device 2 + * 0x1c00 - 0x1FFF PCI MSI device 3 + * + * 0x2000 .... not allocated. Need to increase NR_IRQS + */ +static const sPAPRPIrqRange spapr_irq_ranges_xics[] =3D { + /* "IPI" Not used */ + { "EPOW", SPAPR_IRQ_EPOW, 1, 0 }, + { "HOTPLUG", SPAPR_IRQ_HOTPLUG, 1, 0 }, + { "VIO", SPAPR_IRQ_VIO, 1, 0xFF }, + { "PCI LSI", SPAPR_IRQ_PCI_LSI, PCI_NUM_PINS, 0x1F }, + { "PCI MSI", SPAPR_IRQ_PCI_MSI, 0x400, 0x1F }, + { NULL, 0, 0, 0 }, +}; + +/* + * Increase the XICS IRQ number space to 4K. It gives us 3 possible + * MSI ranges for the PHBs. + */ + +sPAPRIrq spapr_irq_xics =3D { + .nr_irqs =3D 0x1000, + .init =3D spapr_irq_init_xics, + .ranges =3D spapr_irq_ranges_xics, + .assign =3D spapr_irq_assign_xics, + .alloc =3D spapr_irq_alloc_xics, + .alloc_block =3D spapr_irq_alloc_block_xics, + .free =3D spapr_irq_free_xics, + .qirq =3D spapr_qirq_xics, + .print_info =3D spapr_irq_print_info_xics, +}; + +/* * sPAPR IRQ frontend routines for devices */ int spapr_irq_assign(sPAPRMachineState *spapr, uint32_t range, uint32_t ir= q, --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 15283873075279.105477173180589; Thu, 7 Jun 2018 09:01:47 -0700 (PDT) Received: from localhost ([::1]:58827 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxM7-0002wX-EA for importer@patchew.org; Thu, 07 Jun 2018 12:01:43 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38656) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxBV-0001kP-5H for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxBQ-0003W5-AL for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:45 -0400 Received: from 7.mo69.mail-out.ovh.net ([46.105.50.32]:45061) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxBP-0003Ux-Pt for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:40 -0400 Received: from player169.ha.ovh.net (unknown [10.109.120.110]) by mo69.mail-out.ovh.net (Postfix) with ESMTP id 1BA79154BF for ; Thu, 7 Jun 2018 17:50:37 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 816175800A7; Thu, 7 Jun 2018 17:50:32 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:39 +0200 Message-Id: <20180607155003.1580-5-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6074511475972082515 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.50.32 Subject: [Qemu-devel] [PATCH v4 04/28] ppc/xive: introduce a XIVE interrupt source model 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The first sub-engine of the overall XIVE architecture is the Interrupt Virtualization Source Engine (IVSE). An IVSE can be integrated into another logic, like in a PCI PHB or in the main interrupt controller to manage IPIs. Each IVSE instance is associated with an Event State Buffer (ESB) that contains a two bit state entry for each possible event source. When an event is signaled to the IVSE, by MMIO or some other means, the associated interrupt state bits are fetched from the ESB and modified. Depending on the resulting ESB state, the event is forwarded to the IVRE sub-engine of the controller doing the routing. Each supported ESB entry is associated with either a single or a even/odd pair of pages which provides commands to manage the source: to EOI, to turn off the source for instance. On a sPAPR machine, the OS will obtain the page address of the ESB entry associated with a source and its characteristic using the H_INT_GET_SOURCE_INFO hcall. On PowerNV, a similar OPAL call is used. The xive_source_notify() routine is in charge forwarding the source event notification to the routing engine. It will be filled later on. Signed-off-by: C=C3=A9dric Le Goater --- default-configs/ppc64-softmmu.mak | 1 + include/hw/ppc/xive.h | 130 +++++++++++++ hw/intc/xive.c | 379 ++++++++++++++++++++++++++++++++++= ++++ hw/intc/Makefile.objs | 1 + 4 files changed, 511 insertions(+) create mode 100644 include/hw/ppc/xive.h create mode 100644 hw/intc/xive.c diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-soft= mmu.mak index b94af6c7c62a..c6d13e757977 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -16,4 +16,5 @@ CONFIG_VIRTIO_VGA=3Dy CONFIG_XICS=3D$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=3D$(CONFIG_PSERIES) CONFIG_XICS_KVM=3D$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) +CONFIG_XIVE=3D$(CONFIG_PSERIES) CONFIG_MEM_HOTPLUG=3Dy diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h new file mode 100644 index 000000000000..5fec4b08705d --- /dev/null +++ b/include/hw/ppc/xive.h @@ -0,0 +1,130 @@ +/* + * QEMU PowerPC XIVE interrupt controller model + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef PPC_XIVE_H +#define PPC_XIVE_H + +#include "hw/sysbus.h" + +/* + * XIVE Interrupt Source + */ + +#define TYPE_XIVE_SOURCE "xive-source" +#define XIVE_SOURCE(obj) OBJECT_CHECK(XiveSource, (obj), TYPE_XIVE_SOURCE) + +/* + * XIVE Interrupt Source characteristics, which define how the ESB are + * controlled. + */ +#define XIVE_SRC_H_INT_ESB 0x1 /* ESB managed with hcall H_INT_ESB */ +#define XIVE_SRC_STORE_EOI 0x2 /* Store EOI supported */ + +typedef struct XiveSource { + SysBusDevice parent; + + /* IRQs */ + uint32_t nr_irqs; + qemu_irq *qirqs; + + /* PQ bits */ + uint8_t *status; + + /* ESB memory region */ + uint64_t esb_flags; + uint32_t esb_shift; + MemoryRegion esb_mmio; +} XiveSource; + +/* + * ESB MMIO setting. Can be one page, for both source triggering and + * source management, or two different pages. See below for magic + * values. + */ +#define XIVE_ESB_4K 12 /* PSI HB only */ +#define XIVE_ESB_4K_2PAGE 13 +#define XIVE_ESB_64K 16 +#define XIVE_ESB_64K_2PAGE 17 + +static inline bool xive_source_esb_has_2page(XiveSource *xsrc) +{ + return xsrc->esb_shift =3D=3D XIVE_ESB_64K_2PAGE || + xsrc->esb_shift =3D=3D XIVE_ESB_4K_2PAGE; +} + +/* The trigger page is always the first/even page */ +static inline hwaddr xive_source_esb_page(XiveSource *xsrc, uint32_t srcno) +{ + assert(srcno < xsrc->nr_irqs); + return (1ull << xsrc->esb_shift) * srcno; +} + +/* In a two pages ESB MMIO setting, the odd page is for management */ +static inline hwaddr xive_source_esb_mgmt(XiveSource *xsrc, int srcno) +{ + hwaddr addr =3D xive_source_esb_page(xsrc, srcno); + + if (xive_source_esb_has_2page(xsrc)) { + addr +=3D (1 << (xsrc->esb_shift - 1)); + } + + return addr; +} + +/* + * Each interrupt source has a 2-bit state machine which can be + * controlled by MMIO. P indicates that an interrupt is pending (has + * been sent to a queue and is waiting for an EOI). Q indicates that + * the interrupt has been triggered while pending. + * + * This acts as a coalescing mechanism in order to guarantee that a + * given interrupt only occurs at most once in a queue. + * + * When doing an EOI, the Q bit will indicate if the interrupt + * needs to be re-triggered. + */ +#define XIVE_ESB_VAL_P 0x2 +#define XIVE_ESB_VAL_Q 0x1 + +#define XIVE_ESB_RESET 0x0 +#define XIVE_ESB_PENDING XIVE_ESB_VAL_P +#define XIVE_ESB_QUEUED (XIVE_ESB_VAL_P | XIVE_ESB_VAL_Q) +#define XIVE_ESB_OFF XIVE_ESB_VAL_Q + +/* + * "magic" Event State Buffer (ESB) MMIO offsets. + * + * The following offsets into the ESB MMIO allow to read or manipulate + * the PQ bits. They must be used with an 8-byte load instruction. + * They all return the previous state of the interrupt (atomically). + * + * Additionally, some ESB pages support doing an EOI via a store and + * some ESBs support doing a trigger via a separate trigger page. + */ +#define XIVE_ESB_STORE_EOI 0x400 /* Store */ +#define XIVE_ESB_LOAD_EOI 0x000 /* Load */ +#define XIVE_ESB_GET 0x800 /* Load */ +#define XIVE_ESB_SET_PQ_00 0xc00 /* Load */ +#define XIVE_ESB_SET_PQ_01 0xd00 /* Load */ +#define XIVE_ESB_SET_PQ_10 0xe00 /* Load */ +#define XIVE_ESB_SET_PQ_11 0xf00 /* Load */ + +uint8_t xive_source_esb_get(XiveSource *xsrc, uint32_t srcno); +uint8_t xive_source_esb_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq); + +void xive_source_pic_print_info(XiveSource *xsrc, uint32_t offset, + Monitor *mon); + +static inline qemu_irq xive_source_qirq(XiveSource *xsrc, uint32_t srcno) +{ + assert(srcno < xsrc->nr_irqs); + return xsrc->qirqs[srcno]; +} + +#endif /* PPC_XIVE_H */ diff --git a/hw/intc/xive.c b/hw/intc/xive.c new file mode 100644 index 000000000000..4d1cb2497237 --- /dev/null +++ b/hw/intc/xive.c @@ -0,0 +1,379 @@ +/* + * QEMU PowerPC XIVE interrupt controller model + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "target/ppc/cpu.h" +#include "sysemu/cpus.h" +#include "sysemu/dma.h" +#include "monitor/monitor.h" +#include "hw/ppc/xive.h" + +/* + * XIVE ESB helpers + */ + +static uint8_t xive_esb_set(uint8_t *pq, uint8_t value) +{ + uint8_t old_pq =3D *pq & 0x3; + + *pq &=3D ~0x3; + *pq |=3D value & 0x3; + + return old_pq; +} + +static bool xive_esb_trigger(uint8_t *pq) +{ + uint8_t old_pq =3D *pq & 0x3; + + switch (old_pq) { + case XIVE_ESB_RESET: + xive_esb_set(pq, XIVE_ESB_PENDING); + return true; + case XIVE_ESB_PENDING: + case XIVE_ESB_QUEUED: + xive_esb_set(pq, XIVE_ESB_QUEUED); + return false; + case XIVE_ESB_OFF: + xive_esb_set(pq, XIVE_ESB_OFF); + return false; + default: + g_assert_not_reached(); + } +} + +static bool xive_esb_eoi(uint8_t *pq) +{ + uint8_t old_pq =3D *pq & 0x3; + + switch (old_pq) { + case XIVE_ESB_RESET: + case XIVE_ESB_PENDING: + xive_esb_set(pq, XIVE_ESB_RESET); + return false; + case XIVE_ESB_QUEUED: + xive_esb_set(pq, XIVE_ESB_PENDING); + return true; + case XIVE_ESB_OFF: + xive_esb_set(pq, XIVE_ESB_OFF); + return false; + default: + g_assert_not_reached(); + } +} + +/* + * XIVE Interrupt Source (or IVSE) + */ + +uint8_t xive_source_esb_get(XiveSource *xsrc, uint32_t srcno) +{ + assert(srcno < xsrc->nr_irqs); + + return xsrc->status[srcno] & 0x3; +} + +uint8_t xive_source_esb_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq) +{ + assert(srcno < xsrc->nr_irqs); + + return xive_esb_set(&xsrc->status[srcno], pq); +} + +/* + * Returns whether the event notification should be forwarded. + */ +static bool xive_source_esb_trigger(XiveSource *xsrc, uint32_t srcno) +{ + assert(srcno < xsrc->nr_irqs); + + return xive_esb_trigger(&xsrc->status[srcno]); +} + +/* + * Returns whether the event notification should be forwarded. + */ +static bool xive_source_esb_eoi(XiveSource *xsrc, uint32_t srcno) +{ + assert(srcno < xsrc->nr_irqs); + + return xive_esb_eoi(&xsrc->status[srcno]); +} + +/* + * Forward the source event notification to the Router + */ +static void xive_source_notify(XiveSource *xsrc, int srcno) +{ + +} + +/* In a two pages ESB MMIO setting, even page is the trigger page, odd + * page is for management */ +static inline bool addr_is_even(hwaddr addr, uint32_t shift) +{ + return !((addr >> shift) & 1); +} + +static inline bool xive_source_is_trigger_page(XiveSource *xsrc, hwaddr ad= dr) +{ + return xive_source_esb_has_2page(xsrc) && + addr_is_even(addr, xsrc->esb_shift - 1); +} + +/* + * ESB MMIO loads + * Trigger page Management/EOI page + * 2 pages setting even odd + * + * 0x000 .. 0x3FF -1 EOI and return 0|1 + * 0x400 .. 0x7FF -1 EOI and return 0|1 + * 0x800 .. 0xBFF -1 return PQ + * 0xC00 .. 0xCFF -1 return PQ and atomically PQ=3D0 + * 0xD00 .. 0xDFF -1 return PQ and atomically PQ=3D0 + * 0xE00 .. 0xDFF -1 return PQ and atomically PQ=3D1 + * 0xF00 .. 0xDFF -1 return PQ and atomically PQ=3D1 + */ +static uint64_t xive_source_esb_read(void *opaque, hwaddr addr, unsigned s= ize) +{ + XiveSource *xsrc =3D XIVE_SOURCE(opaque); + uint32_t offset =3D addr & 0xFFF; + uint32_t srcno =3D addr >> xsrc->esb_shift; + uint64_t ret =3D -1; + + /* In a two pages ESB MMIO setting, trigger page should not be read */ + if (xive_source_is_trigger_page(xsrc, addr)) { + qemu_log_mask(LOG_GUEST_ERROR, + "XIVE: invalid load on IRQ %d trigger page at " + "0x%"HWADDR_PRIx"\n", srcno, addr); + return -1; + } + + switch (offset) { + case XIVE_ESB_LOAD_EOI ... XIVE_ESB_LOAD_EOI + 0x7FF: + ret =3D xive_source_esb_eoi(xsrc, srcno); + + /* Forward the source event notification for routing */ + if (ret) { + xive_source_notify(xsrc, srcno); + } + break; + + case XIVE_ESB_GET ... XIVE_ESB_GET + 0x3FF: + ret =3D xive_source_esb_get(xsrc, srcno); + break; + + case XIVE_ESB_SET_PQ_00 ... XIVE_ESB_SET_PQ_00 + 0x0FF: + case XIVE_ESB_SET_PQ_01 ... XIVE_ESB_SET_PQ_01 + 0x0FF: + case XIVE_ESB_SET_PQ_10 ... XIVE_ESB_SET_PQ_10 + 0x0FF: + case XIVE_ESB_SET_PQ_11 ... XIVE_ESB_SET_PQ_11 + 0x0FF: + ret =3D xive_source_esb_set(xsrc, srcno, (offset >> 8) & 0x3); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid ESB load addr %x\n", + offset); + } + + return ret; +} + +/* + * ESB MMIO stores + * Trigger page Management/EOI page + * 2 pages setting even odd + * + * 0x000 .. 0x3FF Trigger Trigger + * 0x400 .. 0x7FF Trigger EOI + * 0x800 .. 0xBFF Trigger undefined + * 0xC00 .. 0xCFF Trigger PQ=3D00 + * 0xD00 .. 0xDFF Trigger PQ=3D01 + * 0xE00 .. 0xDFF Trigger PQ=3D10 + * 0xF00 .. 0xDFF Trigger PQ=3D11 + */ +static void xive_source_esb_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + XiveSource *xsrc =3D XIVE_SOURCE(opaque); + uint32_t offset =3D addr & 0xFFF; + uint32_t srcno =3D addr >> xsrc->esb_shift; + bool notify =3D false; + + /* In a two pages ESB MMIO setting, trigger page only triggers */ + if (xive_source_is_trigger_page(xsrc, addr)) { + notify =3D xive_source_esb_trigger(xsrc, srcno); + goto out; + } + + switch (offset) { + case 0 ... 0x3FF: + notify =3D xive_source_esb_trigger(xsrc, srcno); + break; + + case XIVE_ESB_STORE_EOI ... XIVE_ESB_STORE_EOI + 0x3FF: + if (!(xsrc->esb_flags & XIVE_SRC_STORE_EOI)) { + qemu_log_mask(LOG_GUEST_ERROR, + "XIVE: invalid Store EOI for IRQ %d\n", srcno); + return; + } + + notify =3D xive_source_esb_eoi(xsrc, srcno); + break; + + case XIVE_ESB_SET_PQ_00 ... XIVE_ESB_SET_PQ_00 + 0x0FF: + case XIVE_ESB_SET_PQ_01 ... XIVE_ESB_SET_PQ_01 + 0x0FF: + case XIVE_ESB_SET_PQ_10 ... XIVE_ESB_SET_PQ_10 + 0x0FF: + case XIVE_ESB_SET_PQ_11 ... XIVE_ESB_SET_PQ_11 + 0x0FF: + xive_source_esb_set(xsrc, srcno, (offset >> 8) & 0x3); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid ESB write addr %x\n", + offset); + return; + } + +out: + /* Forward the source event notification for routing */ + if (notify) { + xive_source_notify(xsrc, srcno); + } +} + +static const MemoryRegionOps xive_source_esb_ops =3D { + .read =3D xive_source_esb_read, + .write =3D xive_source_esb_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + }, + .impl =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + }, +}; + +static void xive_source_set_irq(void *opaque, int srcno, int val) +{ + XiveSource *xsrc =3D XIVE_SOURCE(opaque); + bool notify =3D false; + + if (val) { + notify =3D xive_source_esb_trigger(xsrc, srcno); + } + + /* Forward the source event notification for routing */ + if (notify) { + xive_source_notify(xsrc, srcno); + } +} + +void xive_source_pic_print_info(XiveSource *xsrc, uint32_t offset, Monitor= *mon) +{ + int i; + + monitor_printf(mon, "XIVE Source %8x ..%8x\n", + offset, offset + xsrc->nr_irqs - 1); + for (i =3D 0; i < xsrc->nr_irqs; i++) { + uint8_t pq =3D xive_source_esb_get(xsrc, i); + + if (pq =3D=3D XIVE_ESB_OFF) { + continue; + } + + monitor_printf(mon, " %8x %c%c\n", i + offset, + pq & XIVE_ESB_VAL_P ? 'P' : '-', + pq & XIVE_ESB_VAL_Q ? 'Q' : '-'); + } +} + +static void xive_source_reset(DeviceState *dev) +{ + XiveSource *xsrc =3D XIVE_SOURCE(dev); + + /* PQs are initialized to 0b01 which corresponds to "ints off" */ + memset(xsrc->status, 0x1, xsrc->nr_irqs); +} + +static void xive_source_realize(DeviceState *dev, Error **errp) +{ + XiveSource *xsrc =3D XIVE_SOURCE(dev); + + if (!xsrc->nr_irqs) { + error_setg(errp, "Number of interrupt needs to be greater than 0"); + return; + } + + if (xsrc->esb_shift !=3D XIVE_ESB_4K && + xsrc->esb_shift !=3D XIVE_ESB_4K_2PAGE && + xsrc->esb_shift !=3D XIVE_ESB_64K && + xsrc->esb_shift !=3D XIVE_ESB_64K_2PAGE) { + error_setg(errp, "Invalid ESB shift setting"); + return; + } + + xsrc->qirqs =3D qemu_allocate_irqs(xive_source_set_irq, xsrc, + xsrc->nr_irqs); + + xsrc->status =3D g_malloc0(xsrc->nr_irqs); + + memory_region_init_io(&xsrc->esb_mmio, OBJECT(xsrc), + &xive_source_esb_ops, xsrc, "xive.esb", + (1ull << xsrc->esb_shift) * xsrc->nr_irqs); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &xsrc->esb_mmio); +} + +static const VMStateDescription vmstate_xive_source =3D { + .name =3D TYPE_XIVE_SOURCE, + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_UINT32_EQUAL(nr_irqs, XiveSource, NULL), + VMSTATE_VBUFFER_UINT32(status, XiveSource, 1, NULL, nr_irqs), + VMSTATE_END_OF_LIST() + }, +}; + +/* + * The default XIVE interrupt source setting for the ESB MMIOs is two + * 64k pages without Store EOI, to be in sync with KVM. + */ +static Property xive_source_properties[] =3D { + DEFINE_PROP_UINT64("flags", XiveSource, esb_flags, 0), + DEFINE_PROP_UINT32("nr-irqs", XiveSource, nr_irqs, 0), + DEFINE_PROP_UINT32("shift", XiveSource, esb_shift, XIVE_ESB_64K_2PAGE), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xive_source_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->desc =3D "XIVE Interrupt Source"; + dc->props =3D xive_source_properties; + dc->realize =3D xive_source_realize; + dc->reset =3D xive_source_reset; + dc->vmsd =3D &vmstate_xive_source; +} + +static const TypeInfo xive_source_info =3D { + .name =3D TYPE_XIVE_SOURCE, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(XiveSource), + .class_init =3D xive_source_class_init, +}; + +static void xive_register_types(void) +{ + type_register_static(&xive_source_info); +} + +type_init(xive_register_types) diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 0e9963f5eecc..72a46ed91c31 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -37,6 +37,7 @@ obj-$(CONFIG_SH4) +=3D sh_intc.o obj-$(CONFIG_XICS) +=3D xics.o obj-$(CONFIG_XICS_SPAPR) +=3D xics_spapr.o obj-$(CONFIG_XICS_KVM) +=3D xics_kvm.o +obj-$(CONFIG_XIVE) +=3D xive.o obj-$(CONFIG_POWERNV) +=3D xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) +=3D allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) +=3D s390_flic.o --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528387497095844.8311646465767; Thu, 7 Jun 2018 09:04:57 -0700 (PDT) Received: from localhost ([::1]:58846 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxPE-0005M7-6Z for importer@patchew.org; Thu, 07 Jun 2018 12:04:56 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38696) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxBa-0001oV-FE for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxBV-0003Z4-IP for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:50 -0400 Received: from 8.mo69.mail-out.ovh.net ([46.105.56.233]:42199) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxBV-0003Xy-8f for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:45 -0400 Received: from player169.ha.ovh.net (unknown [10.109.105.34]) by mo69.mail-out.ovh.net (Postfix) with ESMTP id 6C84615923 for ; Thu, 7 Jun 2018 17:50:43 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 0B7A55800A3; Thu, 7 Jun 2018 17:50:37 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:40 +0200 Message-Id: <20180607155003.1580-6-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6076200323369503571 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.56.233 Subject: [Qemu-devel] [PATCH v4 05/28] ppc/xive: add support for the LSI interrupt sources 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The 'sent' status of the LSI interrupt source is modeled with the 'P' bit of the ESB and the assertion status of the source is maintained in an array under the main sPAPRXive object. The type of the source is stored in the same array for practical reasons. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/xive.h | 20 ++++++++++++++- hw/intc/xive.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++-= ---- 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index 5fec4b08705d..e118acd59f1e 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -32,8 +32,10 @@ typedef struct XiveSource { /* IRQs */ uint32_t nr_irqs; qemu_irq *qirqs; + unsigned long *lsi_map; + int32_t lsi_map_size; /* for VMSTATE_BITMAP */ =20 - /* PQ bits */ + /* PQ bits and LSI assertion bit */ uint8_t *status; =20 /* ESB memory region */ @@ -89,6 +91,7 @@ static inline hwaddr xive_source_esb_mgmt(XiveSource *xsr= c, int srcno) * When doing an EOI, the Q bit will indicate if the interrupt * needs to be re-triggered. */ +#define XIVE_STATUS_ASSERTED 0x4 /* Extra bit for LSI */ #define XIVE_ESB_VAL_P 0x2 #define XIVE_ESB_VAL_Q 0x1 =20 @@ -127,4 +130,19 @@ static inline qemu_irq xive_source_qirq(XiveSource *xs= rc, uint32_t srcno) return xsrc->qirqs[srcno]; } =20 +static inline bool xive_source_irq_is_lsi(XiveSource *xsrc, uint32_t srcno) +{ + assert(srcno < xsrc->nr_irqs); + return test_bit(srcno, xsrc->lsi_map); +} + +static inline void xive_source_irq_set(XiveSource *xsrc, uint32_t srcno, + bool lsi) +{ + assert(srcno < xsrc->nr_irqs); + if (lsi) { + bitmap_set(xsrc->lsi_map, srcno, 1); + } +} + #endif /* PPC_XIVE_H */ diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 4d1cb2497237..3ad8c151b9dc 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -91,11 +91,37 @@ uint8_t xive_source_esb_set(XiveSource *xsrc, uint32_t = srcno, uint8_t pq) /* * Returns whether the event notification should be forwarded. */ +static bool xive_source_lsi_trigger(XiveSource *xsrc, uint32_t srcno) +{ + uint8_t old_pq =3D xive_source_esb_get(xsrc, srcno); + + switch (old_pq) { + case XIVE_ESB_RESET: + xive_source_esb_set(xsrc, srcno, XIVE_ESB_PENDING); + return true; + default: + return false; + } +} + +/* + * Returns whether the event notification should be forwarded. + */ static bool xive_source_esb_trigger(XiveSource *xsrc, uint32_t srcno) { + bool ret; + assert(srcno < xsrc->nr_irqs); =20 - return xive_esb_trigger(&xsrc->status[srcno]); + ret =3D xive_esb_trigger(&xsrc->status[srcno]); + + if (xive_source_irq_is_lsi(xsrc, srcno) && + xive_source_esb_get(xsrc, srcno) =3D=3D XIVE_ESB_QUEUED) { + qemu_log_mask(LOG_GUEST_ERROR, + "XIVE: queued an event on LSI IRQ %d\n", srcno); + } + + return ret; } =20 /* @@ -103,9 +129,22 @@ static bool xive_source_esb_trigger(XiveSource *xsrc, = uint32_t srcno) */ static bool xive_source_esb_eoi(XiveSource *xsrc, uint32_t srcno) { + bool ret; + assert(srcno < xsrc->nr_irqs); =20 - return xive_esb_eoi(&xsrc->status[srcno]); + ret =3D xive_esb_eoi(&xsrc->status[srcno]); + + /* LSI sources do not set the Q bit but they can still be + * asserted, in which case we should forward a new event + * notification + */ + if (xive_source_irq_is_lsi(xsrc, srcno) && + xsrc->status[srcno] & XIVE_STATUS_ASSERTED) { + ret =3D xive_source_lsi_trigger(xsrc, srcno); + } + + return ret; } =20 /* @@ -266,8 +305,17 @@ static void xive_source_set_irq(void *opaque, int srcn= o, int val) XiveSource *xsrc =3D XIVE_SOURCE(opaque); bool notify =3D false; =20 - if (val) { - notify =3D xive_source_esb_trigger(xsrc, srcno); + if (xive_source_irq_is_lsi(xsrc, srcno)) { + if (val) { + xsrc->status[srcno] |=3D XIVE_STATUS_ASSERTED; + notify =3D xive_source_lsi_trigger(xsrc, srcno); + } else { + xsrc->status[srcno] &=3D ~XIVE_STATUS_ASSERTED; + } + } else { + if (val) { + notify =3D xive_source_esb_trigger(xsrc, srcno); + } } =20 /* Forward the source event notification for routing */ @@ -289,9 +337,11 @@ void xive_source_pic_print_info(XiveSource *xsrc, uint= 32_t offset, Monitor *mon) continue; } =20 - monitor_printf(mon, " %8x %c%c\n", i + offset, + monitor_printf(mon, " %8x %s %c%c%c\n", i + offset, + xive_source_irq_is_lsi(xsrc, i) ? "LSI" : "MSI", pq & XIVE_ESB_VAL_P ? 'P' : '-', - pq & XIVE_ESB_VAL_Q ? 'Q' : '-'); + pq & XIVE_ESB_VAL_Q ? 'Q' : '-', + xsrc->status[i] & XIVE_STATUS_ASSERTED ? 'A' : ' '); } } =20 @@ -299,6 +349,8 @@ static void xive_source_reset(DeviceState *dev) { XiveSource *xsrc =3D XIVE_SOURCE(dev); =20 + /* Do not clear the LSI bitmap */ + /* PQs are initialized to 0b01 which corresponds to "ints off" */ memset(xsrc->status, 0x1, xsrc->nr_irqs); } @@ -325,6 +377,9 @@ static void xive_source_realize(DeviceState *dev, Error= **errp) =20 xsrc->status =3D g_malloc0(xsrc->nr_irqs); =20 + xsrc->lsi_map =3D bitmap_new(xsrc->nr_irqs); + xsrc->lsi_map_size =3D xsrc->nr_irqs; + memory_region_init_io(&xsrc->esb_mmio, OBJECT(xsrc), &xive_source_esb_ops, xsrc, "xive.esb", (1ull << xsrc->esb_shift) * xsrc->nr_irqs); @@ -338,6 +393,7 @@ static const VMStateDescription vmstate_xive_source =3D= { .fields =3D (VMStateField[]) { VMSTATE_UINT32_EQUAL(nr_irqs, XiveSource, NULL), VMSTATE_VBUFFER_UINT32(status, XiveSource, 1, NULL, nr_irqs), + VMSTATE_BITMAP(lsi_map, XiveSource, 1, lsi_map_size), VMSTATE_END_OF_LIST() }, }; --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528386822013595.0626115422426; Thu, 7 Jun 2018 08:53:42 -0700 (PDT) Received: from localhost ([::1]:58764 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxEL-0003jS-7D for importer@patchew.org; Thu, 07 Jun 2018 11:53:41 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38724) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxBf-0001ro-KD for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxBa-0003cE-Uk for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:55 -0400 Received: from 8.mo5.mail-out.ovh.net ([178.32.116.78]:34830) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxBa-0003bJ-Ny for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:50 -0400 Received: from player169.ha.ovh.net (unknown [10.109.122.79]) by mo5.mail-out.ovh.net (Postfix) with ESMTP id F0CB11BE4C3 for ; Thu, 7 Jun 2018 17:50:48 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 7A8B75800AF; Thu, 7 Jun 2018 17:50:43 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:41 +0200 Message-Id: <20180607155003.1580-7-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6077607701403765587 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 178.32.116.78 Subject: [Qemu-devel] [PATCH v4 06/28] ppc/xive: introduce the XiveFabric interface 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The XiveFabric offers a simple interface, between the XiveSource object and the main interrupt controller of the machine. It will forward event notifications to the XIVE Interrupt Virtualization Routing Engine (IVRE). Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/xive.h | 23 +++++++++++++++++++++++ hw/intc/xive.c | 25 +++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index e118acd59f1e..be93fae6317b 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -13,6 +13,27 @@ #include "hw/sysbus.h" =20 /* + * XIVE Fabric (Interface between Source and Router) + */ + +typedef struct XiveFabric { + Object parent; +} XiveFabric; + +#define TYPE_XIVE_FABRIC "xive-fabric" +#define XIVE_FABRIC(obj) \ + OBJECT_CHECK(XiveFabric, (obj), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_CLASS(klass) \ + OBJECT_CLASS_CHECK(XiveFabricClass, (klass), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_GET_CLASS(obj) \ + OBJECT_GET_CLASS(XiveFabricClass, (obj), TYPE_XIVE_FABRIC) + +typedef struct XiveFabricClass { + InterfaceClass parent; + void (*notify)(XiveFabric *xf, uint32_t lisn); +} XiveFabricClass; + +/* * XIVE Interrupt Source */ =20 @@ -42,6 +63,8 @@ typedef struct XiveSource { uint64_t esb_flags; uint32_t esb_shift; MemoryRegion esb_mmio; + + XiveFabric *xive; } XiveSource; =20 /* diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 3ad8c151b9dc..3f6fcb358f83 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -152,7 +152,11 @@ static bool xive_source_esb_eoi(XiveSource *xsrc, uint= 32_t srcno) */ static void xive_source_notify(XiveSource *xsrc, int srcno) { + XiveFabricClass *xfc =3D XIVE_FABRIC_GET_CLASS(xsrc->xive); =20 + if (xfc->notify) { + xfc->notify(xsrc->xive, srcno); + } } =20 /* In a two pages ESB MMIO setting, even page is the trigger page, odd @@ -358,6 +362,17 @@ static void xive_source_reset(DeviceState *dev) static void xive_source_realize(DeviceState *dev, Error **errp) { XiveSource *xsrc =3D XIVE_SOURCE(dev); + Object *obj; + Error *local_err =3D NULL; + + obj =3D object_property_get_link(OBJECT(dev), "xive", &local_err); + if (!obj) { + error_propagate(errp, local_err); + error_prepend(errp, "required link 'xive' not found: "); + return; + } + + xsrc->xive =3D XIVE_FABRIC(obj); =20 if (!xsrc->nr_irqs) { error_setg(errp, "Number of interrupt needs to be greater than 0"); @@ -427,9 +442,19 @@ static const TypeInfo xive_source_info =3D { .class_init =3D xive_source_class_init, }; =20 +/* + * XIVE Fabric + */ +static const TypeInfo xive_fabric_info =3D { + .name =3D TYPE_XIVE_FABRIC, + .parent =3D TYPE_INTERFACE, + .class_size =3D sizeof(XiveFabricClass), +}; + static void xive_register_types(void) { type_register_static(&xive_source_info); + type_register_static(&xive_fabric_info); } =20 type_init(xive_register_types) --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528386996053326.80766000158224; Thu, 7 Jun 2018 08:56:36 -0700 (PDT) Received: from localhost ([::1]:58784 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxH9-0006pj-3a for importer@patchew.org; Thu, 07 Jun 2018 11:56:35 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38763) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxBl-0001wh-A0 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxBg-0003fD-IB for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:01 -0400 Received: from 3.mo3.mail-out.ovh.net ([46.105.44.175]:48820) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxBg-0003e5-5q for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:50:56 -0400 Received: from player169.ha.ovh.net (unknown [10.109.120.121]) by mo3.mail-out.ovh.net (Postfix) with ESMTP id 832901BC30A for ; Thu, 7 Jun 2018 17:50:54 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 0719A580097; Thu, 7 Jun 2018 17:50:48 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:42 +0200 Message-Id: <20180607155003.1580-8-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6079296550560697171 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.44.175 Subject: [Qemu-devel] [PATCH v4 07/28] ppc/xive: introduce the XiveRouter model 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The XiveRouter models the second sub-engine of the overall XIVE architecture : the Interrupt Virtualization Routing Engine (IVRE). The IVRE handles event notifications of the IVSE through MMIO stores and performs the interrupt routing process. For this purpose, it uses a set of table stored in system memory, the first of which being the Interrupt Virtualization entries (IVE) table. The IVT associates an interrupt source number with an Event Queue Descriptor which will be used in a second phase of the routing process to identify a notification target. The XiveRouter is an abstract class which needs to be inherited from to define a storage for the IVT, and other upcoming tables. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/xive.h | 32 ++++++++++++++++++ include/hw/ppc/xive_regs.h | 30 +++++++++++++++++ hw/intc/xive.c | 84 ++++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 146 insertions(+) create mode 100644 include/hw/ppc/xive_regs.h diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index be93fae6317b..13c414bf7d55 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -11,6 +11,7 @@ #define PPC_XIVE_H =20 #include "hw/sysbus.h" +#include "hw/ppc/xive_regs.h" =20 /* * XIVE Fabric (Interface between Source and Router) @@ -168,4 +169,35 @@ static inline void xive_source_irq_set(XiveSource *xsr= c, uint32_t srcno, } } =20 +/* + * XIVE Router + */ + +typedef struct XiveRouter { + SysBusDevice parent; + + uint32_t chip_id; +} XiveRouter; + +#define TYPE_XIVE_ROUTER "xive-router" +#define XIVE_ROUTER(obj) \ + OBJECT_CHECK(XiveRouter, (obj), TYPE_XIVE_ROUTER) +#define XIVE_ROUTER_CLASS(klass) \ + OBJECT_CLASS_CHECK(XiveRouterClass, (klass), TYPE_XIVE_ROUTER) +#define XIVE_ROUTER_GET_CLASS(obj) \ + OBJECT_GET_CLASS(XiveRouterClass, (obj), TYPE_XIVE_ROUTER) + +typedef struct XiveRouterClass { + SysBusDeviceClass parent; + + /* XIVE table accessors */ + int (*get_ive)(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive); + int (*set_ive)(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive); +} XiveRouterClass; + +void xive_router_print_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive, + Monitor *mon); +int xive_router_get_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive); +int xive_router_set_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive); + #endif /* PPC_XIVE_H */ diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h new file mode 100644 index 000000000000..74420030111a --- /dev/null +++ b/include/hw/ppc/xive_regs.h @@ -0,0 +1,30 @@ +/* + * QEMU PowerPC XIVE interrupt controller model + * + * Copyright (c) 2016-2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef _PPC_XIVE_REGS_H +#define _PPC_XIVE_REGS_H + +/* IVE (Interrupt Virtualization Entry) + * + * One per interrupt source. Targets that interrupt to a given EQ + * and provides the corresponding logical interrupt number (EQ data) + */ +typedef struct XiveIVE { + /* Use a single 64-bit definition to make it easier to + * perform atomic updates + */ + uint64_t w; +#define IVE_VALID PPC_BIT(0) +#define IVE_EQ_BLOCK PPC_BITMASK(4, 7) /* Destination EQ block# = */ +#define IVE_EQ_INDEX PPC_BITMASK(8, 31) /* Destination EQ index */ +#define IVE_MASKED PPC_BIT(32) /* Masked */ +#define IVE_EQ_DATA PPC_BITMASK(33, 63) /* Data written to the EQ= */ +} XiveIVE; + +#endif /* _PPC_XIVE_REGS_H */ diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 3f6fcb358f83..7f007d5a3ec0 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -443,6 +443,89 @@ static const TypeInfo xive_source_info =3D { }; =20 /* + * XIVE Router (aka. Virtualization Controller or IVRE) + */ + +int xive_router_get_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive) +{ + XiveRouterClass *xrc =3D XIVE_ROUTER_GET_CLASS(xrtr); + + return xrc->get_ive(xrtr, lisn, ive); +} + +int xive_router_set_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive) +{ + XiveRouterClass *xrc =3D XIVE_ROUTER_GET_CLASS(xrtr); + + return xrc->set_ive(xrtr, lisn, ive); +} + +static void xive_router_notify(XiveFabric *xf, uint32_t lisn) +{ + XiveRouter *xrtr =3D XIVE_ROUTER(xf); + XiveIVE ive; + + /* IVE cache lookup */ + if (xive_router_get_ive(xrtr, lisn, &ive)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Unknown LISN %x\n", lisn); + return; + } + + /* The IVRE has also a State Bit Cache for its internal sources + * which is also involed at this point. We can skip the SBC lookup + * here because the internal sources are modeled in a different + * way in QEMU. + */ + + if (!(ive.w & IVE_VALID)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid LISN %x\n", lisn); + return; + } + + if (ive.w & IVE_MASKED) { + /* Notification completed */ + return; + } +} + +static Property xive_router_properties[] =3D { + DEFINE_PROP_UINT32("chip-id", XiveRouter, chip_id, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xive_router_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + XiveFabricClass *xfc =3D XIVE_FABRIC_CLASS(klass); + + dc->desc =3D "XIVE Router Engine"; + dc->props =3D xive_router_properties; + xfc->notify =3D xive_router_notify; +} + +static const TypeInfo xive_router_info =3D { + .name =3D TYPE_XIVE_ROUTER, + .parent =3D TYPE_SYS_BUS_DEVICE, + .abstract =3D true, + .class_size =3D sizeof(XiveRouterClass), + .class_init =3D xive_router_class_init, + .interfaces =3D (InterfaceInfo[]) { + { TYPE_XIVE_FABRIC }, + { } + } +}; + +void xive_router_print_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive, + Monitor *mon) +{ + if (!(ive->w & IVE_VALID)) { + return; + } + + monitor_printf(mon, " %8x %s\n", lisn, ive->w & IVE_MASKED ? "M" : " = "); +} + +/* * XIVE Fabric */ static const TypeInfo xive_fabric_info =3D { @@ -455,6 +538,7 @@ static void xive_register_types(void) { type_register_static(&xive_source_info); type_register_static(&xive_fabric_info); + type_register_static(&xive_router_info); } =20 type_init(xive_register_types) --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528386960124682.9488086825409; Thu, 7 Jun 2018 08:56:00 -0700 (PDT) Received: from localhost ([::1]:58781 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxGZ-0006Lb-53 for importer@patchew.org; Thu, 07 Jun 2018 11:55:59 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38814) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxBq-00023v-Dq for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxBl-0003hy-Kh for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:06 -0400 Received: from 4.mo7.mail-out.ovh.net ([178.32.122.254]:52400) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxBl-0003h1-B3 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:01 -0400 Received: from player169.ha.ovh.net (unknown [10.109.122.116]) by mo7.mail-out.ovh.net (Postfix) with ESMTP id DD9B1B08C1 for ; Thu, 7 Jun 2018 17:50:59 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 79DCB580097; Thu, 7 Jun 2018 17:50:54 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:43 +0200 Message-Id: <20180607155003.1580-9-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6080703923150359379 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 178.32.122.254 Subject: [Qemu-devel] [PATCH v4 08/28] ppc/xive: introduce the XIVE Event Queues 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The Event Queue Descriptor (EQD) table is an internal table of the XIVE routing sub-engine, the IVRE. It specifies on which Event Queue the Event Queue data should be posted when an exception occurs (and later on pulled by the OS) and which Virtual Processor to notify. The routing algorithm of the XiveRouter is extended to push in the system memory event queue the Event Queue data defined in the associated IVE. The event queue is a circular buffer in RAM provided by the OS, one per server and priority couple, containing Event Queue entries. These are 4 bytes long, the first bit being a 'generation' bit and the 31 following bits the EQ Data field. The EQ Data field is a way to set an invariant logical event source number for an IRQ. It is set with the H_INT_SET_SOURCE_CONFIG hcall when the EISN flag is used. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/xive.h | 17 +++++ include/hw/ppc/xive_regs.h | 48 +++++++++++++ hw/intc/xive.c | 163 +++++++++++++++++++++++++++++++++++++++++= +++- 3 files changed, 227 insertions(+), 1 deletion(-) diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index 13c414bf7d55..fc2ed7319f0f 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -193,11 +193,28 @@ typedef struct XiveRouterClass { /* XIVE table accessors */ int (*get_ive)(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive); int (*set_ive)(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive); + int (*get_eq)(XiveRouter *xrtr, uint8_t eq_blk, uint32_t eq_idx, + XiveEQ *eq); + int (*set_eq)(XiveRouter *xrtr, uint8_t eq_blk, uint32_t eq_idx, + XiveEQ *eq); } XiveRouterClass; =20 void xive_router_print_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive, Monitor *mon); int xive_router_get_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive); int xive_router_set_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive); +int xive_router_get_eq(XiveRouter *xrtr, uint8_t eq_blk, uint32_t eq_idx, + XiveEQ *eq); +int xive_router_set_eq(XiveRouter *xrtr, uint8_t eq_blk, uint32_t eq_idx, + XiveEQ *eq); + +/* + * For legacy compatibility, the exceptions define up to 256 different + * priorities. P9 implements only 9 levels : 8 active levels [0 - 7] + * and the least favored level 0xFF. + */ +#define XIVE_PRIORITY_MAX 7 + +void xive_eq_reset(XiveEQ *eq); =20 #endif /* PPC_XIVE_H */ diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h index 74420030111a..50d96d028002 100644 --- a/include/hw/ppc/xive_regs.h +++ b/include/hw/ppc/xive_regs.h @@ -27,4 +27,52 @@ typedef struct XiveIVE { #define IVE_EQ_DATA PPC_BITMASK(33, 63) /* Data written to the EQ= */ } XiveIVE; =20 +/* EQ */ +typedef struct XiveEQ { + uint32_t w0; +#define EQ_W0_VALID PPC_BIT32(0) /* "v" bit */ +#define EQ_W0_ENQUEUE PPC_BIT32(1) /* "q" bit */ +#define EQ_W0_UCOND_NOTIFY PPC_BIT32(2) /* "n" bit */ +#define EQ_W0_BACKLOG PPC_BIT32(3) /* "b" bit */ +#define EQ_W0_PRECL_ESC_CTL PPC_BIT32(4) /* "p" bit */ +#define EQ_W0_ESCALATE_CTL PPC_BIT32(5) /* "e" bit */ +#define EQ_W0_UNCOND_ESCALATE PPC_BIT32(6) /* "u" bit - DD2.0 */ +#define EQ_W0_SILENT_ESCALATE PPC_BIT32(7) /* "s" bit - DD2.0 */ +#define EQ_W0_QSIZE PPC_BITMASK32(12, 15) +#define EQ_W0_SW0 PPC_BIT32(16) +#define EQ_W0_FIRMWARE EQ_W0_SW0 /* Owned by FW */ +#define EQ_QSIZE_4K 0 +#define EQ_QSIZE_64K 4 +#define EQ_W0_HWDEP PPC_BITMASK32(24, 31) + uint32_t w1; +#define EQ_W1_ESn PPC_BITMASK32(0, 1) +#define EQ_W1_ESn_P PPC_BIT32(0) +#define EQ_W1_ESn_Q PPC_BIT32(1) +#define EQ_W1_ESe PPC_BITMASK32(2, 3) +#define EQ_W1_ESe_P PPC_BIT32(2) +#define EQ_W1_ESe_Q PPC_BIT32(3) +#define EQ_W1_GENERATION PPC_BIT32(9) +#define EQ_W1_PAGE_OFF PPC_BITMASK32(10, 31) + uint32_t w2; +#define EQ_W2_MIGRATION_REG PPC_BITMASK32(0, 3) +#define EQ_W2_OP_DESC_HI PPC_BITMASK32(4, 31) + uint32_t w3; +#define EQ_W3_OP_DESC_LO PPC_BITMASK32(0, 31) + uint32_t w4; +#define EQ_W4_ESC_EQ_BLOCK PPC_BITMASK32(4, 7) +#define EQ_W4_ESC_EQ_INDEX PPC_BITMASK32(8, 31) + uint32_t w5; +#define EQ_W5_ESC_EQ_DATA PPC_BITMASK32(1, 31) + uint32_t w6; +#define EQ_W6_FORMAT_BIT PPC_BIT32(8) +#define EQ_W6_NVT_BLOCK PPC_BITMASK32(9, 12) +#define EQ_W6_NVT_INDEX PPC_BITMASK32(13, 31) + uint32_t w7; +#define EQ_W7_F0_IGNORE PPC_BIT32(0) +#define EQ_W7_F0_BLK_GROUPING PPC_BIT32(1) +#define EQ_W7_F0_PRIORITY PPC_BITMASK32(8, 15) +#define EQ_W7_F1_WAKEZ PPC_BIT32(0) +#define EQ_W7_F1_LOG_SERVER_ID PPC_BITMASK32(1, 31) +} XiveEQ; + #endif /* _PPC_XIVE_REGS_H */ diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 7f007d5a3ec0..ae5c7f545d30 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -443,6 +443,64 @@ static const TypeInfo xive_source_info =3D { }; =20 /* + * XiveEQ helpers + */ + +void xive_eq_reset(XiveEQ *eq) +{ + memset(eq, 0, sizeof(*eq)); + + /* switch off the escalation and notification ESBs */ + eq->w1 =3D EQ_W1_ESe_Q | EQ_W1_ESn_Q; +} + +static void xive_eq_pic_print_info(XiveEQ *eq, Monitor *mon) +{ + uint64_t qaddr_base =3D (((uint64_t)(eq->w2 & 0x0fffffff)) << 32) | eq= ->w3; + uint32_t qindex =3D GETFIELD(EQ_W1_PAGE_OFF, eq->w1); + uint32_t qgen =3D GETFIELD(EQ_W1_GENERATION, eq->w1); + uint32_t qsize =3D GETFIELD(EQ_W0_QSIZE, eq->w0); + uint32_t qentries =3D 1 << (qsize + 10); + + uint32_t server =3D GETFIELD(EQ_W6_NVT_INDEX, eq->w6); + uint8_t priority =3D GETFIELD(EQ_W7_F0_PRIORITY, eq->w7); + + monitor_printf(mon, "%c%c%c%c%c prio:%d server:%03d eq:@%08"PRIx64 + "% 6d/%5d ^%d", + eq->w0 & EQ_W0_VALID ? 'v' : '-', + eq->w0 & EQ_W0_ENQUEUE ? 'q' : '-', + eq->w0 & EQ_W0_UCOND_NOTIFY ? 'n' : '-', + eq->w0 & EQ_W0_BACKLOG ? 'b' : '-', + eq->w0 & EQ_W0_ESCALATE_CTL ? 'e' : '-', + priority, server, qaddr_base, qindex, qentries, qgen); +} + +static void xive_eq_push(XiveEQ *eq, uint32_t data) +{ + uint64_t qaddr_base =3D (((uint64_t)(eq->w2 & 0x0fffffff)) << 32) | eq= ->w3; + uint32_t qsize =3D GETFIELD(EQ_W0_QSIZE, eq->w0); + uint32_t qindex =3D GETFIELD(EQ_W1_PAGE_OFF, eq->w1); + uint32_t qgen =3D GETFIELD(EQ_W1_GENERATION, eq->w1); + + uint64_t qaddr =3D qaddr_base + (qindex << 2); + uint32_t qdata =3D cpu_to_be32((qgen << 31) | (data & 0x7fffffff)); + uint32_t qentries =3D 1 << (qsize + 10); + + if (dma_memory_write(&address_space_memory, qaddr, &qdata, sizeof(qdat= a))) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to write EQ data @0x%" + HWADDR_PRIx "\n", qaddr); + return; + } + + qindex =3D (qindex + 1) % qentries; + if (qindex =3D=3D 0) { + qgen ^=3D 1; + eq->w1 =3D SETFIELD(EQ_W1_GENERATION, eq->w1, qgen); + } + eq->w1 =3D SETFIELD(EQ_W1_PAGE_OFF, eq->w1, qindex); +} + +/* * XIVE Router (aka. Virtualization Controller or IVRE) */ =20 @@ -460,6 +518,81 @@ int xive_router_set_ive(XiveRouter *xrtr, uint32_t lis= n, XiveIVE *ive) return xrc->set_ive(xrtr, lisn, ive); } =20 +int xive_router_get_eq(XiveRouter *xrtr, uint8_t eq_blk, uint32_t eq_idx, + XiveEQ *eq) +{ + XiveRouterClass *xrc =3D XIVE_ROUTER_GET_CLASS(xrtr); + + return xrc->get_eq(xrtr, eq_blk, eq_idx, eq); +} + +int xive_router_set_eq(XiveRouter *xrtr, uint8_t eq_blk, uint32_t eq_idx, + XiveEQ *eq) +{ + XiveRouterClass *xrc =3D XIVE_ROUTER_GET_CLASS(xrtr); + + return xrc->set_eq(xrtr, eq_blk, eq_idx, eq); +} + +/* + * An EQ trigger can come from an event trigger (IPI or HW) or from + * another chip. We don't model the PowerBus but the EQ trigger + * message has the same parameters than in the function below. + */ +static void xive_router_eq_notify(XiveRouter *xrtr, uint8_t eq_blk, + uint32_t eq_idx, uint32_t eq_data) +{ + XiveEQ eq; + uint8_t priority; + uint8_t format; + + /* EQD cache lookup */ + if (xive_router_get_eq(xrtr, eq_blk, eq_idx, &eq)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No EQ %x/%x\n", eq_blk, eq_i= dx); + return; + } + + if (!(eq.w0 & EQ_W0_VALID)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: EQ %x/%x is invalid\n", + eq_blk, eq_idx); + return; + } + + if (eq.w0 & EQ_W0_ENQUEUE) { + xive_eq_push(&eq, eq_data); + xive_router_set_eq(xrtr, eq_blk, eq_idx, &eq); + } + + /* + * The W7 format depends on the F bit in W6. It defines the type + * of the notification : + * + * F=3D0 : single or multiple VP notification + * F=3D1 : User level Event-Based Branch (EBB) notification, no + * priority + */ + format =3D GETFIELD(EQ_W6_FORMAT_BIT, eq.w6); + priority =3D GETFIELD(EQ_W7_F0_PRIORITY, eq.w7); + + /* The EQ is masked */ + if (format =3D=3D 0 && priority =3D=3D 0xff) { + return; + } + + /* + * Check the EQ ESn (Event State Buffer for notification) for + * futher even coalescing in the Router + */ + if (!(eq.w0 & EQ_W0_UCOND_NOTIFY)) { + qemu_log_mask(LOG_UNIMP, "XIVE: !UCOND_NOTIFY not implemented\n"); + return; + } + + /* + * Follows IVPE notification + */ +} + static void xive_router_notify(XiveFabric *xf, uint32_t lisn) { XiveRouter *xrtr =3D XIVE_ROUTER(xf); @@ -486,6 +619,14 @@ static void xive_router_notify(XiveFabric *xf, uint32_= t lisn) /* Notification completed */ return; } + + /* + * The event trigger becomes an EQ trigger + */ + xive_router_eq_notify(xrtr, + GETFIELD(IVE_EQ_BLOCK, ive.w), + GETFIELD(IVE_EQ_INDEX, ive.w), + GETFIELD(IVE_EQ_DATA, ive.w)); } =20 static Property xive_router_properties[] =3D { @@ -518,11 +659,31 @@ static const TypeInfo xive_router_info =3D { void xive_router_print_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive, Monitor *mon) { + uint8_t eq_blk; + uint32_t eq_idx; + if (!(ive->w & IVE_VALID)) { return; } =20 - monitor_printf(mon, " %8x %s\n", lisn, ive->w & IVE_MASKED ? "M" : " = "); + eq_idx =3D GETFIELD(IVE_EQ_INDEX, ive->w); + eq_blk =3D GETFIELD(IVE_EQ_BLOCK, ive->w); + + monitor_printf(mon, " %8x %s eqidx:%04x eqblk:%02x ", lisn, + ive->w & IVE_MASKED ? "M" : " ", eq_idx, eq_blk); + + if (!(ive->w & IVE_MASKED)) { + XiveEQ eq; + + if (!xive_router_get_eq(xrtr, eq_blk, eq_idx, &eq)) { + xive_eq_pic_print_info(&eq, mon); + monitor_printf(mon, " data:%08x", + (int) GETFIELD(IVE_EQ_DATA, ive->w)); + } else { + monitor_printf(mon, "no eq ?!"); + } + } + monitor_printf(mon, "\n"); } =20 /* --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 152838712188383.27453098864362; Thu, 7 Jun 2018 08:58:41 -0700 (PDT) Received: from localhost ([::1]:58795 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxJB-0000Fh-5E for importer@patchew.org; Thu, 07 Jun 2018 11:58:41 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38839) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxBv-00028F-Rd for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:13 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxBr-0003la-46 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:11 -0400 Received: from 3.mo178.mail-out.ovh.net ([46.105.44.197]:36846) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxBq-0003kj-Q8 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:07 -0400 Received: from player169.ha.ovh.net (unknown [10.109.105.30]) by mo178.mail-out.ovh.net (Postfix) with ESMTP id 6169E1A18E for ; Thu, 7 Jun 2018 17:51:05 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id EAB82580091; Thu, 7 Jun 2018 17:50:59 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:44 +0200 Message-Id: <20180607155003.1580-10-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6082392773681056595 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.44.197 Subject: [Qemu-devel] [PATCH v4 09/28] ppc/xive: add support for the EQ Event State buffers 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The Event Queue Descriptor also contains two Event State Buffers providing further coalescing of interrupts, one for the notification event (ESn) and one for the escalation events (ESe). A MMIO page is assigned for each to control the EOI through loads only. Stores are not allowed. The EQ ESB are modeled through an object resembling the 'XiveSource' It is stateless as the EQ state bits are backed into the XiveEQ structure under the XiveRouter and the MMIO accesses follow the same rules as the standard source ESBs. EQ ESBs are not supported by the Linux drivers neither on OPAL nor on sPAPR. Nnevetherless, it provides a mean to study the question in the future and validates a bit more the XIVE model. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/xive.h | 20 +++++++ hw/intc/xive.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++= +++- 2 files changed, 177 insertions(+), 2 deletions(-) diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index fc2ed7319f0f..e5f6800b50d3 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -209,6 +209,26 @@ int xive_router_set_eq(XiveRouter *xrtr, uint8_t eq_bl= k, uint32_t eq_idx, XiveEQ *eq); =20 /* + * XIVE EQ ESBs + */ + +#define TYPE_XIVE_EQ_SOURCE "xive-eq-source" +#define XIVE_EQ_SOURCE(obj) \ + OBJECT_CHECK(XiveEQSource, (obj), TYPE_XIVE_EQ_SOURCE) + +typedef struct XiveEQSource { + SysBusDevice parent; + + uint32_t nr_eqs; + + /* ESB memory region */ + uint32_t esb_shift; + MemoryRegion esb_mmio; + + XiveRouter *xrtr; +} XiveEQSource; + +/* * For legacy compatibility, the exceptions define up to 256 different * priorities. P9 implements only 9 levels : 8 active levels [0 - 7] * and the least favored level 0xFF. diff --git a/hw/intc/xive.c b/hw/intc/xive.c index ae5c7f545d30..64d8d15385bc 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -584,8 +584,18 @@ static void xive_router_eq_notify(XiveRouter *xrtr, ui= nt8_t eq_blk, * futher even coalescing in the Router */ if (!(eq.w0 & EQ_W0_UCOND_NOTIFY)) { - qemu_log_mask(LOG_UNIMP, "XIVE: !UCOND_NOTIFY not implemented\n"); - return; + uint8_t pq =3D GETFIELD(EQ_W1_ESn, eq.w1); + bool notify =3D xive_esb_trigger(&pq); + + if (pq !=3D GETFIELD(EQ_W1_ESn, eq.w1)) { + eq.w1 =3D SETFIELD(EQ_W1_ESn, eq.w1, pq); + xive_router_set_eq(xrtr, eq_blk, eq_idx, &eq); + } + + /* ESn[Q]=3D1 : end of notification */ + if (!notify) { + return; + } } =20 /* @@ -687,6 +697,150 @@ void xive_router_print_ive(XiveRouter *xrtr, uint32_t= lisn, XiveIVE *ive, } =20 /* + * EQ ESB MMIO loads + */ +static uint64_t xive_eq_source_read(void *opaque, hwaddr addr, unsigned si= ze) +{ + XiveEQSource *xsrc =3D XIVE_EQ_SOURCE(opaque); + XiveRouter *xrtr =3D xsrc->xrtr; + uint32_t offset =3D addr & 0xFFF; + uint8_t eq_blk; + uint32_t eq_idx; + XiveEQ eq; + uint32_t eq_esmask; + uint8_t pq; + uint64_t ret =3D -1; + + eq_blk =3D xrtr->chip_id; + eq_idx =3D addr >> (xsrc->esb_shift + 1); + if (xive_router_get_eq(xrtr, eq_blk, eq_idx, &eq)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No EQ %x/%x\n", eq_blk, eq_i= dx); + return -1; + } + + if (!(eq.w0 & EQ_W0_VALID)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: EQ %x/%x is invalid\n", + eq_blk, eq_idx); + return -1; + } + + eq_esmask =3D addr_is_even(addr, xsrc->esb_shift) ? EQ_W1_ESn : EQ_W1_= ESe; + pq =3D GETFIELD(eq_esmask, eq.w1); + + switch (offset) { + case XIVE_ESB_LOAD_EOI ... XIVE_ESB_LOAD_EOI + 0x7FF: + ret =3D xive_esb_eoi(&pq); + + /* Forward the source event notification for routing ?? */ + break; + + case XIVE_ESB_GET ... XIVE_ESB_GET + 0x3FF: + ret =3D pq; + break; + + case XIVE_ESB_SET_PQ_00 ... XIVE_ESB_SET_PQ_00 + 0x0FF: + case XIVE_ESB_SET_PQ_01 ... XIVE_ESB_SET_PQ_01 + 0x0FF: + case XIVE_ESB_SET_PQ_10 ... XIVE_ESB_SET_PQ_10 + 0x0FF: + case XIVE_ESB_SET_PQ_11 ... XIVE_ESB_SET_PQ_11 + 0x0FF: + ret =3D xive_esb_set(&pq, (offset >> 8) & 0x3); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid EQ ESB load addr %d\= n", + offset); + return -1; + } + + if (pq !=3D GETFIELD(eq_esmask, eq.w1)) { + eq.w1 =3D SETFIELD(eq_esmask, eq.w1, pq); + xive_router_set_eq(xrtr, eq_blk, eq_idx, &eq); + } + + return ret; +} + +/* + * EQ ESB MMIO stores are invalid + */ +static void xive_eq_source_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid ESB write addr 0x%" + HWADDR_PRIx"\n", addr); +} + +static const MemoryRegionOps xive_eq_source_ops =3D { + .read =3D xive_eq_source_read, + .write =3D xive_eq_source_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + }, + .impl =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + }, +}; + +static void xive_eq_source_realize(DeviceState *dev, Error **errp) +{ + XiveEQSource *xsrc =3D XIVE_EQ_SOURCE(dev); + Object *obj; + Error *local_err =3D NULL; + + obj =3D object_property_get_link(OBJECT(dev), "xive", &local_err); + if (!obj) { + error_propagate(errp, local_err); + error_prepend(errp, "required link 'xive' not found: "); + return; + } + + xsrc->xrtr =3D XIVE_ROUTER(obj); + + if (!xsrc->nr_eqs) { + error_setg(errp, "Number of interrupt needs to be greater than 0"); + return; + } + + if (xsrc->esb_shift !=3D XIVE_ESB_4K && + xsrc->esb_shift !=3D XIVE_ESB_64K) { + error_setg(errp, "Invalid ESB shift setting"); + return; + } + + /* + * Each EQ is assigned an even/odd pair of MMIO pages, the even page + * manages the ESn field while the odd page manages the ESe field. + */ + memory_region_init_io(&xsrc->esb_mmio, OBJECT(xsrc), + &xive_eq_source_ops, xsrc, "xive.eq", + (1ull << (xsrc->esb_shift + 1)) * xsrc->nr_eqs); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &xsrc->esb_mmio); +} + +static Property xive_eq_source_properties[] =3D { + DEFINE_PROP_UINT32("nr-eqs", XiveEQSource, nr_eqs, 0), + DEFINE_PROP_UINT32("shift", XiveEQSource, esb_shift, XIVE_ESB_64K), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xive_eq_source_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->desc =3D "XIVE EQ Source"; + dc->props =3D xive_eq_source_properties; + dc->realize =3D xive_eq_source_realize; +} + +static const TypeInfo xive_eq_source_info =3D { + .name =3D TYPE_XIVE_EQ_SOURCE, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(XiveEQSource), + .class_init =3D xive_eq_source_class_init, +}; + +/* * XIVE Fabric */ static const TypeInfo xive_fabric_info =3D { @@ -700,6 +854,7 @@ static void xive_register_types(void) type_register_static(&xive_source_info); type_register_static(&xive_fabric_info); type_register_static(&xive_router_info); + type_register_static(&xive_eq_source_info); } =20 type_init(xive_register_types) --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528387393314791.7079366760217; Thu, 7 Jun 2018 09:03:13 -0700 (PDT) Received: from localhost ([::1]:58833 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxNY-00044k-Ge for importer@patchew.org; Thu, 07 Jun 2018 12:03:12 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38867) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxC2-0002CZ-05 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:22 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxBx-0003om-7y for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:18 -0400 Received: from 5.mo69.mail-out.ovh.net ([46.105.43.105]:34558) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxBw-0003nN-Ny for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:13 -0400 Received: from player169.ha.ovh.net (unknown [10.109.122.17]) by mo69.mail-out.ovh.net (Postfix) with ESMTP id DCD35179EC for ; Thu, 7 Jun 2018 17:51:10 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 6F562580091; Thu, 7 Jun 2018 17:51:05 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:45 +0200 Message-Id: <20180607155003.1580-11-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6083800147262475091 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.43.105 Subject: [Qemu-devel] [PATCH v4 10/28] ppc/xive: introduce the XIVE interrupt thread context 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" There is a XIVE presenter in each POWER9 processor that can generate four different exceptions to its threads: - hypervisor exception, - O/S exception - Event-Based Branch (EBB) - msgsnd (doorbell). Each exception has a state independent from the others called a Thread Interrupt Management context. This context is a set of registers which let the thread handle priority management and interrupt acknowledgment among other things. The most important ones being : - Interrupt Priority Register (PIPR) - Interrupt Pending Buffer (IPB) - Current Processor Priority (CPPR) - Notification Source Register (NSR) These registers are accessible through a specific MMIO region, called the Thread Interrupt Management Area (TIMA), four aligned pages, each exposing a different view of the registers. First page (page address ending in 0b00) gives access to the entire context and is reserved for the ring 0 security monitor. The second (page address ending in 0b01) is for the hypervisor, ring 1. The third (page address ending in 0b10) is for the operating system, ring 2. The fourth (page address ending in 0b11) is for user level, ring 3. The thread interrupt context is modeled with a XiveTCTX object containing the values of the different exception registers. The TIMA region is mapped at the same address for each CPU. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/xive.h | 37 ++++ include/hw/ppc/xive_regs.h | 82 +++++++++ hw/intc/xive.c | 443 +++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 562 insertions(+) diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index e5f6800b50d3..280bd5a1e6ee 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -237,4 +237,41 @@ typedef struct XiveEQSource { =20 void xive_eq_reset(XiveEQ *eq); =20 + +/* + * XIVE Thread interrupt Management (TM) context + */ + +#define TYPE_XIVE_TCTX "xive-tctx" +#define XIVE_TCTX(obj) OBJECT_CHECK(XiveTCTX, (obj), TYPE_XIVE_TCTX) + +/* + * XIVE Thread interrupt Management register rings : + * + * QW-0 User event-based exception state + * QW-1 O/S OS context for priority management, interrupt acks + * QW-2 Pool hypervisor context for virtual processor being dispa= tched + * QW-3 Physical for the security monitor to manage the entire context + */ +#define TM_RING_COUNT 4 +#define TM_RING_SIZE 0x10 + +typedef struct XiveTCTX { + DeviceState parent_obj; + + CPUState *cs; + qemu_irq output; + + uint8_t regs[TM_RING_COUNT * TM_RING_SIZE]; + + XiveRouter *xrtr; +} XiveTCTX; + +/* + * XIVE Thread Interrupt Management Aera (TIMA) + */ +extern const MemoryRegionOps xive_tm_ops; + +void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon); + #endif /* PPC_XIVE_H */ diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h index 50d96d028002..a5473bb2d01b 100644 --- a/include/hw/ppc/xive_regs.h +++ b/include/hw/ppc/xive_regs.h @@ -10,6 +10,88 @@ #ifndef _PPC_XIVE_REGS_H #define _PPC_XIVE_REGS_H =20 +#define TM_SHIFT 16 + +/* TM register offsets */ +#define TM_QW0_USER 0x000 /* All rings */ +#define TM_QW1_OS 0x010 /* Ring 0..2 */ +#define TM_QW2_HV_POOL 0x020 /* Ring 0..1 */ +#define TM_QW3_HV_PHYS 0x030 /* Ring 0..1 */ + +/* Byte offsets inside a QW QW0 QW1 QW2 QW3 */ +#define TM_NSR 0x0 /* + + - + */ +#define TM_CPPR 0x1 /* - + - + */ +#define TM_IPB 0x2 /* - + + + */ +#define TM_LSMFB 0x3 /* - + + + */ +#define TM_ACK_CNT 0x4 /* - + - - */ +#define TM_INC 0x5 /* - + - + */ +#define TM_AGE 0x6 /* - + - + */ +#define TM_PIPR 0x7 /* - + - + */ + +#define TM_WORD0 0x0 +#define TM_WORD1 0x4 + +/* + * QW word 2 contains the valid bit at the top and other fields + * depending on the QW. + */ +#define TM_WORD2 0x8 +#define TM_QW0W2_VU PPC_BIT32(0) +#define TM_QW0W2_LOGIC_SERV PPC_BITMASK32(1, 31) /* XX 2,31 ? */ +#define TM_QW1W2_VO PPC_BIT32(0) +#define TM_QW1W2_OS_CAM PPC_BITMASK32(8, 31) +#define TM_QW2W2_VP PPC_BIT32(0) +#define TM_QW2W2_POOL_CAM PPC_BITMASK32(8, 31) +#define TM_QW3W2_VT PPC_BIT32(0) +#define TM_QW3W2_LP PPC_BIT32(6) +#define TM_QW3W2_LE PPC_BIT32(7) +#define TM_QW3W2_T PPC_BIT32(31) + +/* + * In addition to normal loads to "peek" and writes (only when invalid) + * using 4 and 8 bytes accesses, the above registers support these + * "special" byte operations: + * + * - Byte load from QW0[NSR] - User level NSR (EBB) + * - Byte store to QW0[NSR] - User level NSR (EBB) + * - Byte load/store to QW1[CPPR] and QW3[CPPR] - CPPR access + * - Byte load from QW3[TM_WORD2] - Read VT||00000||LP||LE on thrd 0 + * otherwise VT||0000000 + * - Byte store to QW3[TM_WORD2] - Set VT bit (and LP/LE if present) + * + * Then we have all these "special" CI ops at these offset that trigger + * all sorts of side effects: + */ +#define TM_SPC_ACK_EBB 0x800 /* Load8 ack EBB to reg*/ +#define TM_SPC_ACK_OS_REG 0x810 /* Load16 ack OS irq to reg */ +#define TM_SPC_PUSH_USR_CTX 0x808 /* Store32 Push/Validate user cont= ext */ +#define TM_SPC_PULL_USR_CTX 0x808 /* Load32 Pull/Invalidate user + * context */ +#define TM_SPC_SET_OS_PENDING 0x812 /* Store8 Set OS irq pending bit */ +#define TM_SPC_PULL_OS_CTX 0x818 /* Load32/Load64 Pull/Invalidate OS + * context to reg */ +#define TM_SPC_PULL_POOL_CTX 0x828 /* Load32/Load64 Pull/Invalidate P= ool + * context to reg*/ +#define TM_SPC_ACK_HV_REG 0x830 /* Load16 ack HV irq to reg */ +#define TM_SPC_PULL_USR_CTX_OL 0xc08 /* Store8 Pull/Inval usr ctx to odd + * line */ +#define TM_SPC_ACK_OS_EL 0xc10 /* Store8 ack OS irq to even line = */ +#define TM_SPC_ACK_HV_POOL_EL 0xc20 /* Store8 ack HV evt pool to even + * line */ +#define TM_SPC_ACK_HV_EL 0xc30 /* Store8 ack HV irq to even line = */ +/* XXX more... */ + +/* NSR fields for the various QW ack types */ +#define TM_QW0_NSR_EB PPC_BIT8(0) +#define TM_QW1_NSR_EO PPC_BIT8(0) +#define TM_QW3_NSR_HE PPC_BITMASK8(0, 1) +#define TM_QW3_NSR_HE_NONE 0 +#define TM_QW3_NSR_HE_POOL 1 +#define TM_QW3_NSR_HE_PHYS 2 +#define TM_QW3_NSR_HE_LSI 3 +#define TM_QW3_NSR_I PPC_BIT8(2) +#define TM_QW3_NSR_GRP_LVL PPC_BIT8(3, 7) + /* IVE (Interrupt Virtualization Entry) * * One per interrupt source. Targets that interrupt to a given EQ diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 64d8d15385bc..77e4f0e1f3f5 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -15,6 +15,448 @@ #include "sysemu/dma.h" #include "monitor/monitor.h" #include "hw/ppc/xive.h" +#include "hw/ppc/xive_regs.h" + +/* + * XIVE Thread Interrupt Management context + */ + +static uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t ring) +{ + return 0; +} + +static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr) +{ + if (cppr > XIVE_PRIORITY_MAX) { + cppr =3D 0xff; + } + + tctx->regs[ring + TM_CPPR] =3D cppr; +} + +/* + * XIVE Thread Interrupt Management Area (TIMA) + * + * This region gives access to the registers of the thread interrupt + * management context. It is four page wide, each page providing a + * different view of the registers. The page with the lower offset is + * the most privileged and gives access to the entire context. + */ + +#define XIVE_TM_HW_PAGE 0x0 +#define XIVE_TM_HV_PAGE 0x1 +#define XIVE_TM_OS_PAGE 0x2 +#define XIVE_TM_USER_PAGE 0x3 + +/* + * Define an access map for each page of the TIMA that we will use in + * the memory region ops to filter values when doing loads and stores + * of raw registers values + * + * Registers accessibility bits : + * + * 0x0 - no access + * 0x1 - write only + * 0x2 - read only + * 0x3 - read/write + */ + +static const uint8_t xive_tm_hw_view[] =3D { + /* QW-0 User */ 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, + /* QW-1 OS */ 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, + /* QW-2 HV */ 0, 0, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, + /* QW-3 HW */ 3, 3, 3, 3, 0, 3, 0, 3, 3, 0, 0, 3, 3, 3, 3, 0, +}; + +static const uint8_t xive_tm_hv_view[] =3D { + /* QW-0 User */ 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, + /* QW-1 OS */ 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, + /* QW-2 HV */ 0, 0, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, + /* QW-3 HW */ 3, 3, 3, 3, 0, 3, 0, 3, 3, 0, 0, 3, 0, 0, 0, 0, +}; + +static const uint8_t xive_tm_os_view[] =3D { + /* QW-0 User */ 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, + /* QW-1 OS */ 2, 3, 2, 2, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, + /* QW-2 HV */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* QW-3 HW */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, +}; + +static const uint8_t xive_tm_user_view[] =3D { + /* QW-0 User */ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* QW-1 OS */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* QW-2 HV */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* QW-3 HW */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +/* + * Overall TIMA access map for the thread interrupt management context + * registers + */ +static const uint8_t *xive_tm_views[] =3D { + [XIVE_TM_HW_PAGE] =3D xive_tm_hw_view, + [XIVE_TM_HV_PAGE] =3D xive_tm_hv_view, + [XIVE_TM_OS_PAGE] =3D xive_tm_os_view, + [XIVE_TM_USER_PAGE] =3D xive_tm_user_view, +}; + +/* + * Computes a register access mask for a given offset in the TIMA + */ +static uint64_t xive_tm_mask(hwaddr offset, unsigned size, bool write) +{ + uint8_t page_offset =3D (offset >> TM_SHIFT) & 0x3; + uint8_t reg_offset =3D offset & 0x3F; + uint8_t reg_mask =3D write ? 0x1 : 0x2; + uint64_t mask =3D 0x0; + int i; + + for (i =3D 0; i < size; i++) { + if (xive_tm_views[page_offset][reg_offset + i] & reg_mask) { + mask |=3D (uint64_t) 0xff << (8 * (size - i - 1)); + } + } + + return mask; +} + +static void xive_tm_raw_write(XiveTCTX *tctx, hwaddr offset, uint64_t valu= e, + unsigned size) +{ + uint8_t ring_offset =3D offset & 0x30; + uint8_t reg_offset =3D offset & 0x3F; + uint64_t mask =3D xive_tm_mask(offset, size, true); + int i; + + /* + * Only 4 or 8 bytes stores are allowed and the User ring is + * excluded + */ + if (size < 4 || !mask || ring_offset =3D=3D TM_QW0_USER) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at TIMA= @%" + HWADDR_PRIx"\n", offset); + return; + } + + /* + * Use the register offset for the raw values and filter out + * reserved values + */ + for (i =3D 0; i < size; i++) { + uint8_t byte_mask =3D (mask >> (8 * (size - i - 1))); + if (byte_mask) { + tctx->regs[reg_offset + i] =3D (value >> (8 * (size - i - 1)))= & + byte_mask; + } + } +} + +static uint64_t xive_tm_raw_read(XiveTCTX *tctx, hwaddr offset, unsigned s= ize) +{ + uint8_t ring_offset =3D offset & 0x30; + uint8_t reg_offset =3D offset & 0x3F; + uint64_t mask =3D xive_tm_mask(offset, size, false); + uint64_t ret; + int i; + + /* + * Only 4 or 8 bytes loads are allowed and the User ring is + * excluded + */ + if (size < 4 || !mask || ring_offset =3D=3D TM_QW0_USER) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid read access at TIMA = @%" + HWADDR_PRIx"\n", offset); + return -1; + } + + /* Use the register offset for the raw values */ + ret =3D 0; + for (i =3D 0; i < size; i++) { + ret |=3D (uint64_t) tctx->regs[reg_offset + i] << (8 * (size - i -= 1)); + } + + /* filter out reserved values */ + return ret & mask; +} + +/* + * The TM context is mapped twice within each page. Stores and loads + * to the first mapping below 2K write and read the specified values + * without modification. The second mapping above 2K performs specific + * state changes (side effects) in addition to setting/returning the + * interrupt management area context of the processor thread. + */ +static uint64_t xive_tm_ack_os_reg(XiveTCTX *tctx, hwaddr offset, unsigned= size) +{ + return xive_tctx_accept(tctx, TM_QW1_OS); +} + +static void xive_tm_set_os_cppr(XiveTCTX *tctx, hwaddr offset, + uint64_t value, unsigned size) +{ + xive_tctx_set_cppr(tctx, TM_QW1_OS, value & 0xff); +} + +/* + * Define a mapping of "special" operations depending on the TIMA page + * offset and the size of the operation. + */ +typedef struct XiveTmOp { + uint8_t page_offset; + uint32_t op_offset; + unsigned size; + void (*write_handler)(XiveTCTX *tctx, hwaddr offset, uint64_t valu= e, + unsigned size); + uint64_t (*read_handler)(XiveTCTX *tctx, hwaddr offset, unsigned size); +} XiveTmOp; + +static const XiveTmOp xive_tm_operations[] =3D { + /* + * MMIOs below 2K : raw values and special operations without side + * effects + */ + { XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr, NULL= }, + + /* MMIOs above 2K : special operations with side effects */ + { XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL, xive_tm_ack_os_reg = }, +}; + +static const XiveTmOp *xive_tm_find_op(hwaddr offset, unsigned size, bool = write) +{ + uint8_t page_offset =3D (offset >> TM_SHIFT) & 0x3; + uint32_t op_offset =3D offset & 0xFFF; + int i; + + for (i =3D 0; i < ARRAY_SIZE(xive_tm_operations); i++) { + const XiveTmOp *xto =3D &xive_tm_operations[i]; + + /* Accesses done from a more privileged TIMA page is allowed */ + if (xto->page_offset >=3D page_offset && + xto->op_offset =3D=3D op_offset && + xto->size =3D=3D size && + ((write && xto->write_handler) || (!write && xto->read_handler= ))) { + return xto; + } + } + return NULL; +} + +/* + * TIMA MMIO handlers + */ +static void xive_tm_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + PowerPCCPU *cpu =3D POWERPC_CPU(current_cpu); + XiveTCTX *tctx =3D XIVE_TCTX(cpu->intc); + const XiveTmOp *xto; + + /* + * TODO: check V bit in Q[0-3]W2, check PTER bit associated with CPU + */ + + /* + * First, check for special operations in the 2K region + */ + if (offset & 0x800) { + xto =3D xive_tm_find_op(offset, size, true); + if (!xto) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at = TIMA" + "@%"HWADDR_PRIx"\n", offset); + } else { + xto->write_handler(tctx, offset, value, size); + } + return; + } + + /* + * Then, for special operations in the region below 2K. + */ + xto =3D xive_tm_find_op(offset, size, true); + if (xto) { + xto->write_handler(tctx, offset, value, size); + return; + } + + /* + * Finish with raw access to the register values + */ + xive_tm_raw_write(tctx, offset, value, size); +} + +static uint64_t xive_tm_read(void *opaque, hwaddr offset, unsigned size) +{ + PowerPCCPU *cpu =3D POWERPC_CPU(current_cpu); + XiveTCTX *tctx =3D XIVE_TCTX(cpu->intc); + const XiveTmOp *xto; + + /* + * TODO: check V bit in Q[0-3]W2, check PTER bit associated with CPU + */ + + /* + * First, check for special operations in the 2K region + */ + if (offset & 0x800) { + xto =3D xive_tm_find_op(offset, size, false); + if (!xto) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid read access to T= IMA" + "@%"HWADDR_PRIx"\n", offset); + return -1; + } + return xto->read_handler(tctx, offset, size); + } + + /* + * Then, for special operations in the region below 2K. + */ + xto =3D xive_tm_find_op(offset, size, false); + if (xto) { + return xto->read_handler(tctx, offset, size); + } + + /* + * Finish with raw access to the register values + */ + return xive_tm_raw_read(tctx, offset, size); +} + +const MemoryRegionOps xive_tm_ops =3D { + .read =3D xive_tm_read, + .write =3D xive_tm_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 8, + }, + .impl =3D { + .min_access_size =3D 1, + .max_access_size =3D 8, + }, +}; + +static char *xive_tctx_ring_print(uint8_t *ring) +{ + uint32_t w2 =3D be32_to_cpu(*((uint32_t *) &ring[TM_WORD2])); + + return g_strdup_printf("%02x %02x %02x %02x %02x " + "%02x %02x %02x %08x", + ring[TM_NSR], ring[TM_CPPR], ring[TM_IPB], ring[TM_LSMF= B], + ring[TM_ACK_CNT], ring[TM_INC], ring[TM_AGE], ring[TM_P= IPR], + w2); +} + +static const struct { + uint8_t qw; + const char *name; +} xive_tctx_ring_infos[TM_RING_COUNT] =3D { + { TM_QW3_HV_PHYS, "HW" }, + { TM_QW2_HV_POOL, "HV" }, + { TM_QW1_OS, "OS" }, + { TM_QW0_USER, "USER" }, +}; + +void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon) +{ + int cpu_index =3D tctx->cs ? tctx->cs->cpu_index : -1; + int i; + + monitor_printf(mon, "CPU[%04x]: QW NSR CPPR IPB LSMFB ACK# INC AGE= PIPR" + " W2\n", cpu_index); + + for (i =3D 0; i < TM_RING_COUNT; i++) { + char *s =3D xive_tctx_ring_print(&tctx->regs[xive_tctx_ring_infos[= i].qw]); + monitor_printf(mon, "CPU[%04x]: %4s %s\n", cpu_index, + xive_tctx_ring_infos[i].name, s); + g_free(s); + } +} + +static void xive_tctx_reset(void *dev) +{ + XiveTCTX *tctx =3D XIVE_TCTX(dev); + + memset(tctx->regs, 0, sizeof(tctx->regs)); + + /* Set some defaults */ + tctx->regs[TM_QW1_OS + TM_LSMFB] =3D 0xFF; + tctx->regs[TM_QW1_OS + TM_ACK_CNT] =3D 0xFF; + tctx->regs[TM_QW1_OS + TM_AGE] =3D 0xFF; +} + +static void xive_tctx_realize(DeviceState *dev, Error **errp) +{ + XiveTCTX *tctx =3D XIVE_TCTX(dev); + PowerPCCPU *cpu; + CPUPPCState *env; + Object *obj; + Error *local_err =3D NULL; + + obj =3D object_property_get_link(OBJECT(dev), "xive", &local_err); + if (!obj) { + error_propagate(errp, local_err); + error_prepend(errp, "required link 'xive' not found: "); + return; + } + tctx->xrtr =3D XIVE_ROUTER(obj); + + obj =3D object_property_get_link(OBJECT(dev), "cpu", &local_err); + if (!obj) { + error_propagate(errp, local_err); + error_prepend(errp, "required link 'cpu' not found: "); + return; + } + + cpu =3D POWERPC_CPU(obj); + tctx->cs =3D CPU(obj); + + env =3D &cpu->env; + switch (PPC_INPUT(env)) { + case PPC_FLAGS_INPUT_POWER7: + tctx->output =3D env->irq_inputs[POWER7_INPUT_INT]; + break; + + default: + error_setg(errp, "XIVE interrupt controller does not support " + "this CPU bus model"); + return; + } + + qemu_register_reset(xive_tctx_reset, dev); +} + +static void xive_tctx_unrealize(DeviceState *dev, Error **errp) +{ + qemu_unregister_reset(xive_tctx_reset, dev); +} + +static const VMStateDescription vmstate_xive_tctx =3D { + .name =3D TYPE_XIVE_TCTX, + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_BUFFER(regs, XiveTCTX), + VMSTATE_END_OF_LIST() + }, +}; + +static void xive_tctx_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->realize =3D xive_tctx_realize; + dc->unrealize =3D xive_tctx_unrealize; + dc->desc =3D "XIVE Interrupt Thread Context"; + dc->vmsd =3D &vmstate_xive_tctx; +} + +static const TypeInfo xive_tctx_info =3D { + .name =3D TYPE_XIVE_TCTX, + .parent =3D TYPE_DEVICE, + .instance_size =3D sizeof(XiveTCTX), + .class_init =3D xive_tctx_class_init, +}; =20 /* * XIVE ESB helpers @@ -855,6 +1297,7 @@ static void xive_register_types(void) type_register_static(&xive_fabric_info); type_register_static(&xive_router_info); type_register_static(&xive_eq_source_info); + type_register_static(&xive_tctx_info); } =20 type_init(xive_register_types) --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528387159230906.9078174212195; Thu, 7 Jun 2018 08:59:19 -0700 (PDT) Received: from localhost ([::1]:58799 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxJm-0000kn-Co for importer@patchew.org; Thu, 07 Jun 2018 11:59:18 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38906) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxC7-0002HT-79 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxC2-0003rQ-AK for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:23 -0400 Received: from 9.mo1.mail-out.ovh.net ([178.32.108.172]:57867) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxC2-0003qU-03 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:18 -0400 Received: from player169.ha.ovh.net (unknown [10.109.105.80]) by mo1.mail-out.ovh.net (Postfix) with ESMTP id 5DB09105B97 for ; Thu, 7 Jun 2018 17:51:16 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id E8F9558009A; Thu, 7 Jun 2018 17:51:10 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:46 +0200 Message-Id: <20180607155003.1580-12-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6085488996675586899 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 178.32.108.172 Subject: [Qemu-devel] [PATCH v4 11/28] ppc/xive: introduce a simplified XIVE presenter 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The last sub-engine of the XIVE architecture is the Interrupt Virtualization Presentation Engine (IVPE). On HW, they share elements, the Power Bus interface (CQ), the routing table descriptors, and they can be combined in the same HW logic. We do the same in QEMU and combine both engines in the XiveRouter for simplicity. When the IVRE has completed its job of matching an event source with a Virtual Processor (VP) target to notify, it forwards the event notification to the IVPE handling the Virtual Processor threads. The IVPE scans the thread interrupt context of the VPs dispatched on the HW processor threads and if a match is found, it signals the thread. If not, the IVRE escalates the notification to some other targets and records the notification in a backlog queue. The IVPE maintains the thread interrupt context state for each of its VPs not dispatched on HW processor threads in the Virtual Processor Descriptor (VPD) table. The model currently only supports single VP notifications. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/xive.h | 8 ++ include/hw/ppc/xive_regs.h | 22 +++++ hw/intc/xive.c | 227 +++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 257 insertions(+) diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index 280bd5a1e6ee..e29b52eeb91f 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -197,6 +197,10 @@ typedef struct XiveRouterClass { XiveEQ *eq); int (*set_eq)(XiveRouter *xrtr, uint8_t eq_blk, uint32_t eq_idx, XiveEQ *eq); + int (*get_vp)(XiveRouter *xrtr, uint8_t vp_blk, uint32_t vp_idx, + XiveVP *vp); + int (*set_vp)(XiveRouter *xrtr, uint8_t vp_blk, uint32_t vp_idx, + XiveVP *vp); } XiveRouterClass; =20 void xive_router_print_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive, @@ -207,6 +211,10 @@ int xive_router_get_eq(XiveRouter *xrtr, uint8_t eq_bl= k, uint32_t eq_idx, XiveEQ *eq); int xive_router_set_eq(XiveRouter *xrtr, uint8_t eq_blk, uint32_t eq_idx, XiveEQ *eq); +int xive_router_get_vp(XiveRouter *xrtr, uint8_t vp_blk, uint32_t vp_idx, + XiveVP *vp); +int xive_router_set_vp(XiveRouter *xrtr, uint8_t vp_blk, uint32_t vp_idx, + XiveVP *vp); =20 /* * XIVE EQ ESBs diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h index a5473bb2d01b..b438184a88b8 100644 --- a/include/hw/ppc/xive_regs.h +++ b/include/hw/ppc/xive_regs.h @@ -157,4 +157,26 @@ typedef struct XiveEQ { #define EQ_W7_F1_LOG_SERVER_ID PPC_BITMASK32(1, 31) } XiveEQ; =20 +/* VP */ +typedef struct XiveVP { + uint32_t w0; +#define VP_W0_VALID PPC_BIT32(0) + uint32_t w1; + uint32_t w2; + uint32_t w3; + uint32_t w4; + uint32_t w5; + uint32_t w6; + uint32_t w7; + uint32_t w8; +#define VP_W8_GRP_VALID PPC_BIT32(0) + uint32_t w9; + uint32_t wa; + uint32_t wb; + uint32_t wc; + uint32_t wd; + uint32_t we; + uint32_t wf; +} XiveVP; + #endif /* _PPC_XIVE_REGS_H */ diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 77e4f0e1f3f5..6ea9441852e3 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -373,6 +373,37 @@ void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor = *mon) } } =20 +/* The HW CAM (23bits) is hardwired to : + * + * 0x000||0b1||4Bit chip number||7Bit Thread number. + * + * and when the block grouping extension is enabled : + * + * 4Bit chip number||0x001||7Bit Thread number. + */ +static uint32_t tctx_hw_cam_line(bool block_group, uint8_t chip_id, uint8_= t tid) +{ + if (block_group) { + return 1 << 11 | (chip_id & 0xf) << 7 | (tid & 0x7f); + } else { + return (chip_id & 0xf) << 11 | 1 << 7 | (tid & 0x7f); + } +} + +static uint32_t tctx_cam_line(uint8_t vp_blk, uint32_t vp_idx) +{ + return (vp_blk << 19) | vp_idx; +} + +static uint32_t xive_tctx_hw_cam(XiveTCTX *tctx, bool block_group) +{ + PowerPCCPU *cpu =3D POWERPC_CPU(tctx->cs); + CPUPPCState *env =3D &cpu->env; + uint32_t pir =3D env->spr_cb[SPR_PIR].default_value; + + return tctx_hw_cam_line(block_group, (pir >> 8) & 0xf, pir & 0x7f); +} + static void xive_tctx_reset(void *dev) { XiveTCTX *tctx =3D XIVE_TCTX(dev); @@ -976,6 +1007,194 @@ int xive_router_set_eq(XiveRouter *xrtr, uint8_t eq_= blk, uint32_t eq_idx, return xrc->set_eq(xrtr, eq_blk, eq_idx, eq); } =20 +int xive_router_get_vp(XiveRouter *xrtr, uint8_t vp_blk, uint32_t vp_idx, + XiveVP *vp) +{ + XiveRouterClass *xrc =3D XIVE_ROUTER_GET_CLASS(xrtr); + + return xrc->get_vp(xrtr, vp_blk, vp_idx, vp); +} + +int xive_router_set_vp(XiveRouter *xrtr, uint8_t vp_blk, uint32_t vp_idx, + XiveVP *vp) +{ + XiveRouterClass *xrc =3D XIVE_ROUTER_GET_CLASS(xrtr); + + return xrc->set_vp(xrtr, vp_blk, vp_idx, vp); +} + +static bool xive_tctx_ring_match(XiveTCTX *tctx, uint8_t ring, + uint8_t vp_blk, uint32_t vp_idx, + bool cam_ignore, uint32_t logic_serv) +{ + uint8_t *regs =3D &tctx->regs[ring]; + uint32_t w2 =3D be32_to_cpu(*((uint32_t *) ®s[TM_WORD2])); + uint32_t cam =3D tctx_cam_line(vp_blk, vp_idx); + bool block_group =3D false; /* TODO (PowerNV) */ + + /* TODO (PowerNV): ignore low order bits of vp id */ + + switch (ring) { + case TM_QW3_HV_PHYS: + return (w2 & TM_QW3W2_VT) && xive_tctx_hw_cam(tctx, block_group) = =3D=3D + tctx_hw_cam_line(block_group, vp_blk, vp_idx); + + case TM_QW2_HV_POOL: + return (w2 & TM_QW2W2_VP) && (cam =3D=3D GETFIELD(TM_QW2W2_POOL_CA= M, w2)); + + case TM_QW1_OS: + return (w2 & TM_QW1W2_VO) && (cam =3D=3D GETFIELD(TM_QW1W2_OS_CAM,= w2)); + + case TM_QW0_USER: + return ((w2 & TM_QW1W2_VO) && (cam =3D=3D GETFIELD(TM_QW1W2_OS_CAM= , w2)) && + (w2 & TM_QW0W2_VU) && + (logic_serv =3D=3D GETFIELD(TM_QW0W2_LOGIC_SERV, w2))); + + default: + g_assert_not_reached(); + } +} + +static int xive_presenter_tctx_match(XiveTCTX *tctx, uint8_t format, + uint8_t vp_blk, uint32_t vp_idx, + bool cam_ignore, uint32_t logic_serv) +{ + if (format =3D=3D 0) { + /* F=3D0 & i=3D1: Logical server notification */ + if (cam_ignore =3D=3D true) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no support for LS " + "notification VP %x/%x\n", vp_blk, vp_idx); + return -1; + } + + /* F=3D0 & i=3D0: Specific VP notification */ + if (xive_tctx_ring_match(tctx, TM_QW3_HV_PHYS, + vp_blk, vp_idx, false, 0)) { + return TM_QW3_HV_PHYS; + } + if (xive_tctx_ring_match(tctx, TM_QW2_HV_POOL, + vp_blk, vp_idx, false, 0)) { + return TM_QW2_HV_POOL; + } + if (xive_tctx_ring_match(tctx, TM_QW1_OS, + vp_blk, vp_idx, false, 0)) { + return TM_QW1_OS; + } + } else { + /* F=3D1 : User level Event-Based Branch (EBB) notification */ + if (xive_tctx_ring_match(tctx, TM_QW0_USER, + vp_blk, vp_idx, false, logic_serv)) { + return TM_QW0_USER; + } + } + return -1; +} + +typedef struct XiveTCTXMatch { + XiveTCTX *tctx; + uint8_t ring; +} XiveTCTXMatch; + +static bool xive_presenter_match(XiveRouter *xrtr, uint8_t format, + uint8_t vp_blk, uint32_t vp_idx, + bool cam_ignore, uint8_t priority, + uint32_t logic_serv, XiveTCTXMatch *match) +{ + CPUState *cs; + + /* TODO (PowerNV): handle chip_id overwrite of block field for + * hardwired CAM compares */ + + CPU_FOREACH(cs) { + PowerPCCPU *cpu =3D POWERPC_CPU(cs); + XiveTCTX *tctx =3D XIVE_TCTX(cpu->intc); + int ring; + + /* + * HW checks that the CPU is enabled in the Physical Thread + * Enable Register (PTER). + */ + + /* + * Check the thread context CAM lines and record matches. We + * will handle CPU exception delivery later + */ + ring =3D xive_presenter_tctx_match(tctx, format, vp_blk, vp_idx, + cam_ignore, logic_serv); + /* + * Save the context and follow on to catch duplicates, that we + * don't support yet. + */ + if (ring !=3D -1) { + if (match->tctx) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: already found a thre= ad " + "context VP %x/%x\n", vp_blk, vp_idx); + return false; + } + + match->ring =3D ring; + match->tctx =3D tctx; + } + } + + if (!match->tctx) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: VP %x/%x is not dispatched\n= ", + vp_blk, vp_idx); + return false; + } + + return true; +} + +/* + * This is our simple Xive Presenter Engine model. It is merged in the + * Router as it does not require an extra object. + * + * It receives notification requests sent by the IVRE to find one VP + * (or more) dispatched on the processor threads. In case of single VP + * notification, the process is abreviated and the thread is signaled + * if a match is found. In case of a logical server notification (bits + * ignored at the end of the VP identifier), the IVPE and IVRE select + * a winning thread using different filters. This involves 2 or 3 + * exchanges on the PowerBus that the model does not support. + * + * The parameters represent what is sent on the PowerBus + */ +static void xive_presenter_notify(XiveRouter *xrtr, uint8_t format, + uint8_t vp_blk, uint32_t vp_idx, + bool cam_ignore, uint8_t priority, + uint32_t logic_serv) +{ + XiveVP vp; + XiveTCTXMatch match =3D { 0 }; + bool found; + + /* VPD cache lookup */ + if (xive_router_get_vp(xrtr, vp_blk, vp_idx, &vp)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no VP %x/%x\n", + vp_blk, vp_idx); + return; + } + + if (!(vp.w0 & VP_W0_VALID)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: VP %x/%x is invalid\n", + vp_blk, vp_idx); + return; + } + + found =3D xive_presenter_match(xrtr, format, vp_blk, vp_idx, cam_ignor= e, + priority, logic_serv, &match); + if (found) { + return; + } + + /* If no VP dispatched on a HW thread : + * - update the VP if backlog is activated + * - escalate (ESe PQ bits and IVE in w4-5) if escalation is + * activated + */ +} + /* * An EQ trigger can come from an event trigger (IPI or HW) or from * another chip. We don't model the PowerBus but the EQ trigger @@ -1043,6 +1262,14 @@ static void xive_router_eq_notify(XiveRouter *xrtr, = uint8_t eq_blk, /* * Follows IVPE notification */ + xive_presenter_notify(xrtr, format, + GETFIELD(EQ_W6_NVT_BLOCK, eq.w6), + GETFIELD(EQ_W6_NVT_INDEX, eq.w6), + GETFIELD(EQ_W7_F0_IGNORE, eq.w7), + priority, + GETFIELD(EQ_W7_F1_LOG_SERVER_ID, eq.w7)); + + /* TODO: Auto EOI. */ } =20 static void xive_router_notify(XiveFabric *xf, uint32_t lisn) --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 152838734741418.417050864458815; Thu, 7 Jun 2018 09:02:27 -0700 (PDT) Received: from localhost ([::1]:58831 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxMo-0003WA-Jt for importer@patchew.org; Thu, 07 Jun 2018 12:02:26 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38964) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxCC-0002KQ-Gw for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxC7-0003uH-P3 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:28 -0400 Received: from 8.mo173.mail-out.ovh.net ([46.105.46.122]:47146) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxC7-0003tP-Ec for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:23 -0400 Received: from player169.ha.ovh.net (unknown [10.109.108.82]) by mo173.mail-out.ovh.net (Postfix) with ESMTP id C54B1C2AD2 for ; Thu, 7 Jun 2018 17:51:21 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 6414E58009A; Thu, 7 Jun 2018 17:51:16 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:47 +0200 Message-Id: <20180607155003.1580-13-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6086896375051619155 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.46.122 Subject: [Qemu-devel] [PATCH v4 12/28] ppc/xive: notify the CPU when the interrupt priority is more privileged 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" After the event was pushed in the Xive EQ, the IVPE raises the bit corresponding to the priority of the pending interrupt in the register IBP (Interrupt Pending Buffer) to indicate there is an event pending in one of the 8 priority queues. The Pending Interrupt Priority Register (PIPR) is also updated using the IPB. This register represent the priority of the most favored pending notification. The PIPR is then compared to the the Current Processor Priority Register (CPPR). If it is more favored (numerically less than), the CPU interrupt line is raised and the EO bit of the Notification Source Register (NSR) is updated to notify the presence of an exception for the O/S. The check needs to be done whenever the PIPR or the CPPR are changed. The O/S acknowledges the interrupt with a special load in the Thread Interrupt Management Area. If the EO bit of the NSR is set, the CPPR takes the value of PIPR. The bit number in the IBP corresponding to the priority of the pending interrupt is reseted and so is the EO bit of the NSR. Signed-off-by: C=C3=A9dric Le Goater --- hw/intc/xive.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 6ea9441852e3..f249ffc8943e 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -21,9 +21,73 @@ * XIVE Thread Interrupt Management context */ =20 +/* Convert a priority number to an Interrupt Pending Buffer (IPB) + * register, which indicates a pending interrupt at the priority + * corresponding to the bit number + */ +static uint8_t priority_to_ipb(uint8_t priority) +{ + return priority > XIVE_PRIORITY_MAX ? + 0 : 1 << (XIVE_PRIORITY_MAX - priority); +} + +/* Convert an Interrupt Pending Buffer (IPB) register to a Pending + * Interrupt Priority Register (PIPR), which contains the priority of + * the most favored pending notification. + */ +static uint8_t ipb_to_pipr(uint8_t ibp) +{ + return ibp ? clz32((uint32_t)ibp << 24) : 0xff; +} + +static void ipb_update(uint8_t *regs, uint8_t priority) +{ + regs[TM_IPB] |=3D priority_to_ipb(priority); + regs[TM_PIPR] =3D ipb_to_pipr(regs[TM_IPB]); +} + +static uint8_t exception_mask(uint8_t ring) +{ + switch (ring) { + case TM_QW1_OS: + return TM_QW1_NSR_EO; + default: + g_assert_not_reached(); + } +} + static uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t ring) { - return 0; + uint8_t *regs =3D &tctx->regs[ring]; + uint8_t nsr =3D regs[TM_NSR]; + uint8_t mask =3D exception_mask(ring); + + qemu_irq_lower(tctx->output); + + if (regs[TM_NSR] & mask) { + uint8_t cppr =3D regs[TM_PIPR]; + + regs[TM_CPPR] =3D cppr; + + /* Reset the pending buffer bit */ + regs[TM_IPB] &=3D ~priority_to_ipb(cppr); + regs[TM_PIPR] =3D ipb_to_pipr(regs[TM_IPB]); + + /* Drop Exception bit */ + regs[TM_NSR] &=3D ~mask; + } + + return (nsr << 8) | regs[TM_CPPR]; +} + +static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring) +{ + uint8_t *regs =3D &tctx->regs[ring]; + + if (regs[TM_PIPR] < regs[TM_CPPR]) { + regs[TM_NSR] |=3D exception_mask(ring); + qemu_irq_raise(tctx->output); + } } =20 static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr) @@ -33,6 +97,9 @@ static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ri= ng, uint8_t cppr) } =20 tctx->regs[ring + TM_CPPR] =3D cppr; + + /* CPPR has changed, check if we need to raise a pending exception */ + xive_tctx_notify(tctx, ring); } =20 /* @@ -199,6 +266,17 @@ static void xive_tm_set_os_cppr(XiveTCTX *tctx, hwaddr= offset, } =20 /* + * Adjust the IPB to allow a CPU to process event queues of other + * priorities during one physical interrupt cycle. + */ +static void xive_tm_set_os_pending(XiveTCTX *tctx, hwaddr offset, + uint64_t value, unsigned size) +{ + ipb_update(&tctx->regs[TM_QW1_OS], value & 0xff); + xive_tctx_notify(tctx, TM_QW1_OS); +} + +/* * Define a mapping of "special" operations depending on the TIMA page * offset and the size of the operation. */ @@ -220,6 +298,7 @@ static const XiveTmOp xive_tm_operations[] =3D { =20 /* MMIOs above 2K : special operations with side effects */ { XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL, xive_tm_ack_os_reg = }, + { XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, N= ULL }, }; =20 static const XiveTmOp *xive_tm_find_op(hwaddr offset, unsigned size, bool = write) @@ -414,6 +493,13 @@ static void xive_tctx_reset(void *dev) tctx->regs[TM_QW1_OS + TM_LSMFB] =3D 0xFF; tctx->regs[TM_QW1_OS + TM_ACK_CNT] =3D 0xFF; tctx->regs[TM_QW1_OS + TM_AGE] =3D 0xFF; + + /* + * Initialize PIPR to 0xFF to avoid phantom interrupts when the + * CPPR is first set. + */ + tctx->regs[TM_QW1_OS + TM_PIPR] =3D + ipb_to_pipr(tctx->regs[TM_QW1_OS + TM_IPB]); } =20 static void xive_tctx_realize(DeviceState *dev, Error **errp) @@ -1185,9 +1271,15 @@ static void xive_presenter_notify(XiveRouter *xrtr, = uint8_t format, found =3D xive_presenter_match(xrtr, format, vp_blk, vp_idx, cam_ignor= e, priority, logic_serv, &match); if (found) { + ipb_update(&match.tctx->regs[match.ring], priority); + xive_tctx_notify(match.tctx, match.ring); return; } =20 + /* Record the IPB in the associated VP */ + ipb_update((uint8_t *) &vp.w4, priority); + xive_router_set_vp(xrtr, vp_blk, vp_idx, &vp); + /* If no VP dispatched on a HW thread : * - update the VP if backlog is activated * - escalate (ESe PQ bits and IVE in w4-5) if escalation is --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528387367605250.1203536533534; Thu, 7 Jun 2018 09:02:47 -0700 (PDT) Received: from localhost ([::1]:58832 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxN8-0003ms-OK for importer@patchew.org; Thu, 07 Jun 2018 12:02:46 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39019) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxCJ-0002R9-Ob for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:37 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxCE-0003yC-U1 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:35 -0400 Received: from 4.mo2.mail-out.ovh.net ([87.98.172.75]:33552) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxCE-0003xR-KF for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:30 -0400 Received: from player169.ha.ovh.net (unknown [10.109.108.98]) by mo2.mail-out.ovh.net (Postfix) with ESMTP id 710EB1375CF for ; Thu, 7 Jun 2018 17:51:27 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id D27E058009A; Thu, 7 Jun 2018 17:51:21 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:48 +0200 Message-Id: <20180607155003.1580-14-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6088585224899693395 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 87.98.172.75 Subject: [Qemu-devel] [PATCH v4 13/28] spapr/xive: introduce a XIVE interrupt controller 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" sPAPRXive models the XIVE interrupt controller of the sPAPR machine. It inherits from the XiveRouter and provisions storage for the routing tables : - Interrupt Virtualization Entries (IVE) - Event Queue Descriptor (EQD) sPAPRXive incorporates an internal XiveSource for the IPIs and the virtual device interrupts of the guest. This model is consistent with XIVE architecture which also incorporates an internal IVSE for IPIs and accelerator interrupts in the IVRE sub-engine. sPAPRXive exports two memory regions, one for the ESB trigger and management pages used to control the sources and one for the TIMA pages. They are mapped by default at the addresses found on chip 0 of a real system. This is consistent with the XIVE architecture which defines a Virtualization Controller BAR for the internal IVSE ESB pages and a Thread Managment BAR for the TIMA. Signed-off-by: C=C3=A9dric Le Goater --- default-configs/ppc64-softmmu.mak | 1 + include/hw/ppc/spapr_xive.h | 46 ++++++ hw/intc/spapr_xive.c | 308 ++++++++++++++++++++++++++++++++++= ++++ hw/intc/Makefile.objs | 1 + 4 files changed, 356 insertions(+) create mode 100644 include/hw/ppc/spapr_xive.h create mode 100644 hw/intc/spapr_xive.c diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-soft= mmu.mak index c6d13e757977..f8d34722931d 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -17,4 +17,5 @@ CONFIG_XICS=3D$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=3D$(CONFIG_PSERIES) CONFIG_XICS_KVM=3D$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) CONFIG_XIVE=3D$(CONFIG_PSERIES) +CONFIG_XIVE_SPAPR=3D$(CONFIG_PSERIES) CONFIG_MEM_HOTPLUG=3Dy diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h new file mode 100644 index 000000000000..32733270f734 --- /dev/null +++ b/include/hw/ppc/spapr_xive.h @@ -0,0 +1,46 @@ +/* + * QEMU PowerPC sPAPR XIVE interrupt controller model + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef PPC_SPAPR_XIVE_H +#define PPC_SPAPR_XIVE_H + +#include "hw/sysbus.h" +#include "hw/ppc/xive.h" + +#define TYPE_SPAPR_XIVE "spapr-xive" +#define SPAPR_XIVE(obj) OBJECT_CHECK(sPAPRXive, (obj), TYPE_SPAPR_XIVE) + +typedef struct sPAPRXive { + XiveRouter parent; + + /* Internal interrupt source for IPIs and virtual devices */ + XiveSource source; + hwaddr vc_base; + + /* EQ ESB MMIOs */ + XiveEQSource eq_source; + hwaddr eq_base; + + /* Routing table */ + XiveIVE *ivt; + uint32_t nr_irqs; + XiveEQ *eqdt; + uint32_t nr_eqs; + + /* TIMA mapping address */ + hwaddr tm_base; + MemoryRegion tm_mmio; +} sPAPRXive; + +bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn, bool lsi); +bool spapr_xive_irq_disable(sPAPRXive *xive, uint32_t lisn); +void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon); +qemu_irq spapr_xive_qirq(sPAPRXive *xive, uint32_t lisn); + +#endif /* PPC_SPAPR_XIVE_H */ diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c new file mode 100644 index 000000000000..e006c199ed11 --- /dev/null +++ b/hw/intc/spapr_xive.c @@ -0,0 +1,308 @@ +/* + * QEMU PowerPC sPAPR XIVE interrupt controller model + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "target/ppc/cpu.h" +#include "sysemu/cpus.h" +#include "monitor/monitor.h" +#include "hw/ppc/spapr.h" +#include "hw/ppc/spapr_xive.h" +#include "hw/ppc/xive.h" +#include "hw/ppc/xive_regs.h" + +/* + * XIVE Virtualization Controller BAR and Thread Managment BAR that we + * use for the ESB pages and the TIMA pages + */ +#define SPAPR_XIVE_VC_BASE 0x0006010000000000ull +#define SPAPR_XIVE_TM_BASE 0x0006030203180000ull + +void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon) +{ + int i; + + xive_source_pic_print_info(&xive->source, 0, mon); + + monitor_printf(mon, "IVE Table\n"); + for (i =3D 0; i < xive->nr_irqs; i++) { + xive_router_print_ive(XIVE_ROUTER(xive), i, &xive->ivt[i], mon); + } +} + +static void spapr_xive_reset(DeviceState *dev) +{ + sPAPRXive *xive =3D SPAPR_XIVE(dev); + XiveSource *xsrc =3D &xive->source; + int i; + + /* Xive Source reset is done through SysBus, it should put all + * IRQs to OFF (!P|Q) */ + + /* Mask all valid IVEs in the IRQ number space. */ + for (i =3D 0; i < xive->nr_irqs; i++) { + XiveIVE *ive =3D &xive->ivt[i]; + if (ive->w & IVE_VALID) { + ive->w |=3D IVE_MASKED; + } + } + + for (i =3D 0; i < xive->nr_eqs; i++) { + xive_eq_reset(&xive->eqdt[i]); + } + + /* Map the EQ ESB pages after the source ESBs */ + xive->eq_base =3D xive->vc_base + (1ull << xsrc->esb_shift) * xsrc->nr= _irqs; + + /* Map ESB pages and TIMA pages */ + sysbus_mmio_map(SYS_BUS_DEVICE(&xive->source), 0, xive->vc_base); + sysbus_mmio_map(SYS_BUS_DEVICE(&xive->eq_source), 0, xive->eq_base); + sysbus_mmio_map(SYS_BUS_DEVICE(xive), 0, xive->tm_base); +} + +static void spapr_xive_instance_init(Object *obj) +{ + sPAPRXive *xive =3D SPAPR_XIVE(obj); + + object_initialize(&xive->source, sizeof(xive->source), TYPE_XIVE_SOURC= E); + object_property_add_child(obj, "source", OBJECT(&xive->source), NULL); + + object_initialize(&xive->eq_source, sizeof(xive->eq_source), + TYPE_XIVE_EQ_SOURCE); + object_property_add_child(obj, "eq_source", OBJECT(&xive->eq_source), = NULL); +} + +static void spapr_xive_realize(DeviceState *dev, Error **errp) +{ + sPAPRXive *xive =3D SPAPR_XIVE(dev); + XiveSource *xsrc =3D &xive->source; + XiveEQSource *eq_xsrc =3D &xive->eq_source; + Error *local_err =3D NULL; + + if (!xive->nr_irqs) { + error_setg(errp, "Number of interrupt needs to be greater 0"); + return; + } + + if (!xive->nr_eqs) { + error_setg(errp, "Number of interrupt needs to be greater 0"); + return; + } + + /* + * Initialize the internal sources, for IPIs and virtual devices. + */ + object_property_set_int(OBJECT(xsrc), xive->nr_irqs, "nr-irqs", + &error_fatal); + object_property_add_const_link(OBJECT(xsrc), "xive", OBJECT(xive), + &error_fatal); + object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + qdev_set_parent_bus(DEVICE(xsrc), sysbus_get_default()); + + /* + * Initialize the EQ ESB source + */ + object_property_set_int(OBJECT(eq_xsrc), xive->nr_irqs, "nr-eqs", + &error_fatal); + object_property_add_const_link(OBJECT(eq_xsrc), "xive", OBJECT(xive), + &error_fatal); + object_property_set_bool(OBJECT(eq_xsrc), true, "realized", &local_err= ); + if (local_err) { + error_propagate(errp, local_err); + return; + } + qdev_set_parent_bus(DEVICE(eq_xsrc), sysbus_get_default()); + + /* Allocate the routing tables */ + xive->ivt =3D g_new0(XiveIVE, xive->nr_irqs); + xive->eqdt =3D g_new0(XiveEQ, xive->nr_eqs); + + /* TIMA */ + memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &xive_tm_ops, xive, + "xive.tima", 4ull << TM_SHIFT); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &xive->tm_mmio); +} + +static int spapr_xive_get_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *iv= e) +{ + sPAPRXive *xive =3D SPAPR_XIVE(xrtr); + + if (lisn >=3D xive->nr_irqs) { + return -1; + } + + *ive =3D xive->ivt[lisn]; + return 0; +} + +static int spapr_xive_set_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *iv= e) +{ + sPAPRXive *xive =3D SPAPR_XIVE(xrtr); + + if (lisn >=3D xive->nr_irqs) { + return -1; + } + + xive->ivt[lisn] =3D *ive; + return 0; +} + +static int spapr_xive_get_eq(XiveRouter *xrtr, + uint8_t eq_blk, uint32_t eq_idx, XiveEQ *eq) +{ + sPAPRXive *xive =3D SPAPR_XIVE(xrtr); + + if (eq_idx >=3D xive->nr_eqs) { + return -1; + } + + memcpy(eq, &xive->eqdt[eq_idx], sizeof(XiveEQ)); + return 0; +} + +static int spapr_xive_set_eq(XiveRouter *xrtr, + uint8_t eq_blk, uint32_t eq_idx, XiveEQ *eq) +{ + sPAPRXive *xive =3D SPAPR_XIVE(xrtr); + + if (eq_idx >=3D xive->nr_eqs) { + return -1; + } + + memcpy(&xive->eqdt[eq_idx], eq, sizeof(XiveEQ)); + return 0; +} + +static const VMStateDescription vmstate_spapr_xive_eq =3D { + .name =3D TYPE_SPAPR_XIVE "/eq", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField []) { + VMSTATE_UINT32(w0, XiveEQ), + VMSTATE_UINT32(w1, XiveEQ), + VMSTATE_UINT32(w2, XiveEQ), + VMSTATE_UINT32(w3, XiveEQ), + VMSTATE_UINT32(w4, XiveEQ), + VMSTATE_UINT32(w5, XiveEQ), + VMSTATE_UINT32(w6, XiveEQ), + VMSTATE_UINT32(w7, XiveEQ), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_spapr_xive_ive =3D { + .name =3D TYPE_SPAPR_XIVE "/ive", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField []) { + VMSTATE_UINT64(w, XiveIVE), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_spapr_xive =3D { + .name =3D TYPE_SPAPR_XIVE, + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_UINT32_EQUAL(nr_irqs, sPAPRXive, NULL), + VMSTATE_STRUCT_VARRAY_POINTER_UINT32(ivt, sPAPRXive, nr_irqs, + vmstate_spapr_xive_ive, XiveIVE), + VMSTATE_STRUCT_VARRAY_POINTER_UINT32(eqdt, sPAPRXive, nr_eqs, + vmstate_spapr_xive_eq, XiveEQ= ), + VMSTATE_END_OF_LIST() + }, +}; + +static Property spapr_xive_properties[] =3D { + DEFINE_PROP_UINT32("nr-irqs", sPAPRXive, nr_irqs, 0), + DEFINE_PROP_UINT32("nr-eqs", sPAPRXive, nr_eqs, 0), + DEFINE_PROP_UINT64("vc-base", sPAPRXive, vc_base, SPAPR_XIVE_VC_BASE), + DEFINE_PROP_UINT64("tm-base", sPAPRXive, tm_base, SPAPR_XIVE_TM_BASE), + DEFINE_PROP_END_OF_LIST(), +}; + +static void spapr_xive_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + XiveRouterClass *xrc =3D XIVE_ROUTER_CLASS(klass); + + dc->desc =3D "sPAPR XIVE Interrupt Controller"; + dc->props =3D spapr_xive_properties; + dc->realize =3D spapr_xive_realize; + dc->reset =3D spapr_xive_reset; + dc->vmsd =3D &vmstate_spapr_xive; + + xrc->get_ive =3D spapr_xive_get_ive; + xrc->set_ive =3D spapr_xive_set_ive; + xrc->get_eq =3D spapr_xive_get_eq; + xrc->set_eq =3D spapr_xive_set_eq; +} + +static const TypeInfo spapr_xive_info =3D { + .name =3D TYPE_SPAPR_XIVE, + .parent =3D TYPE_XIVE_ROUTER, + .instance_init =3D spapr_xive_instance_init, + .instance_size =3D sizeof(sPAPRXive), + .class_init =3D spapr_xive_class_init, +}; + +static void spapr_xive_register_types(void) +{ + type_register_static(&spapr_xive_info); +} + +type_init(spapr_xive_register_types) + +bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn, bool lsi) +{ + XiveSource *xsrc =3D &xive->source; + + if (lisn >=3D xive->nr_irqs) { + return false; + } + + xive->ivt[lisn].w |=3D IVE_VALID; + xive_source_irq_set(xsrc, lisn, lsi); + return true; +} + +bool spapr_xive_irq_disable(sPAPRXive *xive, uint32_t lisn) +{ + XiveSource *xsrc =3D &xive->source; + + if (lisn >=3D xive->nr_irqs) { + return false; + } + + xive->ivt[lisn].w &=3D ~IVE_VALID; + xive_source_irq_set(xsrc, lisn, false); + return true; +} + +qemu_irq spapr_xive_qirq(sPAPRXive *xive, uint32_t lisn) +{ + XiveSource *xsrc =3D &xive->source; + + if (lisn >=3D xive->nr_irqs) { + return NULL; + } + + if (!(xive->ivt[lisn].w & IVE_VALID)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid LISN %x\n", lisn); + return NULL; + } + + return xive_source_qirq(xsrc, lisn); +} diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 72a46ed91c31..301a8e972d91 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -38,6 +38,7 @@ obj-$(CONFIG_XICS) +=3D xics.o obj-$(CONFIG_XICS_SPAPR) +=3D xics_spapr.o obj-$(CONFIG_XICS_KVM) +=3D xics_kvm.o obj-$(CONFIG_XIVE) +=3D xive.o +obj-$(CONFIG_XIVE_SPAPR) +=3D spapr_xive.o obj-$(CONFIG_POWERNV) +=3D xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) +=3D allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) +=3D s390_flic.o --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528387616485107.05096074871085; Thu, 7 Jun 2018 09:06:56 -0700 (PDT) Received: from localhost ([::1]:58863 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxR6-0000mV-4D for importer@patchew.org; Thu, 07 Jun 2018 12:06:52 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39038) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxCN-0002TK-BH for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxCI-00041Y-Kx for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:39 -0400 Received: from 14.mo3.mail-out.ovh.net ([188.165.43.98]:60262) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxCI-00040H-AZ for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:34 -0400 Received: from player169.ha.ovh.net (unknown [10.109.108.58]) by mo3.mail-out.ovh.net (Postfix) with ESMTP id B8BAC1BC4EA for ; Thu, 7 Jun 2018 17:51:32 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 503015800AC; Thu, 7 Jun 2018 17:51:27 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:49 +0200 Message-Id: <20180607155003.1580-15-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6089992596125813587 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 188.165.43.98 Subject: [Qemu-devel] [PATCH v4 14/28] spapr/xive: use the VCPU id as a VP identifier in the OS CAM. 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" For the IVPE to find a matching VP among the VPs dispatched on the physical processor threads, the model needs to update the OS CAM line of the XIVE thread interrupt context with the VP identifier. The model uses the VCPU id as the VP identifier for the sPAPR and provide a set of helpers to do the conversion between identifiers. EQ ids are also derived from the VCPU id. sPAPRXive does not provision storage for a VPD table but the XiveRouter handlers provide some extra checks to the routing algorithm. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/spapr_xive.h | 15 +++++++++ hw/intc/spapr_xive.c | 80 +++++++++++++++++++++++++++++++++++++++++= ++++ hw/intc/xive.c | 12 +++++++ 3 files changed, 107 insertions(+) diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index 32733270f734..be1163a8f272 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -43,4 +43,19 @@ bool spapr_xive_irq_disable(sPAPRXive *xive, uint32_t li= sn); void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon); qemu_irq spapr_xive_qirq(sPAPRXive *xive, uint32_t lisn); =20 +/* + * sPAPR VP and EQ indexing helpers + */ +static inline uint32_t spapr_xive_vp_to_target(sPAPRXive *xive, uint8_t vp= _blk, + uint32_t vp_idx) +{ + return vp_idx; +} +int spapr_xive_target_to_vp(XiveRouter *xrtr, uint32_t target, + uint8_t *out_vp_blk, uint32_t *out_vp_idx); +int spapr_xive_target_to_eq(XiveRouter *xrtr, uint32_t target, uint8_t pri= o, + uint8_t *out_eq_blk, uint32_t *out_eq_idx); +int spapr_xive_cpu_to_eq(XiveRouter *xrtr, PowerPCCPU *cpu, uint8_t prio, + uint8_t *out_eq_blk, uint32_t *out_eq_idx); + #endif /* PPC_SPAPR_XIVE_H */ diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index e006c199ed11..222c1266a547 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -184,6 +184,84 @@ static int spapr_xive_set_eq(XiveRouter *xrtr, return 0; } =20 +static int spapr_xive_get_vp(XiveRouter *xrtr, + uint8_t vp_blk, uint32_t vp_idx, XiveVP *vp) +{ + sPAPRXive *xive =3D SPAPR_XIVE(xrtr); + uint32_t vcpu_id =3D spapr_xive_vp_to_target(xive, vp_blk, vp_idx); + PowerPCCPU *cpu =3D spapr_find_cpu(vcpu_id); + + if (!cpu) { + return -1; + } + + /* + * sPAPR does not maintain a VPD table. Return that the VP is + * valid if we have found a matching CPU + */ + vp->w0 =3D VP_W0_VALID; + return 0; +} + +static int spapr_xive_set_vp(XiveRouter *xrtr, + uint8_t vp_blk, uint32_t vp_idx, XiveVP *vp) +{ + /* no VPD table */ + return 0; +} + +/* + * sPAPR VP indexing uses a simple mapping of the CPU vcpu_id + */ +int spapr_xive_target_to_vp(XiveRouter *xrtr, uint32_t target, + uint8_t *out_vp_blk, uint32_t *out_vp_idx) +{ + PowerPCCPU *cpu =3D spapr_find_cpu(target); + + if (!cpu) { + return -1; + } + + if (out_vp_blk) { + *out_vp_blk =3D xrtr->chip_id; + } + + if (out_vp_blk) { + *out_vp_idx =3D cpu->vcpu_id; + } + return 0; +} + +/* + * sPAPR EQ indexing uses a simple mapping of the CPU vcpu_id, 8 + * priorities per CPU + */ +int spapr_xive_cpu_to_eq(XiveRouter *xrtr, PowerPCCPU *cpu, uint8_t prio, + uint8_t *out_eq_blk, uint32_t *out_eq_idx) +{ + if (!cpu) { + return -1; + } + + if (out_eq_blk) { + *out_eq_blk =3D xrtr->chip_id; + } + + if (out_eq_idx) { + *out_eq_idx =3D (cpu->vcpu_id << 3) + prio; + } + return 0; +} + +int spapr_xive_target_to_eq(XiveRouter *xrtr, uint32_t target, uint8_t pri= o, + uint8_t *out_eq_blk, uint32_t *out_eq_idx) +{ + PowerPCCPU *cpu =3D spapr_find_cpu(target); + + return spapr_xive_cpu_to_eq(xrtr, cpu, prio, out_eq_blk, out_eq_idx); +} + + static const VMStateDescription vmstate_spapr_xive_eq =3D { .name =3D TYPE_SPAPR_XIVE "/eq", .version_id =3D 1, @@ -248,6 +326,8 @@ static void spapr_xive_class_init(ObjectClass *klass, v= oid *data) xrc->set_ive =3D spapr_xive_set_ive; xrc->get_eq =3D spapr_xive_get_eq; xrc->set_eq =3D spapr_xive_set_eq; + xrc->get_vp =3D spapr_xive_get_vp; + xrc->set_vp =3D spapr_xive_set_vp; } =20 static const TypeInfo spapr_xive_info =3D { diff --git a/hw/intc/xive.c b/hw/intc/xive.c index f249ffc8943e..671ea1c6c36b 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -486,6 +486,8 @@ static uint32_t xive_tctx_hw_cam(XiveTCTX *tctx, bool b= lock_group) static void xive_tctx_reset(void *dev) { XiveTCTX *tctx =3D XIVE_TCTX(dev); + PowerPCCPU *cpu =3D POWERPC_CPU(tctx->cs); + CPUPPCState *env =3D &cpu->env; =20 memset(tctx->regs, 0, sizeof(tctx->regs)); =20 @@ -500,6 +502,16 @@ static void xive_tctx_reset(void *dev) */ tctx->regs[TM_QW1_OS + TM_PIPR] =3D ipb_to_pipr(tctx->regs[TM_QW1_OS + TM_IPB]); + + /* The OS CAM is pushed by the hypervisor when the VP is scheduled + * to run on a HW thread. On QEMU, when running a pseries machine, + * hardwire the VCPU id as this is our VP identifier. + */ + if (!msr_hv) { + uint32_t os_cam =3D cpu_to_be32( + TM_QW1W2_VO | tctx_cam_line(tctx->xrtr->chip_id, cpu->vcpu_id)= ); + memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &os_cam, 4); + } } =20 static void xive_tctx_realize(DeviceState *dev, Error **errp) --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528387809076931.1907339510127; Thu, 7 Jun 2018 09:10:09 -0700 (PDT) Received: from localhost ([::1]:58901 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxUC-0003Zq-HW for importer@patchew.org; Thu, 07 Jun 2018 12:10:04 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39085) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxCT-0002YW-0n for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxCO-00044F-0j for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:45 -0400 Received: from 18.mo5.mail-out.ovh.net ([178.33.45.10]:58811) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxCN-00043W-Pl for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:39 -0400 Received: from player169.ha.ovh.net (unknown [10.109.120.69]) by mo5.mail-out.ovh.net (Postfix) with ESMTP id 2FCB21BD82E for ; Thu, 7 Jun 2018 17:51:38 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id BF5685800AC; Thu, 7 Jun 2018 17:51:32 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:50 +0200 Message-Id: <20180607155003.1580-16-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6091681448222559059 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 178.33.45.10 Subject: [Qemu-devel] [PATCH v4 15/28] spapr: initialize VSMT before initializing the IRQ backend 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" We will need to use xics_max_server_number() to create the sPAPRXive object modeling the interrupt controller of the machine which is created before the CPUs. Signed-off-by: C=C3=A9dric Le Goater --- hw/ppc/spapr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index c097a7093e62..ae915a3b4803 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2423,11 +2423,6 @@ static void spapr_init_cpus(sPAPRMachineState *spapr) boot_cores_nr =3D possible_cpus->len; } =20 - /* VSMT must be set in order to be able to compute VCPU ids, ie to - * call xics_max_server_number() or spapr_vcpu_id(). - */ - spapr_set_vsmt_mode(spapr, &error_fatal); - if (smc->pre_2_10_has_unused_icps) { int i; =20 @@ -2547,6 +2542,11 @@ static void spapr_machine_init(MachineState *machine) /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */ load_limit =3D MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD; =20 + /* VSMT must be set in order to be able to compute VCPU ids, ie to + * call xics_max_server_number() or spapr_vcpu_id(). + */ + spapr_set_vsmt_mode(spapr, &error_fatal); + /* Set up Interrupt Controller before we create the VCPUs */ smc->irq->init(spapr, &error_fatal); =20 --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528387741474143.04368465142613; Thu, 7 Jun 2018 09:09:01 -0700 (PDT) Received: from localhost ([::1]:58883 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxT7-0002Mc-Bz for importer@patchew.org; Thu, 07 Jun 2018 12:08:57 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39122) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxCY-0002dD-6m for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxCT-00046o-EX for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:50 -0400 Received: from 12.mo3.mail-out.ovh.net ([188.165.41.191]:33182) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxCT-000469-3w for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:45 -0400 Received: from player169.ha.ovh.net (unknown [10.109.120.5]) by mo3.mail-out.ovh.net (Postfix) with ESMTP id A19BD1BC63F for ; Thu, 7 Jun 2018 17:51:43 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 3A30058009C; Thu, 7 Jun 2018 17:51:38 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:51 +0200 Message-Id: <20180607155003.1580-17-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6093088824020929363 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 188.165.41.191 Subject: [Qemu-devel] [PATCH v4 16/28] spapr: introdude a new machine IRQ backend for XIVE 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The XIVE IRQ backend uses the same layout as the new XICS backend but covers the full range of the IRQ number space. The IRQ numbers for the CPU IPIs are allocated at the bottom of this space, below 4K, to preserve compatibility with XICS which does not use that range. This should be enough given that the maximum number of CPUs is 1024 for the sPAPR machine under QEMU. For the record, the biggest POWER8 or POWER9 system has a maximum of 1536 HW threads (16 sockets, 192 cores, SMT8). Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/spapr.h | 2 + include/hw/ppc/spapr_irq.h | 3 +- hw/ppc/spapr.c | 3 +- hw/ppc/spapr_irq.c | 212 +++++++++++++++++++++++++++++++++++++++++= +++- 4 files changed, 215 insertions(+), 5 deletions(-) diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index bd256fbc9158..fd0e32c4b32c 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -14,6 +14,7 @@ struct sPAPRNVRAM; typedef struct sPAPREventLogEntry sPAPREventLogEntry; typedef struct sPAPREventSource sPAPREventSource; typedef struct sPAPRPendingHPT sPAPRPendingHPT; +typedef struct sPAPRXive sPAPRXive; =20 #define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL #define SPAPR_ENTRY_POINT 0x100 @@ -167,6 +168,7 @@ struct sPAPRMachineState { int32_t nr_irqs; unsigned long *irq_map; const char *icp_type; + sPAPRXive *xive; =20 bool cmd_line_caps[SPAPR_CAP_NUM]; sPAPRCapabilities def, eff, mig; diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index dd9c4038d5b6..aa41c487b705 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -32,7 +32,7 @@ typedef struct sPAPRIrq { uint32_t nr_irqs; const sPAPRPIrqRange *ranges; =20 - void (*init)(sPAPRMachineState *spapr, Error **errp); + void (*init)(sPAPRMachineState *spapr, uint32_t nr_servers, Error **er= rp); int (*assign)(sPAPRMachineState *spapr, uint32_t range, uint32_t irq, Error **errp); int (*alloc)(sPAPRMachineState *spapr, uint32_t range, uint32_t index, @@ -46,6 +46,7 @@ typedef struct sPAPRIrq { =20 extern sPAPRIrq spapr_irq_legacy; extern sPAPRIrq spapr_irq_xics; +extern sPAPRIrq spapr_irq_xive; =20 const sPAPRPIrqRange *spapr_irq_get_range(sPAPRMachineState *spapr, uint32_t offset); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index ae915a3b4803..156feff6e3fa 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -55,6 +55,7 @@ #include "hw/ppc/spapr_vio.h" #include "hw/pci-host/spapr.h" #include "hw/ppc/xics.h" +#include "hw/ppc/spapr_xive.h" #include "hw/pci/msi.h" =20 #include "hw/pci/pci.h" @@ -2548,7 +2549,7 @@ static void spapr_machine_init(MachineState *machine) spapr_set_vsmt_mode(spapr, &error_fatal); =20 /* Set up Interrupt Controller before we create the VCPUs */ - smc->irq->init(spapr, &error_fatal); + smc->irq->init(spapr, xics_max_server_number(spapr), &error_fatal); =20 /* Set up containers for ibm,client-architecture-support negotiated op= tions */ diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 6bd3dd7e01d7..b5c3e7b197b6 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -9,9 +9,11 @@ =20 #include "qemu/osdep.h" #include "qemu/log.h" +#include "qemu/error-report.h" #include "qapi/error.h" #include "hw/pci/pci.h" #include "hw/ppc/spapr.h" +#include "hw/ppc/spapr_xive.h" #include "sysemu/kvm.h" #include "trace.h" =20 @@ -48,7 +50,8 @@ error: return NULL; } =20 -static void spapr_irq_init_legacy(sPAPRMachineState *spapr, Error **errp) +static void spapr_irq_init_legacy(sPAPRMachineState *spapr, uint32_t nr_se= rvers, + Error **errp) { MachineState *machine =3D MACHINE(spapr); sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(machine); @@ -340,12 +343,13 @@ static void spapr_irq_range_free_msi(sPAPRMachineStat= e *spapr, int irq, int num) * * using the IRQ ranges and device indexes */ -static void spapr_irq_init_xics(sPAPRMachineState *spapr, Error **errp) +static void spapr_irq_init_xics(sPAPRMachineState *spapr, uint32_t nr_serv= ers, + Error **errp) { MachineState *machine =3D MACHINE(spapr); sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(machine); =20 - spapr_irq_init_legacy(spapr, errp); + spapr_irq_init_legacy(spapr, nr_servers, errp); =20 /* * Initialize the MSI IRQ allocator. The full XICS IRQ number @@ -500,6 +504,208 @@ sPAPRIrq spapr_irq_xics =3D { }; =20 /* + * XIVE IRQ backend. + */ +static sPAPRXive *spapr_xive_create(sPAPRMachineState *spapr, + const char *type_xive, int nr_irqs, + int nr_servers, Error **errp) +{ + Error *local_err =3D NULL; + Object *obj; + uint32_t nr_eqs =3D nr_servers << 3; /* 8 priority EQs per CPU */ + + obj =3D object_new(type_xive); + object_property_set_int(obj, nr_irqs, "nr-irqs", &local_err); + if (local_err) { + goto error; + } + object_property_set_int(obj, nr_eqs, "nr-eqs", &local_err); + if (local_err) { + goto error; + } + object_property_set_bool(obj, true, "realized", &local_err); + if (local_err) { + goto error; + } + + qdev_set_parent_bus(DEVICE(obj), sysbus_get_default()); + return SPAPR_XIVE(obj); +error: + error_propagate(errp, local_err); + return NULL; +} + +static void spapr_irq_init_xive(sPAPRMachineState *spapr, uint32_t nr_serv= ers, + Error **errp) +{ + MachineState *machine =3D MACHINE(spapr); + sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(machine); + int i; + + /* We don't have KVM support yet, so check for irqchip=3Don */ + if (kvm_enabled() && machine_kernel_irqchip_required(machine)) { + error_report("kernel_irqchip requested. no XIVE support"); + exit(1); + } + + spapr->xive =3D spapr_xive_create(spapr, TYPE_SPAPR_XIVE, smc->irq->nr= _irqs, + nr_servers, errp); + if (!spapr->xive) { + return; + } + + /* + * Initialize the IRQ allocator. + */ + spapr->nr_irqs =3D smc->irq->nr_irqs; + spapr->irq_map =3D bitmap_new(spapr->nr_irqs); + + /* Allocate the CPU IPIs */ + for (i =3D 0; i < nr_servers; ++i) { + spapr_irq_alloc(spapr, SPAPR_IRQ_IPI, i, errp); + } +} + +/* + * The 'irq' assignment is only used by the sPAPR VIO devices and it + * has been deprecated in QEMU 3.0. This handler should be removed + * soon. + */ +static int spapr_irq_assign_xive(sPAPRMachineState *spapr, uint32_t range, + uint32_t irq, Error **errp) +{ + assert(range =3D=3D SPAPR_IRQ_VIO); + + error_setg(errp, "IRQ assignment is not available on the XIVE " + " IRQ backend"); + return -1; +} + +static int spapr_irq_alloc_xive(sPAPRMachineState *spapr, uint32_t range, + uint32_t index, Error **errp) +{ + bool lsi =3D (range =3D=3D SPAPR_IRQ_PCI_LSI); + int irq =3D spapr_irq_range_base(spapr, range, index, errp); + + if (irq < 0) { + return irq; + } + + /* Enable the IRQ at the XIVE level */ + spapr_xive_irq_enable(spapr->xive, irq, lsi); + return irq; +} + +static int spapr_irq_alloc_block_xive(sPAPRMachineState *spapr, uint32_t r= ange, + uint32_t index, int num, bool align, + Error **errp) +{ + bool lsi =3D (range =3D=3D SPAPR_IRQ_PCI_LSI); + int irq; + int i; + + if (range =3D=3D SPAPR_IRQ_PCI_MSI) { + irq =3D spapr_irq_range_alloc_msi(spapr, range, index, num, align,= errp); + } else { + /* TODO: check range width vs. num */ + irq =3D spapr_irq_range_alloc(spapr, range, index, errp); + } + + if (irq < 0) { + return irq; + } + + /* Enable the IRQ at the XIVE level */ + for (i =3D irq; i < irq + num; ++i) { + spapr_xive_irq_enable(spapr->xive, i, lsi); + } + + return irq; +} + +static void spapr_irq_free_xive(sPAPRMachineState *spapr, int irq, int num, + Error **errp) +{ + int msi_base =3D spapr_irq_range_base(spapr, SPAPR_IRQ_PCI_MSI, 0, NUL= L); + + /* Any IRQ below MSI base should not be freed */ + if (irq < msi_base) { + error_setg(errp, "IRQs %x-%x can not be freed", irq, irq + num); + return; + } + + spapr_irq_range_free_msi(spapr, irq, num); + spapr_xive_irq_disable(spapr->xive, irq); +} + +static qemu_irq spapr_qirq_xive(sPAPRMachineState *spapr, int irq) +{ + return spapr_xive_qirq(spapr->xive, irq); +} + +static void spapr_irq_print_info_xive(sPAPRMachineState *spapr, + Monitor *mon) +{ + CPUState *cs; + + CPU_FOREACH(cs) { + PowerPCCPU *cpu =3D POWERPC_CPU(cs); + + xive_tctx_pic_print_info(XIVE_TCTX(cpu->intc), mon); + } + + spapr_xive_pic_print_info(spapr->xive, mon); +} + +/* + * XIVE IRQ number space + * + * The bottom 4K IRQ numbers are now used to allocate the CPU IPIs in XIVE. + * + * RANGES DEVICES + * + * 0x0000 - 0x0FFF 4K IPIs (max vCPUs =3D 4096) + * + * 0x1000 - 0x1000 1 EPOW + * 0x1001 - 0x1001 1 HOTPLUG + * 0x1002 - 0x10FF unused + * 0x1100 - 0x11FF 256 VIO devices (1 IRQ each) + * 0x1200 - 0x1283 32 PCI LSI devices (4 IRQs each) + * 0x1284 - 0x13FF unused + * 0x1400 - 0x17FF PCI MSI device 1 (1024 IRQs each) + * 0x1800 - 0x1BFF PCI MSI device 2 + * 0x1c00 - 0x1FFF PCI MSI device 3 + * + * 0x2000 .... not allocated. Need to increase NR_IRQS + */ +static const sPAPRPIrqRange spapr_irq_ranges_xive[] =3D { + { "IPI", SPAPR_IRQ_IPI , 1, 0x1000 }, + { "EPOW", SPAPR_IRQ_EPOW, 1, 0 }, + { "HOTPLUG", SPAPR_IRQ_HOTPLUG, 1, 0 }, + { "VIO", SPAPR_IRQ_VIO, 1, 0xFF }, + { "PCI LSI", SPAPR_IRQ_PCI_LSI, PCI_NUM_PINS, 0x1F }, + { "PCI MSI", SPAPR_IRQ_PCI_MSI, 0x400, 0x1F }, + { NULL, 0, 0, 0 }, + }; + +/* + * XIVE uses the full IRQ number space. Set it to 8K to be compatible + * with XICS. + */ + +sPAPRIrq spapr_irq_xive =3D { + .nr_irqs =3D 0x2000, + .init =3D spapr_irq_init_xive, + .ranges =3D spapr_irq_ranges_xive, + .assign =3D spapr_irq_assign_xive, + .alloc =3D spapr_irq_alloc_xive, + .alloc_block =3D spapr_irq_alloc_block_xive, + .free =3D spapr_irq_free_xive, + .qirq =3D spapr_qirq_xive, + .print_info =3D spapr_irq_print_info_xive, +}; + +/* * sPAPR IRQ frontend routines for devices */ int spapr_irq_assign(sPAPRMachineState *spapr, uint32_t range, uint32_t ir= q, --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528387906918580.0432721633699; Thu, 7 Jun 2018 09:11:46 -0700 (PDT) Received: from localhost ([::1]:58918 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxVq-0005yI-12 for importer@patchew.org; Thu, 07 Jun 2018 12:11:46 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39166) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxCe-0002hk-B1 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxCZ-00049V-9Q for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:56 -0400 Received: from 6.mo6.mail-out.ovh.net ([87.98.177.69]:43585) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxCY-00048i-LF for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:51 -0400 Received: from player169.ha.ovh.net (unknown [10.109.105.97]) by mo6.mail-out.ovh.net (Postfix) with ESMTP id 27678162444 for ; Thu, 7 Jun 2018 17:51:49 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id AB5985800A4; Thu, 7 Jun 2018 17:51:43 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:52 +0200 Message-Id: <20180607155003.1580-18-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6094777674399189843 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 87.98.177.69 Subject: [Qemu-devel] [PATCH v4 17/28] spapr: add hcalls support for the XIVE exploitation interrupt mode 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The different XIVE virtualization engines (sources and event queues) are configured with a set of Hypervisor calls : - H_INT_GET_SOURCE_INFO used to obtain the address of the MMIO page of the Event State Buffer (PQ bits) entry associated with the source. - H_INT_SET_SOURCE_CONFIG assigns a source to a "target". - H_INT_GET_SOURCE_CONFIG determines which "target" and "priority" is assigned to a source - H_INT_GET_QUEUE_INFO returns the address of the notification management page associated with the specified "target" and "priority". - H_INT_SET_QUEUE_CONFIG sets or resets the event queue for a given "target" and "priority". It is also used to set the notification configuration associated with the queue, only unconditional notification is supported for the moment. Reset is performed with a queue size of 0 and queueing is disabled in that case. - H_INT_GET_QUEUE_CONFIG returns the queue settings for a given "target" and "priority". - H_INT_RESET resets all of the guest's internal interrupt structures to their initial state, losing all configuration set via the hcalls H_INT_SET_SOURCE_CONFIG and H_INT_SET_QUEUE_CONFIG. - H_INT_SYNC issue a synchronisation on a source to make sure all notifications have reached their queue. Calls that still need to be addressed : H_INT_SET_OS_REPORTING_LINE H_INT_GET_OS_REPORTING_LINE See the code for more documentation on each hcall. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/spapr.h | 15 +- include/hw/ppc/spapr_xive.h | 5 + hw/intc/spapr_xive_hcall.c | 887 ++++++++++++++++++++++++++++++++++++++++= ++++ hw/ppc/spapr_irq.c | 2 + hw/intc/Makefile.objs | 2 +- 5 files changed, 909 insertions(+), 2 deletions(-) create mode 100644 hw/intc/spapr_xive_hcall.c diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index fd0e32c4b32c..3c7bae874f91 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -444,7 +444,20 @@ struct sPAPRMachineState { #define H_INVALIDATE_PID 0x378 #define H_REGISTER_PROC_TBL 0x37C #define H_SIGNAL_SYS_RESET 0x380 -#define MAX_HCALL_OPCODE H_SIGNAL_SYS_RESET + +#define H_INT_GET_SOURCE_INFO 0x3A8 +#define H_INT_SET_SOURCE_CONFIG 0x3AC +#define H_INT_GET_SOURCE_CONFIG 0x3B0 +#define H_INT_GET_QUEUE_INFO 0x3B4 +#define H_INT_SET_QUEUE_CONFIG 0x3B8 +#define H_INT_GET_QUEUE_CONFIG 0x3BC +#define H_INT_SET_OS_REPORTING_LINE 0x3C0 +#define H_INT_GET_OS_REPORTING_LINE 0x3C4 +#define H_INT_ESB 0x3C8 +#define H_INT_SYNC 0x3CC +#define H_INT_RESET 0x3D0 + +#define MAX_HCALL_OPCODE H_INT_RESET =20 /* The hcalls above are standardized in PAPR and implemented by pHyp * as well. diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index be1163a8f272..5dedb9e5c7c0 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -57,5 +57,10 @@ int spapr_xive_target_to_eq(XiveRouter *xrtr, uint32_t t= arget, uint8_t prio, uint8_t *out_eq_blk, uint32_t *out_eq_idx); int spapr_xive_cpu_to_eq(XiveRouter *xrtr, PowerPCCPU *cpu, uint8_t prio, uint8_t *out_eq_blk, uint32_t *out_eq_idx); +bool spapr_xive_eq_is_valid(uint8_t priority); + +typedef struct sPAPRMachineState sPAPRMachineState; + +void spapr_xive_hcall_init(sPAPRMachineState *spapr); =20 #endif /* PPC_SPAPR_XIVE_H */ diff --git a/hw/intc/spapr_xive_hcall.c b/hw/intc/spapr_xive_hcall.c new file mode 100644 index 000000000000..376ff7ba00f9 --- /dev/null +++ b/hw/intc/spapr_xive_hcall.c @@ -0,0 +1,887 @@ +/* + * QEMU PowerPC sPAPR XIVE interrupt controller model + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "cpu.h" +#include "hw/ppc/fdt.h" +#include "hw/ppc/spapr.h" +#include "hw/ppc/spapr_xive.h" +#include "hw/ppc/xive_regs.h" +#include "monitor/monitor.h" + +/* + * OPAL uses the priority 7 EQ to automatically escalate interrupts + * for all other queues (DD2.X POWER9). So only priorities [0..6] are + * available for the guest. + */ +bool spapr_xive_eq_is_valid(uint8_t priority) +{ + switch (priority) { + case 0 ... 6: + return true; + case 7: /* OPAL escalation queue */ + default: + return false; + } +} + +/* + * The H_INT_GET_SOURCE_INFO hcall() is used to obtain the logical + * real address of the MMIO page through which the Event State Buffer + * entry associated with the value of the "lisn" parameter is managed. + * + * Parameters: + * Input + * - "flags" + * Bits 0-63 reserved + * - "lisn" is per "interrupts", "interrupt-map", or + * "ibm,xive-lisn-ranges" properties, or as returned by the + * ibm,query-interrupt-source-number RTAS call, or as returned + * by the H_ALLOCATE_VAS_WINDOW hcall + * + * Output + * - R4: "flags" + * Bits 0-59: Reserved + * Bit 60: H_INT_ESB must be used for Event State Buffer + * management + * Bit 61: 1 =3D=3D LSI 0 =3D=3D MSI + * Bit 62: the full function page supports trigger + * Bit 63: Store EOI Supported + * - R5: Logical Real address of full function Event State Buffer + * management page, -1 if ESB hcall flag is set to 1. + * - R6: Logical Real Address of trigger only Event State Buffer + * management page or -1. + * - R7: Power of 2 page size for the ESB management pages returned in + * R5 and R6. + */ + +#define SPAPR_XIVE_SRC_H_INT_ESB PPC_BIT(60) /* ESB manage with H_INT_= ESB */ +#define SPAPR_XIVE_SRC_LSI PPC_BIT(61) /* Virtual LSI type */ +#define SPAPR_XIVE_SRC_TRIGGER PPC_BIT(62) /* Trigger and management + on same page */ +#define SPAPR_XIVE_SRC_STORE_EOI PPC_BIT(63) /* Store EOI support */ + +static target_ulong h_int_get_source_info(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + sPAPRXive *xive =3D spapr->xive; + XiveIVE ive; + target_ulong flags =3D args[0]; + target_ulong lisn =3D args[1]; + XiveSource *xsrc =3D &xive->source; + + if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + return H_FUNCTION; + } + + if (flags) { + return H_PARAMETER; + } + + if (xive_router_get_ive(XIVE_ROUTER(spapr->xive), lisn, &ive)) { + return H_P2; + } + + if (!(ive.w & IVE_VALID)) { + return H_P2; + } + + /* All sources are emulated under the main XIVE object and share + * the same characteristics. + */ + args[0] =3D 0; + if (!xive_source_esb_has_2page(xsrc)) { + args[0] |=3D SPAPR_XIVE_SRC_TRIGGER; + } + if (xsrc->esb_flags & XIVE_SRC_STORE_EOI) { + args[0] |=3D SPAPR_XIVE_SRC_STORE_EOI; + } + if (xsrc->esb_flags & XIVE_SRC_H_INT_ESB) { + args[0] |=3D SPAPR_XIVE_SRC_H_INT_ESB; + } + + if (xive_source_irq_is_lsi(xsrc, lisn)) { + args[0] |=3D SPAPR_XIVE_SRC_LSI; + } + + if (!(xsrc->esb_flags & XIVE_SRC_H_INT_ESB)) { + args[1] =3D xive->vc_base + + xive_source_esb_mgmt(xsrc, lisn); + } else { + args[1] =3D -1; + } + + if (xive_source_esb_has_2page(xsrc)) { + args[2] =3D xive->vc_base + + xive_source_esb_page(xsrc, lisn); + } else { + args[2] =3D -1; + } + + args[3] =3D xsrc->esb_shift; + + return H_SUCCESS; +} + +/* + * The H_INT_SET_SOURCE_CONFIG hcall() is used to assign a Logical + * Interrupt Source to a target. The Logical Interrupt Source is + * designated with the "lisn" parameter and the target is designated + * with the "target" and "priority" parameters. Upon return from the + * hcall(), no additional interrupts will be directed to the old EQ. + * + * TODO: The old EQ should be investigated for interrupts that + * occurred prior to or during the hcall(). + * + * Parameters: + * Input: + * - "flags" + * Bits 0-61: Reserved + * Bit 62: set the "eisn" in the EA + * Bit 63: masks the interrupt source in the hardware interrupt + * control structure. An interrupt masked by this mechanism will + * be dropped, but it's source state bits will still be + * set. There is no race-free way of unmasking and restoring the + * source. Thus this should only be used in interrupts that are + * also masked at the source, and only in cases where the + * interrupt is not meant to be used for a large amount of time + * because no valid target exists for it for example + * - "lisn" is per "interrupts", "interrupt-map", or + * "ibm,xive-lisn-ranges" properties, or as returned by the + * ibm,query-interrupt-source-number RTAS call, or as returned by + * the H_ALLOCATE_VAS_WINDOW hcall + * - "target" is per "ibm,ppc-interrupt-server#s" or + * "ibm,ppc-interrupt-gserver#s" + * - "priority" is a valid priority not in + * "ibm,plat-res-int-priorities" + * - "eisn" is the guest EISN associated with the "lisn" + * + * Output: + * - None + */ + +#define SPAPR_XIVE_SRC_SET_EISN PPC_BIT(62) +#define SPAPR_XIVE_SRC_MASK PPC_BIT(63) + +static target_ulong h_int_set_source_config(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + XiveRouter *xrtr =3D XIVE_ROUTER(spapr->xive); + XiveIVE ive, new_ive; + target_ulong flags =3D args[0]; + target_ulong lisn =3D args[1]; + target_ulong target =3D args[2]; + target_ulong priority =3D args[3]; + target_ulong eisn =3D args[4]; + uint8_t eq_blk; + uint32_t eq_idx; + + if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + return H_FUNCTION; + } + + if (flags & ~(SPAPR_XIVE_SRC_SET_EISN | SPAPR_XIVE_SRC_MASK)) { + return H_PARAMETER; + } + + if (xive_router_get_ive(XIVE_ROUTER(spapr->xive), lisn, &ive)) { + return H_P2; + } + + if (!(ive.w & IVE_VALID)) { + return H_P2; + } + + /* priority 0xff is used to reset the IVE */ + if (priority =3D=3D 0xff) { + new_ive.w =3D IVE_VALID | IVE_MASKED; + goto out; + } + + if (flags & SPAPR_XIVE_SRC_MASK) { + new_ive.w =3D ive.w | IVE_MASKED; + } else { + new_ive.w =3D ive.w & ~IVE_MASKED; + } + + if (!spapr_xive_eq_is_valid(priority)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid priority %ld request= ed\n", + priority); + return H_P4; + } + + /* Validate that "target" is part of the list of threads allocated + * to the partition. For that, find the EQ corresponding to the + * target. + */ + if (spapr_xive_target_to_eq(xrtr, target, priority, &eq_blk, &eq_idx))= { + return H_P3; + } + + new_ive.w =3D SETFIELD(IVE_EQ_BLOCK, new_ive.w, eq_blk); + new_ive.w =3D SETFIELD(IVE_EQ_INDEX, new_ive.w, eq_idx); + + if (flags & SPAPR_XIVE_SRC_SET_EISN) { + new_ive.w =3D SETFIELD(IVE_EQ_DATA, new_ive.w, eisn); + } + +out: + if (xive_router_set_ive(XIVE_ROUTER(spapr->xive), lisn, &new_ive)) { + return H_HARDWARE; + } + + return H_SUCCESS; +} + +/* + * The H_INT_GET_SOURCE_CONFIG hcall() is used to determine to which + * target/priority pair is assigned to the specified Logical Interrupt + * Source. + * + * Parameters: + * Input: + * - "flags" + * Bits 0-63 Reserved + * - "lisn" is per "interrupts", "interrupt-map", or + * "ibm,xive-lisn-ranges" properties, or as returned by the + * ibm,query-interrupt-source-number RTAS call, or as + * returned by the H_ALLOCATE_VAS_WINDOW hcall + * + * Output: + * - R4: Target to which the specified Logical Interrupt Source is + * assigned + * - R5: Priority to which the specified Logical Interrupt Source is + * assigned + * - R6: EISN for the specified Logical Interrupt Source (this will be + * equivalent to the LISN if not changed by H_INT_SET_SOURCE_CONFIG) + */ +static target_ulong h_int_get_source_config(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong flags =3D args[0]; + target_ulong lisn =3D args[1]; + XiveIVE ive; + XiveEQ eq; + uint8_t eq_blk, vp_blk; + uint32_t eq_idx, vp_idx; + + if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + return H_FUNCTION; + } + + if (flags) { + return H_PARAMETER; + } + + if (xive_router_get_ive(XIVE_ROUTER(spapr->xive), lisn, &ive)) { + return H_P2; + } + + if (!(ive.w & IVE_VALID)) { + return H_P2; + } + + eq_blk =3D GETFIELD(IVE_EQ_BLOCK, ive.w); + eq_idx =3D GETFIELD(IVE_EQ_INDEX, ive.w); + if (xive_router_get_eq(XIVE_ROUTER(spapr->xive), eq_blk, eq_idx, &eq))= { + /* Not sure what to return here */ + return H_HARDWARE; + } + + vp_blk =3D GETFIELD(EQ_W6_NVT_BLOCK, eq.w6); + vp_idx =3D GETFIELD(EQ_W6_NVT_INDEX, eq.w6); + args[0] =3D spapr_xive_vp_to_target(spapr->xive, vp_blk, vp_idx); + + if (ive.w & IVE_MASKED) { + args[1] =3D 0xff; + } else { + args[1] =3D GETFIELD(EQ_W7_F0_PRIORITY, eq.w7); + } + + args[2] =3D GETFIELD(IVE_EQ_DATA, ive.w); + + return H_SUCCESS; +} + +/* + * The H_INT_GET_QUEUE_INFO hcall() is used to get the logical real + * address of the notification management page associated with the + * specified target and priority. + * + * Parameters: + * Input: + * - "flags" + * Bits 0-63 Reserved + * - "target" is per "ibm,ppc-interrupt-server#s" or + * "ibm,ppc-interrupt-gserver#s" + * - "priority" is a valid priority not in + * "ibm,plat-res-int-priorities" + * + * Output: + * - R4: Logical real address of notification page + * - R5: Power of 2 page size of the notification page + */ +static target_ulong h_int_get_queue_info(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + sPAPRXive *xive =3D spapr->xive; + XiveEQSource *eq_xsrc =3D &xive->eq_source; + XiveRouter *xrtr =3D XIVE_ROUTER(xive); + target_ulong flags =3D args[0]; + target_ulong target =3D args[1]; + target_ulong priority =3D args[2]; + XiveEQ eq; + uint8_t eq_blk; + uint32_t eq_idx; + + if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + return H_FUNCTION; + } + + if (flags) { + return H_PARAMETER; + } + + /* + * H_STATE should be returned if a H_INT_RESET is in progress. + * This is not needed when running the emulation under QEMU + */ + + if (!spapr_xive_eq_is_valid(priority)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid priority %ld request= ed\n", + priority); + return H_P3; + } + + /* Validate that "target" is part of the list of threads allocated + * to the partition. For that, find the EQ corresponding to the + * target. + */ + if (spapr_xive_target_to_eq(xrtr, target, priority, &eq_blk, &eq_idx))= { + return H_P2; + } + + if (xive_router_get_eq(xrtr, eq_blk, eq_idx, &eq)) { + return H_HARDWARE; + } + + args[0] =3D xive->eq_base + (1ull << (eq_xsrc->esb_shift + 1)) * eq_id= x; + if (eq.w0 & EQ_W0_ENQUEUE) { + args[1] =3D GETFIELD(EQ_W0_QSIZE, eq.w0) + 12; + } else { + args[1] =3D 0; + } + + return H_SUCCESS; +} + +/* + * The H_INT_SET_QUEUE_CONFIG hcall() is used to set or reset a EQ for + * a given "target" and "priority". It is also used to set the + * notification config associated with the EQ. An EQ size of 0 is + * used to reset the EQ config for a given target and priority. If + * resetting the EQ config, the END associated with the given "target" + * and "priority" will be changed to disable queueing. + * + * Upon return from the hcall(), no additional interrupts will be + * directed to the old EQ (if one was set). The old EQ (if one was + * set) should be investigated for interrupts that occurred prior to + * or during the hcall(). + * + * Parameters: + * Input: + * - "flags" + * Bits 0-62: Reserved + * Bit 63: Unconditional Notify (n) per the XIVE spec + * - "target" is per "ibm,ppc-interrupt-server#s" or + * "ibm,ppc-interrupt-gserver#s" + * - "priority" is a valid priority not in + * "ibm,plat-res-int-priorities" + * - "eventQueue": The logical real address of the start of the EQ + * - "eventQueueSize": The power of 2 EQ size per "ibm,xive-eq-sizes" + * + * Output: + * - None + */ + +#define SPAPR_XIVE_EQ_ALWAYS_NOTIFY PPC_BIT(63) + +static target_ulong h_int_set_queue_config(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + XiveRouter *xrtr =3D XIVE_ROUTER(spapr->xive); + target_ulong flags =3D args[0]; + target_ulong target =3D args[1]; + target_ulong priority =3D args[2]; + target_ulong qpage =3D args[3]; + target_ulong qsize =3D args[4]; + XiveEQ eq; + uint8_t eq_blk, vp_blk; + uint32_t eq_idx, vp_idx; + uint32_t qdata; + + if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + return H_FUNCTION; + } + + if (flags & ~SPAPR_XIVE_EQ_ALWAYS_NOTIFY) { + return H_PARAMETER; + } + + /* + * H_STATE should be returned if a H_INT_RESET is in progress. + * This is not needed when running the emulation under QEMU + */ + + if (!spapr_xive_eq_is_valid(priority)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid priority %ld request= ed\n", + priority); + return H_P3; + } + + /* Validate that "target" is part of the list of threads allocated + * to the partition. For that, find the EQ corresponding to the + * target. + */ + + if (spapr_xive_target_to_eq(xrtr, target, priority, &eq_blk, &eq_idx))= { + return H_P2; + } + + if (xive_router_get_eq(xrtr, eq_blk, eq_idx, &eq)) { + return H_HARDWARE; + } + + switch (qsize) { + case 12: + case 16: + case 21: + case 24: + eq.w3 =3D ((uint64_t)qpage) & 0xffffffff; + eq.w2 =3D (((uint64_t)qpage)) >> 32 & 0x0fffffff; + eq.w0 |=3D EQ_W0_ENQUEUE; + eq.w0 =3D SETFIELD(EQ_W0_QSIZE, eq.w0, qsize - 12); + break; + case 0: + /* reset queue and disable queueing */ + xive_eq_reset(&eq); + goto out; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid EQ size %"PRIx64"\n", + qsize); + return H_P5; + } + + if (qsize) { + /* + * Let's validate the EQ address with a read of the first EQ + * entry. We could also check that the full queue has been + * zeroed by the OS. + */ + if (address_space_read(&address_space_memory, qpage, + MEMTXATTRS_UNSPECIFIED, + (uint8_t *) &qdata, sizeof(qdata))) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to read EQ data @= 0x%" + HWADDR_PRIx "\n", qpage); + return H_P4; + } + } + + if (spapr_xive_target_to_vp(xrtr, target, &vp_blk, &vp_idx)) { + return H_HARDWARE; + } + + /* Ensure the priority and target are correctly set (they will not + * be right after allocation) + */ + eq.w6 =3D SETFIELD(EQ_W6_NVT_BLOCK, 0ul, vp_blk) | + SETFIELD(EQ_W6_NVT_INDEX, 0ul, vp_idx); + eq.w7 =3D SETFIELD(EQ_W7_F0_PRIORITY, 0ul, priority); + + if (flags & SPAPR_XIVE_EQ_ALWAYS_NOTIFY) { + eq.w0 |=3D EQ_W0_UCOND_NOTIFY; + } else { + eq.w0 &=3D ~EQ_W0_UCOND_NOTIFY; + } + + /* The generation bit for the EQ starts at 1 and The EQ page + * offset counter starts at 0. + */ + eq.w1 =3D EQ_W1_GENERATION | SETFIELD(EQ_W1_PAGE_OFF, 0ul, 0ul); + eq.w0 |=3D EQ_W0_VALID; + + /* TODO: issue syncs required to ensure all in-flight interrupts + * are complete on the old EQ */ +out: + /* Update EQ */ + if (xive_router_set_eq(xrtr, eq_blk, eq_idx, &eq)) { + return H_HARDWARE; + } + + return H_SUCCESS; +} + +/* + * The H_INT_GET_QUEUE_CONFIG hcall() is used to get a EQ for a given + * target and priority. + * + * Parameters: + * Input: + * - "flags" + * Bits 0-62: Reserved + * Bit 63: Debug: Return debug data + * - "target" is per "ibm,ppc-interrupt-server#s" or + * "ibm,ppc-interrupt-gserver#s" + * - "priority" is a valid priority not in + * "ibm,plat-res-int-priorities" + * + * Output: + * - R4: "flags": + * Bits 0-61: Reserved + * Bit 62: The value of Event Queue Generation Number (g) per + * the XIVE spec if "Debug" =3D 1 + * Bit 63: The value of Unconditional Notify (n) per the XIVE spec + * - R5: The logical real address of the start of the EQ + * - R6: The power of 2 EQ size per "ibm,xive-eq-sizes" + * - R7: The value of Event Queue Offset Counter per XIVE spec + * if "Debug" =3D 1, else 0 + * + */ + +#define SPAPR_XIVE_EQ_DEBUG PPC_BIT(63) + +static target_ulong h_int_get_queue_config(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + XiveRouter *xrtr =3D XIVE_ROUTER(spapr->xive); + target_ulong flags =3D args[0]; + target_ulong target =3D args[1]; + target_ulong priority =3D args[2]; + XiveEQ eq; + uint8_t eq_blk; + uint32_t eq_idx; + + if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + return H_FUNCTION; + } + + if (flags & ~SPAPR_XIVE_EQ_DEBUG) { + return H_PARAMETER; + } + + /* + * H_STATE should be returned if a H_INT_RESET is in progress. + * This is not needed when running the emulation under QEMU + */ + + if (!spapr_xive_eq_is_valid(priority)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid priority %ld request= ed\n", + priority); + return H_P3; + } + + /* Validate that "target" is part of the list of threads allocated + * to the partition. For that, find the EQ corresponding to the + * target. + */ + if (spapr_xive_target_to_eq(xrtr, target, priority, &eq_blk, &eq_idx))= { + return H_P2; + } + + if (xive_router_get_eq(xrtr, eq_blk, eq_idx, &eq)) { + return H_HARDWARE; + } + + args[0] =3D 0; + if (eq.w0 & EQ_W0_UCOND_NOTIFY) { + args[0] |=3D SPAPR_XIVE_EQ_ALWAYS_NOTIFY; + } + + if (eq.w0 & EQ_W0_ENQUEUE) { + args[1] =3D + (((uint64_t)(eq.w2 & 0x0fffffff)) << 32) | eq.w3; + args[2] =3D GETFIELD(EQ_W0_QSIZE, eq.w0) + 12; + } else { + args[1] =3D 0; + args[2] =3D 0; + } + + /* TODO: do we need any locking on the EQ ? */ + if (flags & SPAPR_XIVE_EQ_DEBUG) { + /* Load the event queue generation number into the return flags */ + args[0] |=3D (uint64_t)GETFIELD(EQ_W1_GENERATION, eq.w1) << 62; + + /* Load R7 with the event queue offset counter */ + args[3] =3D GETFIELD(EQ_W1_PAGE_OFF, eq.w1); + } else { + args[3] =3D 0; + } + + return H_SUCCESS; +} + +/* + * The H_INT_SET_OS_REPORTING_LINE hcall() is used to set the + * reporting cache line pair for the calling thread. The reporting + * cache lines will contain the OS interrupt context when the OS + * issues a CI store byte to @TIMA+0xC10 to acknowledge the OS + * interrupt. The reporting cache lines can be reset by inputting -1 + * in "reportingLine". Issuing the CI store byte without reporting + * cache lines registered will result in the data not being accessible + * to the OS. + * + * Parameters: + * Input: + * - "flags" + * Bits 0-63: Reserved + * - "reportingLine": The logical real address of the reporting cache + * line pair + * + * Output: + * - None + */ +static target_ulong h_int_set_os_reporting_line(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + return H_FUNCTION; + } + + /* + * H_STATE should be returned if a H_INT_RESET is in progress. + * This is not needed when running the emulation under QEMU + */ + + /* TODO: H_INT_SET_OS_REPORTING_LINE */ + return H_FUNCTION; +} + +/* + * The H_INT_GET_OS_REPORTING_LINE hcall() is used to get the logical + * real address of the reporting cache line pair set for the input + * "target". If no reporting cache line pair has been set, -1 is + * returned. + * + * Parameters: + * Input: + * - "flags" + * Bits 0-63: Reserved + * - "target" is per "ibm,ppc-interrupt-server#s" or + * "ibm,ppc-interrupt-gserver#s" + * - "reportingLine": The logical real address of the reporting cache + * line pair + * + * Output: + * - R4: The logical real address of the reporting line if set, else -1 + */ +static target_ulong h_int_get_os_reporting_line(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + return H_FUNCTION; + } + + /* + * H_STATE should be returned if a H_INT_RESET is in progress. + * This is not needed when running the emulation under QEMU + */ + + /* TODO: H_INT_GET_OS_REPORTING_LINE */ + return H_FUNCTION; +} + +/* + * The H_INT_ESB hcall() is used to issue a load or store to the ESB + * page for the input "lisn". This hcall is only supported for LISNs + * that have the ESB hcall flag set to 1 when returned from hcall() + * H_INT_GET_SOURCE_INFO. + * + * Parameters: + * Input: + * - "flags" + * Bits 0-62: Reserved + * bit 63: Store: Store=3D1, store operation, else load operation + * - "lisn" is per "interrupts", "interrupt-map", or + * "ibm,xive-lisn-ranges" properties, or as returned by the + * ibm,query-interrupt-source-number RTAS call, or as + * returned by the H_ALLOCATE_VAS_WINDOW hcall + * - "esbOffset" is the offset into the ESB page for the load or store ope= ration + * - "storeData" is the data to write for a store operation + * + * Output: + * - R4: R4: The value of the load if load operation, else -1 + */ + +#define SPAPR_XIVE_ESB_STORE PPC_BIT(63) + +static target_ulong h_int_esb(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + sPAPRXive *xive =3D spapr->xive; + XiveIVE ive; + target_ulong flags =3D args[0]; + target_ulong lisn =3D args[1]; + target_ulong offset =3D args[2]; + target_ulong data =3D args[3]; + hwaddr mmio_addr; + XiveSource *xsrc =3D &xive->source; + + if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + return H_FUNCTION; + } + + if (flags & ~SPAPR_XIVE_ESB_STORE) { + return H_PARAMETER; + } + + if (xive_router_get_ive(XIVE_ROUTER(spapr->xive), lisn, &ive)) { + return H_P2; + } + + if (!(ive.w & IVE_VALID)) { + return H_P2; + } + + if (offset > (1ull << xsrc->esb_shift)) { + return H_P3; + } + + mmio_addr =3D xive->vc_base + xive_source_esb_page(xsrc, lisn) + offse= t; + + if (dma_memory_rw(&address_space_memory, mmio_addr, &data, 8, + (flags & SPAPR_XIVE_ESB_STORE))) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to access ESB @0x%" + HWADDR_PRIx "\n", mmio_addr); + return H_HARDWARE; + } + args[0] =3D (flags & SPAPR_XIVE_ESB_STORE) ? -1 : data; + return H_SUCCESS; +} + +/* + * The H_INT_SYNC hcall() is used to issue hardware syncs that will + * ensure any in flight events for the input lisn are in the event + * queue. + * + * Parameters: + * Input: + * - "flags" + * Bits 0-63: Reserved + * - "lisn" is per "interrupts", "interrupt-map", or + * "ibm,xive-lisn-ranges" properties, or as returned by the + * ibm,query-interrupt-source-number RTAS call, or as + * returned by the H_ALLOCATE_VAS_WINDOW hcall + * + * Output: + * - None + */ +static target_ulong h_int_sync(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + XiveIVE ive; + target_ulong flags =3D args[0]; + target_ulong lisn =3D args[1]; + + if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + return H_FUNCTION; + } + + if (flags) { + return H_PARAMETER; + } + + if (xive_router_get_ive(XIVE_ROUTER(spapr->xive), lisn, &ive)) { + return H_P2; + } + + if (!(ive.w & IVE_VALID)) { + return H_P2; + } + + /* + * H_STATE should be returned if a H_INT_RESET is in progress. + * This is not needed when running the emulation under QEMU + */ + + /* This is not real hardware. Nothing to be done */ + return H_SUCCESS; +} + +/* + * The H_INT_RESET hcall() is used to reset all of the partition's + * interrupt exploitation structures to their initial state. This + * means losing all previously set interrupt state set via + * H_INT_SET_SOURCE_CONFIG and H_INT_SET_QUEUE_CONFIG. + * + * Parameters: + * Input: + * - "flags" + * Bits 0-63: Reserved + * + * Output: + * - None + */ +static target_ulong h_int_reset(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong flags =3D args[0]; + + if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + return H_FUNCTION; + } + + if (flags) { + return H_PARAMETER; + } + + device_reset(DEVICE(spapr->xive)); + return H_SUCCESS; +} + +void spapr_xive_hcall_init(sPAPRMachineState *spapr) +{ + spapr_register_hypercall(H_INT_GET_SOURCE_INFO, h_int_get_source_info); + spapr_register_hypercall(H_INT_SET_SOURCE_CONFIG, h_int_set_source_con= fig); + spapr_register_hypercall(H_INT_GET_SOURCE_CONFIG, h_int_get_source_con= fig); + spapr_register_hypercall(H_INT_GET_QUEUE_INFO, h_int_get_queue_info); + spapr_register_hypercall(H_INT_SET_QUEUE_CONFIG, h_int_set_queue_confi= g); + spapr_register_hypercall(H_INT_GET_QUEUE_CONFIG, h_int_get_queue_confi= g); + spapr_register_hypercall(H_INT_SET_OS_REPORTING_LINE, + h_int_set_os_reporting_line); + spapr_register_hypercall(H_INT_GET_OS_REPORTING_LINE, + h_int_get_os_reporting_line); + spapr_register_hypercall(H_INT_ESB, h_int_esb); + spapr_register_hypercall(H_INT_SYNC, h_int_sync); + spapr_register_hypercall(H_INT_RESET, h_int_reset); +} diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index b5c3e7b197b6..c9a3c9694a91 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -564,6 +564,8 @@ static void spapr_irq_init_xive(sPAPRMachineState *spap= r, uint32_t nr_servers, for (i =3D 0; i < nr_servers; ++i) { spapr_irq_alloc(spapr, SPAPR_IRQ_IPI, i, errp); } + + spapr_xive_hcall_init(spapr); } =20 /* diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 301a8e972d91..eacd26836ebf 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -38,7 +38,7 @@ obj-$(CONFIG_XICS) +=3D xics.o obj-$(CONFIG_XICS_SPAPR) +=3D xics_spapr.o obj-$(CONFIG_XICS_KVM) +=3D xics_kvm.o obj-$(CONFIG_XIVE) +=3D xive.o -obj-$(CONFIG_XIVE_SPAPR) +=3D spapr_xive.o +obj-$(CONFIG_XIVE_SPAPR) +=3D spapr_xive.o spapr_xive_hcall.o obj-$(CONFIG_POWERNV) +=3D xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) +=3D allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) +=3D s390_flic.o --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528387654604100.82381702177781; Thu, 7 Jun 2018 09:07:34 -0700 (PDT) Received: from localhost ([::1]:58866 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxRl-0001Gn-Nb for importer@patchew.org; Thu, 07 Jun 2018 12:07:33 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39196) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxCj-0002lu-6Z for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxCe-0004C3-E7 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:01 -0400 Received: from 9.mo5.mail-out.ovh.net ([178.32.96.204]:51158) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxCe-0004BQ-4T for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:51:56 -0400 Received: from player169.ha.ovh.net (unknown [10.109.120.100]) by mo5.mail-out.ovh.net (Postfix) with ESMTP id 967F01BDF45 for ; Thu, 7 Jun 2018 17:51:54 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 30EB55800A4; Thu, 7 Jun 2018 17:51:49 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:53 +0200 Message-Id: <20180607155003.1580-19-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6096185048252582739 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 178.32.96.204 Subject: [Qemu-devel] [PATCH v4 18/28] spapr: add device tree support for the XIVE exploitation mode 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The XIVE interface for the guest is described in the device tree under the "interrupt-controller" node. A couple of new properties are specific to XIVE : - "reg" contains the base address and size of the thread interrupt managnement areas (TIMA), also called rings, for the User level and for the Guest OS level. Only the Guest OS level is taken into account today. - "ibm,xive-eq-sizes" the size of the event queues. One cell per size supported, contains log2 of size, in ascending order. - "ibm,xive-lisn-ranges" the IRQ interrupt number ranges assigned to the guest for the IPIs. and also under the root node : - "ibm,plat-res-int-priorities" contains a list of priorities that the hypervisor has reserved for its own use. OPAL uses the priority 7 queue to automatically escalate interrupts for all other queues (DD2.X POWER9). So only priorities [0..6] are allowed for the guest. Extend the sPAPR IRQ backend with a new handler to populate the DT with the appropriate "interrupt-controller" node. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/spapr_irq.h | 2 ++ include/hw/ppc/spapr_xive.h | 2 ++ hw/intc/spapr_xive_hcall.c | 62 +++++++++++++++++++++++++++++++++++++++++= ++++ hw/ppc/spapr.c | 3 ++- hw/ppc/spapr_irq.c | 25 ++++++++++++++++++ 5 files changed, 93 insertions(+), 1 deletion(-) diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index aa41c487b705..b070276c9abb 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -42,6 +42,8 @@ typedef struct sPAPRIrq { void (*free)(sPAPRMachineState *spapr, int irq, int num, Error **errp); qemu_irq (*qirq)(sPAPRMachineState *spapr, int irq); void (*print_info)(sPAPRMachineState *spapr, Monitor *mon); + void (*dt_populate)(sPAPRMachineState *spapr, uint32_t nr_servers, + void *fdt, uint32_t phandle); } sPAPRIrq; =20 extern sPAPRIrq spapr_irq_legacy; diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index 5dedb9e5c7c0..3cbf8dbefb87 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -62,5 +62,7 @@ bool spapr_xive_eq_is_valid(uint8_t priority); typedef struct sPAPRMachineState sPAPRMachineState; =20 void spapr_xive_hcall_init(sPAPRMachineState *spapr); +void spapr_dt_xive(sPAPRXive *xive, int nr_servers, void *fdt, + uint32_t phandle); =20 #endif /* PPC_SPAPR_XIVE_H */ diff --git a/hw/intc/spapr_xive_hcall.c b/hw/intc/spapr_xive_hcall.c index 376ff7ba00f9..526f79276927 100644 --- a/hw/intc/spapr_xive_hcall.c +++ b/hw/intc/spapr_xive_hcall.c @@ -885,3 +885,65 @@ void spapr_xive_hcall_init(sPAPRMachineState *spapr) spapr_register_hypercall(H_INT_SYNC, h_int_sync); spapr_register_hypercall(H_INT_RESET, h_int_reset); } + +void spapr_dt_xive(sPAPRXive *xive, int nr_servers, void *fdt, uint32_t ph= andle) +{ + int node; + uint64_t timas[2 * 2]; + /* Interrupt number ranges for the IPIs */ + uint32_t lisn_ranges[] =3D { + cpu_to_be32(0), + cpu_to_be32(nr_servers), + }; + uint32_t eq_sizes[] =3D { + cpu_to_be32(12), /* 4K */ + cpu_to_be32(16), /* 64K */ + cpu_to_be32(21), /* 2M */ + cpu_to_be32(24), /* 16M */ + }; + /* The following array is in sync with the 'spapr_xive_eq_is_valid' + * routine above. Linux is expected to choose priority 6. + */ + uint32_t plat_res_int_priorities[] =3D { + cpu_to_be32(7), /* start */ + cpu_to_be32(0xf8), /* count */ + }; + gchar *nodename; + + /* Thread Interrupt Management Area : User (ring 3) and OS (ring 2) */ + timas[0] =3D cpu_to_be64(xive->tm_base + 3 * (1ull << TM_SHIFT)); + timas[1] =3D cpu_to_be64(1ull << TM_SHIFT); + timas[2] =3D cpu_to_be64(xive->tm_base + 2 * (1ull << TM_SHIFT)); + timas[3] =3D cpu_to_be64(1ull << TM_SHIFT); + + nodename =3D g_strdup_printf("interrupt-controller@%" PRIx64, + xive->tm_base + 3 * (1 << TM_SHIFT)); + _FDT(node =3D fdt_add_subnode(fdt, 0, nodename)); + g_free(nodename); + + _FDT(fdt_setprop_string(fdt, node, "device_type", "power-ivpe")); + _FDT(fdt_setprop(fdt, node, "reg", timas, sizeof(timas))); + + _FDT(fdt_setprop_string(fdt, node, "compatible", "ibm,power-ivpe")); + _FDT(fdt_setprop(fdt, node, "ibm,xive-eq-sizes", eq_sizes, + sizeof(eq_sizes))); + _FDT(fdt_setprop(fdt, node, "ibm,xive-lisn-ranges", lisn_ranges, + sizeof(lisn_ranges))); + + /* For Linux to link the LSIs to the main interrupt controller. + * These properties are not in XIVE exploitation mode sPAPR + * specs + */ + _FDT(fdt_setprop(fdt, node, "interrupt-controller", NULL, 0)); + _FDT(fdt_setprop_cell(fdt, node, "#interrupt-cells", 2)); + + /* For SLOF */ + _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle)); + _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle)); + + /* The "ibm,plat-res-int-priorities" property defines the priority + * ranges reserved by the hypervisor + */ + _FDT(fdt_setprop(fdt, 0, "ibm,plat-res-int-priorities", + plat_res_int_priorities, sizeof(plat_res_int_prioriti= es))); +} diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 156feff6e3fa..3340264e4cfb 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1233,7 +1233,8 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr, _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2)); =20 /* /interrupt controller */ - spapr_dt_xics(xics_max_server_number(spapr), fdt, PHANDLE_XICP); + smc->irq->dt_populate(spapr, xics_max_server_number(spapr), fdt, + PHANDLE_XICP); =20 ret =3D spapr_populate_memory(spapr, fdt); if (ret < 0) { diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index c9a3c9694a91..be71998777c2 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -240,6 +240,14 @@ static void spapr_irq_print_info_legacy(sPAPRMachineSt= ate *spapr, ics_pic_print_info(spapr->ics, mon); } =20 + +static void spapr_irq_dt_populate_legacy(sPAPRMachineState *spapr, + uint32_t nr_servers, void *fdt, + uint32_t phandle) +{ + spapr_dt_xics(nr_servers, fdt, phandle); +} + sPAPRIrq spapr_irq_legacy =3D { .nr_irqs =3D XICS_IRQS_SPAPR, .init =3D spapr_irq_init_legacy, @@ -249,6 +257,7 @@ sPAPRIrq spapr_irq_legacy =3D { .free =3D spapr_irq_free_legacy, .qirq =3D spapr_qirq_legacy, .print_info =3D spapr_irq_print_info_legacy, + .dt_populate =3D spapr_irq_dt_populate_legacy, }; =20 /* @@ -457,6 +466,13 @@ static void spapr_irq_print_info_xics(sPAPRMachineStat= e *spapr, spapr_irq_print_info_legacy(spapr, mon); } =20 +static void spapr_irq_dt_populate_xics(sPAPRMachineState *spapr, + uint32_t nr_servers, void *fdt, + uint32_t phandle) +{ + spapr_irq_dt_populate_legacy(spapr, nr_servers, fdt, phandle); +} + /* * XICS IRQ number space * @@ -501,6 +517,7 @@ sPAPRIrq spapr_irq_xics =3D { .free =3D spapr_irq_free_xics, .qirq =3D spapr_qirq_xics, .print_info =3D spapr_irq_print_info_xics, + .dt_populate =3D spapr_irq_dt_populate_xics, }; =20 /* @@ -659,6 +676,13 @@ static void spapr_irq_print_info_xive(sPAPRMachineStat= e *spapr, spapr_xive_pic_print_info(spapr->xive, mon); } =20 +static void spapr_irq_dt_populate_xive(sPAPRMachineState *spapr, + uint32_t nr_servers, void *fdt, + uint32_t phandle) +{ + spapr_dt_xive(spapr->xive, nr_servers, fdt, phandle); +} + /* * XIVE IRQ number space * @@ -705,6 +729,7 @@ sPAPRIrq spapr_irq_xive =3D { .free =3D spapr_irq_free_xive, .qirq =3D spapr_qirq_xive, .print_info =3D spapr_irq_print_info_xive, + .dt_populate =3D spapr_irq_dt_populate_xive, }; =20 /* --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528388053527594.2116323605292; Thu, 7 Jun 2018 09:14:13 -0700 (PDT) Received: from localhost ([::1]:58929 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxYC-0007rE-OQ for importer@patchew.org; Thu, 07 Jun 2018 12:14:12 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39246) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxCq-0002t2-AQ for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxCk-0004Ef-1w for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:08 -0400 Received: from 7.mo173.mail-out.ovh.net ([46.105.44.159]:52975) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxCj-0004E0-OC for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:01 -0400 Received: from player169.ha.ovh.net (unknown [10.109.108.82]) by mo173.mail-out.ovh.net (Postfix) with ESMTP id 0F636C4D80 for ; Thu, 7 Jun 2018 17:52:00 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 9EEB55800B3; Thu, 7 Jun 2018 17:51:54 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:54 +0200 Message-Id: <20180607155003.1580-20-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6097592423582108499 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.44.159 Subject: [Qemu-devel] [PATCH v4 19/28] spapr: allocate the interrupt thread context under the CPU core 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Each interrupt mode has its own specific interrupt presenter object, that we store under the CPU object, one for XICS and one for XIVE. Extend the sPAPR IRQ backend with a new handler to support them both. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/spapr.h | 1 + include/hw/ppc/spapr_irq.h | 2 ++ include/hw/ppc/xive.h | 2 ++ hw/intc/xive.c | 21 +++++++++++++++++++++ hw/ppc/spapr_cpu_core.c | 4 ++-- hw/ppc/spapr_irq.c | 23 +++++++++++++++++++++++ 6 files changed, 51 insertions(+), 2 deletions(-) diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 3c7bae874f91..223837882496 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -169,6 +169,7 @@ struct sPAPRMachineState { unsigned long *irq_map; const char *icp_type; sPAPRXive *xive; + const char *xive_tctx_type; =20 bool cmd_line_caps[SPAPR_CAP_NUM]; sPAPRCapabilities def, eff, mig; diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index b070276c9abb..8046cbd83d61 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -44,6 +44,8 @@ typedef struct sPAPRIrq { void (*print_info)(sPAPRMachineState *spapr, Monitor *mon); void (*dt_populate)(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt, uint32_t phandle); + Object *(*cpu_intc_create)(sPAPRMachineState *spapr, Object *cpu, + Error **errp); } sPAPRIrq; =20 extern sPAPRIrq spapr_irq_legacy; diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index e29b52eeb91f..378bd61c6d18 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -281,5 +281,7 @@ typedef struct XiveTCTX { extern const MemoryRegionOps xive_tm_ops; =20 void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon); +Object *xive_tctx_create(Object *cpu, const char *type, XiveRouter *xrtr, + Error **errp); =20 #endif /* PPC_XIVE_H */ diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 671ea1c6c36b..8d86f739522d 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -587,6 +587,27 @@ static const TypeInfo xive_tctx_info =3D { .class_init =3D xive_tctx_class_init, }; =20 +Object *xive_tctx_create(Object *cpu, const char *type, XiveRouter *xrtr, + Error **errp) +{ + Error *local_err =3D NULL; + Object *obj; + + obj =3D object_new(type); + object_property_add_child(cpu, type, obj, &error_abort); + object_unref(obj); + object_property_add_const_link(obj, "cpu", cpu, &error_abort); + object_property_add_const_link(obj, "xive", OBJECT(xrtr), &error_abort= ); + object_property_set_bool(obj, true, "realized", &local_err); + if (local_err) { + object_unparent(obj); + error_propagate(errp, local_err); + return NULL; + } + + return obj; +} + /* * XIVE ESB helpers */ diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index f3e9b879b251..fe9bcfdf01c8 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -148,6 +148,7 @@ static void spapr_cpu_core_realize_child(Object *child, Error *local_err =3D NULL; CPUState *cs =3D CPU(child); PowerPCCPU *cpu =3D POWERPC_CPU(cs); + sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(spapr); =20 object_property_set_bool(child, true, "realized", &local_err); if (local_err) { @@ -159,8 +160,7 @@ static void spapr_cpu_core_realize_child(Object *child, goto error; } =20 - cpu->intc =3D icp_create(child, spapr->icp_type, XICS_FABRIC(spapr), - &local_err); + cpu->intc =3D smc->irq->cpu_intc_create(spapr, child, &local_err); if (local_err) { goto error; } diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index be71998777c2..266f7db3be7b 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -248,6 +248,12 @@ static void spapr_irq_dt_populate_legacy(sPAPRMachineS= tate *spapr, spapr_dt_xics(nr_servers, fdt, phandle); } =20 +static Object *spapr_irq_cpu_intc_create_legacy(sPAPRMachineState *spapr, + Object *cpu, Error **errp) +{ + return icp_create(cpu, spapr->icp_type, XICS_FABRIC(spapr), errp); +} + sPAPRIrq spapr_irq_legacy =3D { .nr_irqs =3D XICS_IRQS_SPAPR, .init =3D spapr_irq_init_legacy, @@ -258,6 +264,7 @@ sPAPRIrq spapr_irq_legacy =3D { .qirq =3D spapr_qirq_legacy, .print_info =3D spapr_irq_print_info_legacy, .dt_populate =3D spapr_irq_dt_populate_legacy, + .cpu_intc_create =3D spapr_irq_cpu_intc_create_legacy, }; =20 /* @@ -473,6 +480,12 @@ static void spapr_irq_dt_populate_xics(sPAPRMachineSta= te *spapr, spapr_irq_dt_populate_legacy(spapr, nr_servers, fdt, phandle); } =20 +static Object *spapr_irq_cpu_intc_create_xics(sPAPRMachineState *spapr, + Object *cpu, Error **errp) +{ + return spapr_irq_cpu_intc_create_legacy(spapr, cpu, errp); +} + /* * XICS IRQ number space * @@ -518,6 +531,7 @@ sPAPRIrq spapr_irq_xics =3D { .qirq =3D spapr_qirq_xics, .print_info =3D spapr_irq_print_info_xics, .dt_populate =3D spapr_irq_dt_populate_xics, + .cpu_intc_create =3D spapr_irq_cpu_intc_create_xics, }; =20 /* @@ -582,6 +596,7 @@ static void spapr_irq_init_xive(sPAPRMachineState *spap= r, uint32_t nr_servers, spapr_irq_alloc(spapr, SPAPR_IRQ_IPI, i, errp); } =20 + spapr->xive_tctx_type =3D TYPE_XIVE_TCTX; spapr_xive_hcall_init(spapr); } =20 @@ -683,6 +698,13 @@ static void spapr_irq_dt_populate_xive(sPAPRMachineSta= te *spapr, spapr_dt_xive(spapr->xive, nr_servers, fdt, phandle); } =20 +static Object *spapr_irq_cpu_intc_create_xive(sPAPRMachineState *spapr, + Object *cpu, Error **er= rp) +{ + return xive_tctx_create(cpu, spapr->xive_tctx_type, + XIVE_ROUTER(spapr->xive), errp); +} + /* * XIVE IRQ number space * @@ -730,6 +752,7 @@ sPAPRIrq spapr_irq_xive =3D { .qirq =3D spapr_qirq_xive, .print_info =3D spapr_irq_print_info_xive, .dt_populate =3D spapr_irq_dt_populate_xive, + .cpu_intc_create =3D spapr_irq_cpu_intc_create_xive, }; =20 /* --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528387957106522.8336651293353; Thu, 7 Jun 2018 09:12:37 -0700 (PDT) Received: from localhost ([::1]:58921 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxWe-0006cD-4e for importer@patchew.org; Thu, 07 Jun 2018 12:12:36 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39257) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxCt-0002uQ-V5 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:13 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxCp-0004H8-3l for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:12 -0400 Received: from 10.mo177.mail-out.ovh.net ([46.105.73.133]:47712) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxCo-0004GK-Q7 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:07 -0400 Received: from player169.ha.ovh.net (unknown [10.109.122.74]) by mo177.mail-out.ovh.net (Postfix) with ESMTP id 80269B49CA for ; Thu, 7 Jun 2018 17:52:05 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 18DE55800B6; Thu, 7 Jun 2018 17:52:00 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:55 +0200 Message-Id: <20180607155003.1580-21-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6099281274084232019 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.73.133 Subject: [Qemu-devel] [PATCH v4 20/28] spapr: introduce a 'pseries-3.0-xive' QEMU machine 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The interrupt mode is statically defined to XIVE only for this machine. The guest OS is required to have support for the XIVE exploitation mode of the POWER9 interrupt controller. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/spapr_irq.h | 1 + hw/ppc/spapr.c | 35 ++++++++++++++++++++++++++++++----- hw/ppc/spapr_irq.c | 3 +++ 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index 8046cbd83d61..85829928a9c4 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -31,6 +31,7 @@ typedef struct sPAPRPIrqRange { typedef struct sPAPRIrq { uint32_t nr_irqs; const sPAPRPIrqRange *ranges; + uint8_t ov5; =20 void (*init)(sPAPRMachineState *spapr, uint32_t nr_servers, Error **er= rp); int (*assign)(sPAPRMachineState *spapr, uint32_t range, uint32_t irq, diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 3340264e4cfb..2774b53f169e 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1060,12 +1060,14 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr,= void *fdt) spapr_dt_rtas_tokens(fdt, rtas); } =20 -/* Prepare ibm,arch-vec-5-platform-support, which indicates the MMU featur= es - * that the guest may request and thus the valid values for bytes 24..26 of - * option vector 5: */ -static void spapr_dt_ov5_platform_support(void *fdt, int chosen) +/* Prepare ibm,arch-vec-5-platform-support, which indicates the MMU + * and the XIVE features that the guest may request and thus the valid + * values for bytes 23..26 of option vector 5: */ +static void spapr_dt_ov5_platform_support(sPAPRMachineState *spapr, void *= fdt, + int chosen) { PowerPCCPU *first_ppc_cpu =3D POWERPC_CPU(first_cpu); + sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(spapr); =20 char val[2 * 4] =3D { 23, 0x00, /* Xive mode, filled in below. */ @@ -1086,7 +1088,10 @@ static void spapr_dt_ov5_platform_support(void *fdt,= int chosen) } else { val[3] =3D 0x00; /* Hash */ } + val[1] =3D smc->irq->ov5; } else { + val[1] =3D smc->irq->ov5; + /* V3 MMU supports both hash and radix in tcg (with dynamic switch= ing) */ val[3] =3D 0xC0; } @@ -1154,7 +1159,7 @@ static void spapr_dt_chosen(sPAPRMachineState *spapr,= void *fdt) _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path)); } =20 - spapr_dt_ov5_platform_support(fdt, chosen); + spapr_dt_ov5_platform_support(spapr, fdt, chosen); =20 g_free(stdout_path); g_free(bootlist); @@ -2577,6 +2582,11 @@ static void spapr_machine_init(MachineState *machine) /* advertise support for ibm,dyamic-memory-v2 */ spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2); =20 + /* advertise XIVE */ + if (smc->irq->ov5) { + spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT); + } + /* init CPUs */ spapr_init_cpus(spapr); =20 @@ -3916,6 +3926,21 @@ static void spapr_machine_3_0_class_options(MachineC= lass *mc) =20 DEFINE_SPAPR_MACHINE(3_0, "3.0", true); =20 +static void spapr_machine_3_0_xive_instance_options(MachineState *machine) +{ + spapr_machine_3_0_instance_options(machine); +} + +static void spapr_machine_3_0_xive_class_options(MachineClass *mc) +{ + sPAPRMachineClass *smc =3D SPAPR_MACHINE_CLASS(mc); + + spapr_machine_3_0_class_options(mc); + smc->irq =3D &spapr_irq_xive; +} + +DEFINE_SPAPR_MACHINE(3_0_xive, "3.0-xive", false); + /* * pseries-2.12 */ diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 266f7db3be7b..745c78024d6f 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -256,6 +256,7 @@ static Object *spapr_irq_cpu_intc_create_legacy(sPAPRMa= chineState *spapr, =20 sPAPRIrq spapr_irq_legacy =3D { .nr_irqs =3D XICS_IRQS_SPAPR, + .ov5 =3D 0x0, /* XICS only */ .init =3D spapr_irq_init_legacy, .assign =3D spapr_irq_assign_legacy, .alloc =3D spapr_irq_alloc_legacy, @@ -522,6 +523,7 @@ static const sPAPRPIrqRange spapr_irq_ranges_xics[] =3D= { =20 sPAPRIrq spapr_irq_xics =3D { .nr_irqs =3D 0x1000, + .ov5 =3D 0x0, /* XICS only */ .init =3D spapr_irq_init_xics, .ranges =3D spapr_irq_ranges_xics, .assign =3D spapr_irq_assign_xics, @@ -743,6 +745,7 @@ static const sPAPRPIrqRange spapr_irq_ranges_xive[] =3D= { =20 sPAPRIrq spapr_irq_xive =3D { .nr_irqs =3D 0x2000, + .ov5 =3D 0x40, /* XIVE exploitation mode only */ .init =3D spapr_irq_init_xive, .ranges =3D spapr_irq_ranges_xive, .assign =3D spapr_irq_assign_xive, --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528387865152864.62532589615; Thu, 7 Jun 2018 09:11:05 -0700 (PDT) Received: from localhost ([::1]:58910 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxV9-000572-Gx for importer@patchew.org; Thu, 07 Jun 2018 12:11:03 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39285) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxCz-0002zt-B3 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:19 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxCu-0004Jx-J3 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:17 -0400 Received: from 9.mo69.mail-out.ovh.net ([46.105.56.78]:48847) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxCu-0004J7-92 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:12 -0400 Received: from player169.ha.ovh.net (unknown [10.109.122.104]) by mo69.mail-out.ovh.net (Postfix) with ESMTP id EB68F186AC for ; Thu, 7 Jun 2018 17:52:10 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 877BD5800B6; Thu, 7 Jun 2018 17:52:05 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:56 +0200 Message-Id: <20180607155003.1580-22-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6100688646238735187 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.56.78 Subject: [Qemu-devel] [PATCH v4 21/28] spapr: add classes for the XIVE models 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The XIVE models for TCG and KVM will have a lot in common. Introduce some classes to handle the differences, mostly to synchronize the state with KVM for the monitor and migration. This is very much like the XICS models. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/spapr_xive.h | 13 ++++++++ include/hw/ppc/xive.h | 29 +++++++++++++++++ hw/intc/spapr_xive.c | 32 ++++++++++++++++++ hw/intc/xive.c | 79 +++++++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 153 insertions(+) diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index 3cbf8dbefb87..1284784f1152 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -38,6 +38,19 @@ typedef struct sPAPRXive { MemoryRegion tm_mmio; } sPAPRXive; =20 +#define SPAPR_XIVE_CLASS(klass) \ + OBJECT_CLASS_CHECK(sPAPRXiveClass, (klass), TYPE_SPAPR_XIVE) +#define SPAPR_XIVE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(sPAPRXiveClass, (obj), TYPE_SPAPR_XIVE) + +typedef struct sPAPRXiveClass { + XiveRouterClass parent_class; + + void (*synchronize_state)(sPAPRXive *xive); + void (*pre_save)(sPAPRXive *xsrc); + int (*post_load)(sPAPRXive *xsrc, int version_id); +} sPAPRXiveClass; + bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn, bool lsi); bool spapr_xive_irq_disable(sPAPRXive *xive, uint32_t lisn); void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon); diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index 378bd61c6d18..d943770efd9d 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -68,6 +68,20 @@ typedef struct XiveSource { XiveFabric *xive; } XiveSource; =20 +#define XIVE_SOURCE_CLASS(klass) \ + OBJECT_CLASS_CHECK(XiveSourceClass, (klass), TYPE_XIVE_SOURCE) +#define XIVE_SOURCE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(XiveSourceClass, (obj), TYPE_XIVE_SOURCE) + +typedef struct XiveSourceClass { + SysBusDeviceClass parent_class; + + void (*synchronize_state)(XiveSource *xsrc); + void (*reset)(XiveSource *xsrc); + void (*pre_save)(XiveSource *xsrc); + int (*post_load)(XiveSource *xsrc, int version_id); +} XiveSourceClass; + /* * ESB MMIO setting. Can be one page, for both source triggering and * source management, or two different pages. See below for magic @@ -275,6 +289,21 @@ typedef struct XiveTCTX { XiveRouter *xrtr; } XiveTCTX; =20 +#define XIVE_TCTX_CLASS(klass) \ + OBJECT_CLASS_CHECK(XiveTCTXClass, (klass), TYPE_XIVE_TCTX) +#define XIVE_TCTX_GET_CLASS(obj) \ + OBJECT_GET_CLASS(XiveTCTXClass, (obj), TYPE_XIVE_TCTX) + +typedef struct XiveTCTXClass { + DeviceClass parent_class; + + void (*realize)(XiveTCTX *tctx, Error **errp); + void (*synchronize_state)(XiveTCTX *tctx); + void (*reset)(XiveTCTX *tctx); + void (*pre_save)(XiveTCTX *tctx); + int (*post_load)(XiveTCTX *tctx, int version_id); +} XiveTCTXClass; + /* * XIVE Thread Interrupt Management Aera (TIMA) */ diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 222c1266a547..91f9b28ebcc4 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -27,8 +27,13 @@ =20 void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon) { + sPAPRXiveClass *sxc =3D SPAPR_XIVE_GET_CLASS(xive); int i; =20 + if (sxc->synchronize_state) { + sxc->synchronize_state(xive); + } + xive_source_pic_print_info(&xive->source, 0, mon); =20 monitor_printf(mon, "IVE Table\n"); @@ -279,6 +284,30 @@ static const VMStateDescription vmstate_spapr_xive_eq = =3D { }, }; =20 +static int vmstate_spapr_xive_pre_save(void *opaque) +{ + sPAPRXive *xive =3D opaque; + sPAPRXiveClass *sxc =3D SPAPR_XIVE_GET_CLASS(xive); + + if (sxc->pre_save) { + sxc->pre_save(xive); + } + + return 0; +} + +static int vmstate_spapr_xive_post_load(void *opaque, int version_id) +{ + sPAPRXive *xive =3D opaque; + sPAPRXiveClass *sxc =3D SPAPR_XIVE_GET_CLASS(xive); + + if (sxc->post_load) { + sxc->post_load(xive, version_id); + } + + return 0; +} + static const VMStateDescription vmstate_spapr_xive_ive =3D { .name =3D TYPE_SPAPR_XIVE "/ive", .version_id =3D 1, @@ -293,6 +322,8 @@ static const VMStateDescription vmstate_spapr_xive =3D { .name =3D TYPE_SPAPR_XIVE, .version_id =3D 1, .minimum_version_id =3D 1, + .pre_save =3D vmstate_spapr_xive_pre_save, + .post_load =3D vmstate_spapr_xive_post_load, .fields =3D (VMStateField[]) { VMSTATE_UINT32_EQUAL(nr_irqs, sPAPRXive, NULL), VMSTATE_STRUCT_VARRAY_POINTER_UINT32(ivt, sPAPRXive, nr_irqs, @@ -336,6 +367,7 @@ static const TypeInfo spapr_xive_info =3D { .instance_init =3D spapr_xive_instance_init, .instance_size =3D sizeof(sPAPRXive), .class_init =3D spapr_xive_class_init, + .class_size =3D sizeof(sPAPRXiveClass), }; =20 static void spapr_xive_register_types(void) diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 8d86f739522d..5cf9fc4e1cb3 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -438,9 +438,14 @@ static const struct { =20 void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon) { + XiveTCTXClass *xtc =3D XIVE_TCTX_GET_CLASS(tctx); int cpu_index =3D tctx->cs ? tctx->cs->cpu_index : -1; int i; =20 + if (xtc->synchronize_state) { + xtc->synchronize_state(tctx); + } + monitor_printf(mon, "CPU[%04x]: QW NSR CPPR IPB LSMFB ACK# INC AGE= PIPR" " W2\n", cpu_index); =20 @@ -486,6 +491,7 @@ static uint32_t xive_tctx_hw_cam(XiveTCTX *tctx, bool b= lock_group) static void xive_tctx_reset(void *dev) { XiveTCTX *tctx =3D XIVE_TCTX(dev); + XiveTCTXClass *xtc =3D XIVE_TCTX_GET_CLASS(tctx); PowerPCCPU *cpu =3D POWERPC_CPU(tctx->cs); CPUPPCState *env =3D &cpu->env; =20 @@ -512,11 +518,16 @@ static void xive_tctx_reset(void *dev) TM_QW1W2_VO | tctx_cam_line(tctx->xrtr->chip_id, cpu->vcpu_id)= ); memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &os_cam, 4); } + + if (xtc->reset) { + xtc->reset(tctx); + } } =20 static void xive_tctx_realize(DeviceState *dev, Error **errp) { XiveTCTX *tctx =3D XIVE_TCTX(dev); + XiveTCTXClass *xtc =3D XIVE_TCTX_GET_CLASS(tctx); PowerPCCPU *cpu; CPUPPCState *env; Object *obj; @@ -552,6 +563,10 @@ static void xive_tctx_realize(DeviceState *dev, Error = **errp) return; } =20 + if (xtc->realize) { + xtc->realize(tctx, errp); + } + qemu_register_reset(xive_tctx_reset, dev); } =20 @@ -560,10 +575,36 @@ static void xive_tctx_unrealize(DeviceState *dev, Err= or **errp) qemu_unregister_reset(xive_tctx_reset, dev); } =20 +static int vmstate_xive_tctx_pre_save(void *opaque) +{ + XiveTCTX *tctx =3D opaque; + XiveTCTXClass *xnc =3D XIVE_TCTX_GET_CLASS(tctx); + + if (xnc->pre_save) { + xnc->pre_save(tctx); + } + + return 0; +} + +static int vmstate_xive_tctx_post_load(void *opaque, int version_id) +{ + XiveTCTX *tctx =3D opaque; + XiveTCTXClass *xnc =3D XIVE_TCTX_GET_CLASS(tctx); + + if (xnc->post_load) { + xnc->post_load(tctx, version_id); + } + + return 0; +} + static const VMStateDescription vmstate_xive_tctx =3D { .name =3D TYPE_XIVE_TCTX, .version_id =3D 1, .minimum_version_id =3D 1, + .pre_save =3D vmstate_xive_tctx_pre_save, + .post_load =3D vmstate_xive_tctx_post_load, .fields =3D (VMStateField[]) { VMSTATE_BUFFER(regs, XiveTCTX), VMSTATE_END_OF_LIST() @@ -585,6 +626,7 @@ static const TypeInfo xive_tctx_info =3D { .parent =3D TYPE_DEVICE, .instance_size =3D sizeof(XiveTCTX), .class_init =3D xive_tctx_class_init, + .class_size =3D sizeof(XiveTCTXClass), }; =20 Object *xive_tctx_create(Object *cpu, const char *type, XiveRouter *xrtr, @@ -922,8 +964,13 @@ static void xive_source_set_irq(void *opaque, int srcn= o, int val) =20 void xive_source_pic_print_info(XiveSource *xsrc, uint32_t offset, Monitor= *mon) { + XiveSourceClass *xsc =3D XIVE_SOURCE_GET_CLASS(xsrc); int i; =20 + if (xsc->synchronize_state) { + xsc->synchronize_state(xsrc); + } + monitor_printf(mon, "XIVE Source %8x ..%8x\n", offset, offset + xsrc->nr_irqs - 1); for (i =3D 0; i < xsrc->nr_irqs; i++) { @@ -944,11 +991,16 @@ void xive_source_pic_print_info(XiveSource *xsrc, uin= t32_t offset, Monitor *mon) static void xive_source_reset(DeviceState *dev) { XiveSource *xsrc =3D XIVE_SOURCE(dev); + XiveSourceClass *xsc =3D XIVE_SOURCE_GET_CLASS(xsrc); =20 /* Do not clear the LSI bitmap */ =20 /* PQs are initialized to 0b01 which corresponds to "ints off" */ memset(xsrc->status, 0x1, xsrc->nr_irqs); + + if (xsc->reset) { + xsc->reset(xsrc); + } } =20 static void xive_source_realize(DeviceState *dev, Error **errp) @@ -993,10 +1045,36 @@ static void xive_source_realize(DeviceState *dev, Er= ror **errp) sysbus_init_mmio(SYS_BUS_DEVICE(dev), &xsrc->esb_mmio); } =20 +static int vmstate_xive_source_pre_save(void *opaque) +{ + XiveSource *xsrc =3D opaque; + XiveSourceClass *xsc =3D XIVE_SOURCE_GET_CLASS(xsrc); + + if (xsc->pre_save) { + xsc->pre_save(xsrc); + } + + return 0; +} + +static int vmstate_xive_source_post_load(void *opaque, int version_id) +{ + XiveSource *xsrc =3D opaque; + XiveSourceClass *xsc =3D XIVE_SOURCE_GET_CLASS(xsrc); + + if (xsc->post_load) { + xsc->post_load(xsrc, version_id); + } + + return 0; +} + static const VMStateDescription vmstate_xive_source =3D { .name =3D TYPE_XIVE_SOURCE, .version_id =3D 1, .minimum_version_id =3D 1, + .pre_save =3D vmstate_xive_source_pre_save, + .post_load =3D vmstate_xive_source_post_load, .fields =3D (VMStateField[]) { VMSTATE_UINT32_EQUAL(nr_irqs, XiveSource, NULL), VMSTATE_VBUFFER_UINT32(status, XiveSource, 1, NULL, nr_irqs), @@ -1032,6 +1110,7 @@ static const TypeInfo xive_source_info =3D { .parent =3D TYPE_SYS_BUS_DEVICE, .instance_size =3D sizeof(XiveSource), .class_init =3D xive_source_class_init, + .class_size =3D sizeof(XiveSourceClass), }; =20 /* --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 152838811889363.554135581876494; Thu, 7 Jun 2018 09:15:18 -0700 (PDT) Received: from localhost ([::1]:58935 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxZC-0000yi-8C for importer@patchew.org; Thu, 07 Jun 2018 12:15:14 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39314) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxD4-00035A-R4 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxD0-0004N4-4K for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:22 -0400 Received: from 6.mo2.mail-out.ovh.net ([87.98.165.38]:32954) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxCz-0004MD-RT for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:18 -0400 Received: from player169.ha.ovh.net (unknown [10.109.122.15]) by mo2.mail-out.ovh.net (Postfix) with ESMTP id 671C613BC16 for ; Thu, 7 Jun 2018 17:52:16 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 02F6B5800A3; Thu, 7 Jun 2018 17:52:10 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:57 +0200 Message-Id: <20180607155003.1580-23-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6102377497870830419 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 87.98.165.38 Subject: [Qemu-devel] [PATCH v4 22/28] target/ppc/kvm: add Linux KVM definitions for XIVE 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" These definitions add a new capability and a new KVM device for the XIVE native exploitation interrupt mode. New ioctls are also introduced to initialize the KVM device and to capture/restore the VM state for migration. Signed-off-by: C=C3=A9dric Le Goater --- linux-headers/asm-powerpc/kvm.h | 23 +++++++++++++++++++++++ linux-headers/linux/kvm.h | 3 +++ target/ppc/kvm_ppc.h | 6 ++++++ target/ppc/kvm.c | 7 +++++++ 4 files changed, 39 insertions(+) diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kv= m.h index 833ed9a16adf..27f3dae65761 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -480,6 +480,16 @@ struct kvm_ppc_cpu_char { #define KVM_REG_PPC_ICP_PPRI_SHIFT 16 /* pending irq priority */ #define KVM_REG_PPC_ICP_PPRI_MASK 0xff =20 +#define KVM_REG_PPC_VP_STATE (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x8d) +#define KVM_REG_PPC_VP_EQ0 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x8e) +#define KVM_REG_PPC_VP_EQ1 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x8f) +#define KVM_REG_PPC_VP_EQ2 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x90) +#define KVM_REG_PPC_VP_EQ3 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x91) +#define KVM_REG_PPC_VP_EQ4 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x92) +#define KVM_REG_PPC_VP_EQ5 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x93) +#define KVM_REG_PPC_VP_EQ6 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x94) +#define KVM_REG_PPC_VP_EQ7 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x95) + /* Device control API: PPC-specific devices */ #define KVM_DEV_MPIC_GRP_MISC 1 #define KVM_DEV_MPIC_BASE_ADDR 0 /* 64-bit */ @@ -673,4 +683,17 @@ struct kvm_ppc_cpu_char { #define KVM_XICS_PRESENTED (1ULL << 43) #define KVM_XICS_QUEUED (1ULL << 44) =20 +/* POWER9 XIVE Interrupt Controller */ +#define KVM_DEV_XIVE_GRP_SOURCES 1 /* 64-bit source attributes */ +#define KVM_DEV_XIVE_GRP_CTRL 2 +#define KVM_DEV_XIVE_GET_ESB_FD 1 +#define KVM_DEV_XIVE_GET_TIMA_FD 2 +#define KVM_DEV_XIVE_VC_BASE 3 +#define KVM_DEV_XIVE_GRP_IVE 3 /* 64-bit source attributes */ +#define KVM_DEV_XIVE_GRP_SYNC 4 /* 64-bit source attributes */ + +/* Layout of 64-bit XIVE source attribute values */ +#define KVM_XIVE_LEVEL_SENSITIVE (1ULL << 0) +#define KVM_XIVE_LEVEL_ASSERTED (1ULL << 1) + #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index cdb148e959eb..634a24e92b03 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -948,6 +948,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_S390_BPB 152 #define KVM_CAP_GET_MSR_FEATURES 153 #define KVM_CAP_HYPERV_EVENTFD 154 +#define KVM_CAP_PPC_IRQ_XIVE 155 =20 #ifdef KVM_CAP_IRQ_ROUTING =20 @@ -1171,6 +1172,8 @@ enum kvm_device_type { #define KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_ITS, #define KVM_DEV_TYPE_ARM_VGIC_ITS KVM_DEV_TYPE_ARM_VGIC_ITS + KVM_DEV_TYPE_XIVE, +#define KVM_DEV_TYPE_XIVE KVM_DEV_TYPE_XIVE KVM_DEV_TYPE_MAX, }; =20 diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index e2840e1d33e8..52f25bfb03b9 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -59,6 +59,7 @@ bool kvmppc_has_cap_fixup_hcalls(void); bool kvmppc_has_cap_htm(void); bool kvmppc_has_cap_mmu_radix(void); bool kvmppc_has_cap_mmu_hash_v3(void); +bool kvmppc_has_cap_xive(void); int kvmppc_get_cap_safe_cache(void); int kvmppc_get_cap_safe_bounds_check(void); int kvmppc_get_cap_safe_indirect_branch(void); @@ -293,6 +294,11 @@ static inline bool kvmppc_has_cap_mmu_hash_v3(void) return false; } =20 +static inline bool kvmppc_has_cap_xive(void) +{ + return false; +} + static inline int kvmppc_get_cap_safe_cache(void) { return 0; diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 2c0c34e125e4..09e4c1efdf79 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -86,6 +86,7 @@ static int cap_fixup_hcalls; static int cap_htm; /* Hardware transactional memory support */ static int cap_mmu_radix; static int cap_mmu_hash_v3; +static int cap_xive; static int cap_resize_hpt; static int cap_ppc_pvr_compat; static int cap_ppc_safe_cache; @@ -148,6 +149,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_htm =3D kvm_vm_check_extension(s, KVM_CAP_PPC_HTM); cap_mmu_radix =3D kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_RADIX); cap_mmu_hash_v3 =3D kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3); + cap_xive =3D kvm_vm_check_extension(s, KVM_CAP_PPC_IRQ_XIVE); cap_resize_hpt =3D kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT); kvmppc_get_cpu_characteristics(s); /* @@ -2447,6 +2449,11 @@ static int parse_cap_ppc_safe_indirect_branch(struct= kvm_ppc_cpu_char c) return 0; } =20 +bool kvmppc_has_cap_xive(void) +{ + return cap_xive; +} + static void kvmppc_get_cpu_characteristics(KVMState *s) { struct kvm_ppc_cpu_char c; --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528388009758620.0563814321844; Thu, 7 Jun 2018 09:13:29 -0700 (PDT) Received: from localhost ([::1]:58925 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxXU-0007Bj-TB for importer@patchew.org; Thu, 07 Jun 2018 12:13:28 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39352) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxDA-0003AZ-8u for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxD5-0004Q9-Hs for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:28 -0400 Received: from 8.mo1.mail-out.ovh.net ([178.33.110.239]:53848) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxD5-0004PE-Bq for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:23 -0400 Received: from player169.ha.ovh.net (unknown [10.109.120.103]) by mo1.mail-out.ovh.net (Postfix) with ESMTP id D5F92105B52 for ; Thu, 7 Jun 2018 17:52:21 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 7205E5800B6; Thu, 7 Jun 2018 17:52:16 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:58 +0200 Message-Id: <20180607155003.1580-24-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6103784870269586259 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 178.33.110.239 Subject: [Qemu-devel] [PATCH v4 23/28] spapr/xive: add common realize routine for KVM 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The XiveSource and sPAPRXive device models will be shared between the TCG and the KVM mode. The difference will reside in the way the memory regions are initialized and in the qemu_irq handler. Introduce common realize routines to share some code. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/spapr_xive.h | 1 + include/hw/ppc/xive.h | 3 +++ hw/intc/spapr_xive.c | 15 +++++++++++++-- hw/intc/xive.c | 22 +++++++++++++++++----- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index 1284784f1152..4aa04bc48ccb 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -55,6 +55,7 @@ bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn= , bool lsi); bool spapr_xive_irq_disable(sPAPRXive *xive, uint32_t lisn); void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon); qemu_irq spapr_xive_qirq(sPAPRXive *xive, uint32_t lisn); +void spapr_xive_common_realize(sPAPRXive *xive, Error **errp); =20 /* * sPAPR VP and EQ indexing helpers diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index d943770efd9d..7a54b3ce594f 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -183,6 +183,9 @@ static inline void xive_source_irq_set(XiveSource *xsrc= , uint32_t srcno, } } =20 +void xive_source_common_realize(XiveSource *xsrc, qemu_irq_handler handler, + Error **errp); + /* * XIVE Router */ diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 91f9b28ebcc4..2812b1a1a030 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -84,9 +84,8 @@ static void spapr_xive_instance_init(Object *obj) object_property_add_child(obj, "eq_source", OBJECT(&xive->eq_source), = NULL); } =20 -static void spapr_xive_realize(DeviceState *dev, Error **errp) +void spapr_xive_common_realize(sPAPRXive *xive, Error **errp) { - sPAPRXive *xive =3D SPAPR_XIVE(dev); XiveSource *xsrc =3D &xive->source; XiveEQSource *eq_xsrc =3D &xive->eq_source; Error *local_err =3D NULL; @@ -132,6 +131,18 @@ static void spapr_xive_realize(DeviceState *dev, Error= **errp) /* Allocate the routing tables */ xive->ivt =3D g_new0(XiveIVE, xive->nr_irqs); xive->eqdt =3D g_new0(XiveEQ, xive->nr_eqs); +} + +static void spapr_xive_realize(DeviceState *dev, Error **errp) +{ + sPAPRXive *xive =3D SPAPR_XIVE(dev); + Error *local_err =3D NULL; + + spapr_xive_common_realize(xive, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } =20 /* TIMA */ memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &xive_tm_ops, xive, diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 5cf9fc4e1cb3..4d073c37bbda 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -1003,13 +1003,13 @@ static void xive_source_reset(DeviceState *dev) } } =20 -static void xive_source_realize(DeviceState *dev, Error **errp) +void xive_source_common_realize(XiveSource *xsrc, qemu_irq_handler handler, + Error **errp) { - XiveSource *xsrc =3D XIVE_SOURCE(dev); Object *obj; Error *local_err =3D NULL; =20 - obj =3D object_property_get_link(OBJECT(dev), "xive", &local_err); + obj =3D object_property_get_link(OBJECT(xsrc), "xive", &local_err); if (!obj) { error_propagate(errp, local_err); error_prepend(errp, "required link 'xive' not found: "); @@ -1031,14 +1031,26 @@ static void xive_source_realize(DeviceState *dev, E= rror **errp) return; } =20 - xsrc->qirqs =3D qemu_allocate_irqs(xive_source_set_irq, xsrc, - xsrc->nr_irqs); + xsrc->qirqs =3D qemu_allocate_irqs(handler, xsrc, xsrc->nr_irqs); =20 xsrc->status =3D g_malloc0(xsrc->nr_irqs); =20 xsrc->lsi_map =3D bitmap_new(xsrc->nr_irqs); xsrc->lsi_map_size =3D xsrc->nr_irqs; =20 +} + +static void xive_source_realize(DeviceState *dev, Error **errp) +{ + XiveSource *xsrc =3D XIVE_SOURCE(dev); + Error *local_err =3D NULL; + + xive_source_common_realize(xsrc, xive_source_set_irq, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + memory_region_init_io(&xsrc->esb_mmio, OBJECT(xsrc), &xive_source_esb_ops, xsrc, "xive.esb", (1ull << xsrc->esb_shift) * xsrc->nr_irqs); --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528388309353590.1778305191756; Thu, 7 Jun 2018 09:18:29 -0700 (PDT) Received: from localhost ([::1]:58977 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxcB-0004Hh-GD for importer@patchew.org; Thu, 07 Jun 2018 12:18:19 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39396) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxDG-0003FJ-2A for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:37 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxDB-0004T3-A2 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:34 -0400 Received: from 4.mo68.mail-out.ovh.net ([46.105.59.63]:57356) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxDA-0004SS-TY for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:29 -0400 Received: from player169.ha.ovh.net (unknown [10.109.105.112]) by mo68.mail-out.ovh.net (Postfix) with ESMTP id 5C56FE6A4C for ; Thu, 7 Jun 2018 17:52:27 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id E02735800A4; Thu, 7 Jun 2018 17:52:21 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:49:59 +0200 Message-Id: <20180607155003.1580-25-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6105473720927554387 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.59.63 Subject: [Qemu-devel] [PATCH v4 24/28] spapr/xive: add KVM support 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" This introduces a set of XIVE models specific to KVM. They handle the initialization and the state synchronization with KVM, for the monitor usage and for the migration. The TIMA and the source ESB memory regions are initialized differently under KVM. 'ram device' memory mappings, similarly to VFIO, are exposed to the guest and the associated VMAs on the host are populated dynamically with the appropriate pages using a fault handler. Migration needs to follow a specific sequence to make sure the different internal states are captured correctly. This is why we raise the sPAPRXive KVM model migration priority to make sure its pre_save handler runs before the other XIVE models' pre_save. sPAPRXive pre_save starts by masking all the sources to quiesce the interrupt flow and perform a XIVE xync to stabilize the EQs. The EQs are then masked to stop notifications to a VP and their state is captured. What is important is the EQ index and the toggle bit. Follows the capture of the state of the thread context. When done, a rollback is performed to restore the sources and the EQs to their initial state. Post_load is simpler and only needs to restore the different state in the correct order. The get/set operations rely on their KVM counterpart in the host kernel which acts as a proxy for OPAL, the host firmware. Extra quiescence points are possibly needed so the XIVE migration is currently work in progress. Signed-off-by: C=C3=A9dric Le Goater --- default-configs/ppc64-softmmu.mak | 1 + include/hw/ppc/spapr_xive.h | 20 + include/hw/ppc/xive.h | 3 + include/migration/vmstate.h | 1 + hw/intc/spapr_xive.c | 1 + hw/intc/spapr_xive_kvm.c | 809 ++++++++++++++++++++++++++++++++++= ++++ hw/ppc/spapr_irq.c | 29 +- hw/intc/Makefile.objs | 1 + 8 files changed, 855 insertions(+), 10 deletions(-) create mode 100644 hw/intc/spapr_xive_kvm.c diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-soft= mmu.mak index f8d34722931d..ac7e3af2473c 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -18,4 +18,5 @@ CONFIG_XICS_SPAPR=3D$(CONFIG_PSERIES) CONFIG_XICS_KVM=3D$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) CONFIG_XIVE=3D$(CONFIG_PSERIES) CONFIG_XIVE_SPAPR=3D$(CONFIG_PSERIES) +CONFIG_XIVE_KVM=3D$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) CONFIG_MEM_HOTPLUG=3Dy diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index 4aa04bc48ccb..f3e9208ad1f3 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -36,6 +36,10 @@ typedef struct sPAPRXive { /* TIMA mapping address */ hwaddr tm_base; MemoryRegion tm_mmio; + + /* KVM support */ + int fd; + void *tm_mmap; } sPAPRXive; =20 #define SPAPR_XIVE_CLASS(klass) \ @@ -79,4 +83,20 @@ void spapr_xive_hcall_init(sPAPRMachineState *spapr); void spapr_dt_xive(sPAPRXive *xive, int nr_servers, void *fdt, uint32_t phandle); =20 +/* + * XIVE KVM models + */ + +#define TYPE_SPAPR_XIVE_KVM "spapr-xive-kvm" +#define SPAPR_XIVE_KVM(obj) \ + OBJECT_CHECK(sPAPRXive, (obj), TYPE_SPAPR_XIVE_KVM) + +#define TYPE_XIVE_SOURCE_KVM "xive-source-kvm" +#define XIVE_SOURCE_KVM(obj) \ + OBJECT_CHECK(XiveSource, (obj), TYPE_XIVE_SOURCE_KVM) + +#define TYPE_XIVE_TCTX_KVM "xive-tctx-kvm" +#define XIVE_TCTX_KVM(obj) \ + OBJECT_CHECK(XiveTCTX, (obj), TYPE_XIVE_TCTX_KVM) + #endif /* PPC_SPAPR_XIVE_H */ diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index 7a54b3ce594f..a2c1cc6b5126 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -65,6 +65,9 @@ typedef struct XiveSource { uint32_t esb_shift; MemoryRegion esb_mmio; =20 + /* KVM support */ + void *esb_mmap; + XiveFabric *xive; } XiveSource; =20 diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 3747110f951a..b707c31b1b0c 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -156,6 +156,7 @@ typedef enum { MIG_PRI_PCI_BUS, /* Must happen before IOMMU */ MIG_PRI_GICV3_ITS, /* Must happen before PCI devices */ MIG_PRI_GICV3, /* Must happen before the ITS */ + MIG_PRI_XIVE_IC, /* Must happen before XIVE thread context = */ MIG_PRI_MAX, } MigrationPriority; =20 diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 2812b1a1a030..4eebba5ab8e7 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -335,6 +335,7 @@ static const VMStateDescription vmstate_spapr_xive =3D { .minimum_version_id =3D 1, .pre_save =3D vmstate_spapr_xive_pre_save, .post_load =3D vmstate_spapr_xive_post_load, + .priority =3D MIG_PRI_XIVE_IC, .fields =3D (VMStateField[]) { VMSTATE_UINT32_EQUAL(nr_irqs, sPAPRXive, NULL), VMSTATE_STRUCT_VARRAY_POINTER_UINT32(ivt, sPAPRXive, nr_irqs, diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c new file mode 100644 index 000000000000..8b0d5d693e27 --- /dev/null +++ b/hw/intc/spapr_xive_kvm.c @@ -0,0 +1,809 @@ +/* + * QEMU PowerPC sPAPR XIVE interrupt controller model + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "target/ppc/cpu.h" +#include "sysemu/cpus.h" +#include "sysemu/kvm.h" +#include "monitor/monitor.h" +#include "hw/ppc/spapr.h" +#include "hw/ppc/spapr_xive.h" +#include "hw/ppc/xive.h" +#include "hw/ppc/xive_regs.h" +#include "kvm_ppc.h" + +#include + +/* + * Helpers for CPU hotplug + */ +typedef struct KVMEnabledCPU { + unsigned long vcpu_id; + QLIST_ENTRY(KVMEnabledCPU) node; +} KVMEnabledCPU; + +static QLIST_HEAD(, KVMEnabledCPU) + kvm_enabled_cpus =3D QLIST_HEAD_INITIALIZER(&kvm_enabled_cpus); + +static bool xive_tctx_kvm_cpu_is_enabled(CPUState *cs) +{ + KVMEnabledCPU *enabled_cpu; + unsigned long vcpu_id =3D kvm_arch_vcpu_id(cs); + + QLIST_FOREACH(enabled_cpu, &kvm_enabled_cpus, node) { + if (enabled_cpu->vcpu_id =3D=3D vcpu_id) { + return true; + } + } + return false; +} + +static void xive_tctx_kvm_cpu_enable(CPUState *cs) +{ + KVMEnabledCPU *enabled_cpu; + unsigned long vcpu_id =3D kvm_arch_vcpu_id(cs); + + enabled_cpu =3D g_malloc(sizeof(*enabled_cpu)); + enabled_cpu->vcpu_id =3D vcpu_id; + QLIST_INSERT_HEAD(&kvm_enabled_cpus, enabled_cpu, node); +} + +/* + * XIVE Thread Interrupt Management context (KVM) + */ +static int xive_tctx_kvm_get_state(XiveTCTX *tctx) +{ + uint64_t state[4] =3D { 0 }; + int ret; + + ret =3D kvm_get_one_reg(tctx->cs, KVM_REG_PPC_VP_STATE, state); + if (ret !=3D 0) { + error_report("Unable to retrieve KVM XIVE interrupt controller sta= te" + " for CPU %ld: %s", kvm_arch_vcpu_id(tctx->cs), + strerror(errno)); + return ret; + } + + /* + * First quad is word0 and word1 of the OS ring. Second quad is + * the OPAL internal state which holds word4 of the VP + * structure. We are only interested by the IPB in there but we + * should consider it as opaque. + * + * As we won't use the registers of the HV ring on sPAPR, let's + * hijack them to store the 'OPAL' state + */ + *((uint64_t *) &tctx->regs[TM_QW1_OS]) =3D state[0]; + *((uint64_t *) &tctx->regs[TM_QW2_HV_POOL]) =3D state[1]; + + /* + * KVM also returns word2 containing the VP CAM value which is + * interesting to print out in the QEMU monitor but we don't + * restore it. + */ + *((uint64_t *) &tctx->regs[TM_QW1_OS + TM_WORD2]) =3D state[2]; + + return 0; +} + +static void xive_tctx_kvm_do_synchronize_state(CPUState *cpu, + run_on_cpu_data arg) +{ + xive_tctx_kvm_get_state(arg.host_ptr); +} + +static void xive_tctx_kvm_synchronize_state(XiveTCTX *tctx) +{ + run_on_cpu(tctx->cs, xive_tctx_kvm_do_synchronize_state, + RUN_ON_CPU_HOST_PTR(tctx)); +} + +static int xive_tctx_kvm_post_load(XiveTCTX *tctx, int version_id) +{ + uint64_t state[4]; + int ret; + + state[0] =3D *((uint64_t *) &tctx->regs[TM_QW1_OS]); + state[1] =3D *((uint64_t *) &tctx->regs[TM_QW2_HV_POOL]); + + ret =3D kvm_set_one_reg(tctx->cs, KVM_REG_PPC_VP_STATE, state); + if (ret !=3D 0) { + error_report("Unable to restore KVM XIVE interrupt controller stat= e" + " for CPU %ld: %s", kvm_arch_vcpu_id(tctx->cs), + strerror(errno)); + } + return ret; +} + +static void xive_tctx_kvm_realize(XiveTCTX *tctx, Error **errp) +{ + sPAPRXive *xive =3D SPAPR_XIVE(tctx->xrtr); + CPUState *cs =3D tctx->cs; + unsigned long vcpu_id =3D kvm_arch_vcpu_id(cs); + int ret; + + /* Check if CPU was hot unplugged and replugged. */ + if (xive_tctx_kvm_cpu_is_enabled(cs)) { + return; + } + + ret =3D kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_IRQ_XIVE, 0, xive->fd, + vcpu_id, 0); + if (ret < 0) { + error_setg(errp, "Unable to connect CPU%ld to KVM XIVE device: %s", + vcpu_id, strerror(errno)); + return; + } + + xive_tctx_kvm_cpu_enable(cs); +} + +static void xive_tctx_kvm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + XiveTCTXClass *xnc =3D XIVE_TCTX_CLASS(klass); + + dc->desc =3D "sPAPR XIVE KVM Interrupt Thread Context"; + + xnc->realize =3D xive_tctx_kvm_realize; + xnc->synchronize_state =3D xive_tctx_kvm_synchronize_state; + xnc->post_load =3D xive_tctx_kvm_post_load; +} + +static const TypeInfo xive_tctx_kvm_info =3D { + .name =3D TYPE_XIVE_TCTX_KVM, + .parent =3D TYPE_XIVE_TCTX, + .instance_size =3D sizeof(XiveTCTX), + .class_init =3D xive_tctx_kvm_class_init, + .class_size =3D sizeof(XiveTCTXClass), +}; + +/* + * XIVE Interrupt Source (KVM) + */ +static void xive_source_kvm_reset(XiveSource *xsrc) +{ + sPAPRXive *xive =3D SPAPR_XIVE_KVM(xsrc->xive); + int i; + + /* + * At reset, interrupt sources are simply created and MASKED. We + * only need to inform the KVM device about their type: LSI or + * MSI. + */ + for (i =3D 0; i < xsrc->nr_irqs; i++) { + Error *err =3D NULL; + uint64_t state =3D 0; + + if (xive_source_irq_is_lsi(xsrc, i)) { + state |=3D KVM_XIVE_LEVEL_SENSITIVE; + if (xsrc->status[i] & XIVE_STATUS_ASSERTED) { + state |=3D KVM_XIVE_LEVEL_ASSERTED; + } + } + + kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCES, + i, &state, true, &err); + if (err) { + error_report_err(err); + return; + } + } +} + +/* + * This is used to perform the magic loads from an ESB described in + * xive.h. + */ +static uint8_t xive_esb_read(XiveSource *xsrc, int srcno, uint32_t offset) +{ + unsigned long addr =3D (unsigned long) xsrc->esb_mmap + + xive_source_esb_mgmt(xsrc, srcno) + offset; + + return *((uint8_t *) addr); +} + +static void xive_source_kvm_get_state(XiveSource *xsrc) +{ + int i; + + for (i =3D 0; i < xsrc->nr_irqs; i++) { + /* Perform a load without side effect to retrieve the PQ bits */ + uint8_t pq =3D xive_esb_read(xsrc, i, XIVE_ESB_GET); + + /* and save PQ locally */ + xive_source_esb_set(xsrc, i, pq); + } +} + +static void xive_source_kvm_synchronize_state(XiveSource *xsrc) +{ + xive_source_kvm_get_state(xsrc); +} + +static int xive_source_kvm_post_load(XiveSource *xsrc, int version_id) +{ + int i; + int unused =3D 0; + + for (i =3D 0; i < xsrc->nr_irqs; i++) { + uint8_t pq =3D xive_source_esb_get(xsrc, i); + + /* TODO: prevent the compiler from optimizing away the load */ + unused |=3D xive_esb_read(xsrc, i, XIVE_ESB_SET_PQ_00 + (pq << 8)); + } + + return unused; +} + +static void xive_source_kvm_set_irq(void *opaque, int srcno, int val) +{ + XiveSource *xsrc =3D opaque; + struct kvm_irq_level args; + int rc; + + args.irq =3D srcno; + if (!xive_source_irq_is_lsi(xsrc, srcno)) { + if (!val) { + return; + } + args.level =3D KVM_INTERRUPT_SET; + } else { + args.level =3D val ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET; + } + rc =3D kvm_vm_ioctl(kvm_state, KVM_IRQ_LINE, &args); + if (rc < 0) { + error_report("kvm_irq_line() failed : %s", strerror(errno)); + } +} + +static void *spapr_xive_kvm_mmap(sPAPRXive *xive, int ctrl, size_t len, + Error **errp) +{ + Error *local_err =3D NULL; + void *addr; + int fd; + + kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_CTRL, ctrl, &fd, false, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return NULL; + } + + addr =3D mmap(NULL, len, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0); + close(fd); + if (addr =3D=3D MAP_FAILED) { + error_setg_errno(errp, errno, "Unable to set XIVE mmaping"); + return NULL; + } + + return addr; +} + +/* + * The sPAPRXive KVM model should have initialized the KVM device + * before initializing the source + */ +static void xive_source_kvm_realize(DeviceState *dev, Error **errp) +{ + XiveSource *xsrc =3D XIVE_SOURCE_KVM(dev); + sPAPRXive *xive =3D NULL; + Error *local_err =3D NULL; + size_t esb_len; + + xive_source_common_realize(xsrc, xive_source_kvm_set_irq, errp); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + xive =3D SPAPR_XIVE_KVM(xsrc->xive); + + /* Map the source ESB pages */ + esb_len =3D (1ull << xsrc->esb_shift) * xsrc->nr_irqs; + xsrc->esb_mmap =3D spapr_xive_kvm_mmap(xive, KVM_DEV_XIVE_GET_ESB_FD, + esb_len, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + memory_region_init_ram_device_ptr(&xsrc->esb_mmio, OBJECT(xsrc), + "xive.esb", esb_len, xsrc->esb_mmap); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &xsrc->esb_mmio); +} + +static void xive_source_kvm_unrealize(DeviceState *dev, Error **errp) +{ + XiveSource *xsrc =3D XIVE_SOURCE_KVM(dev); + size_t esb_len =3D (1ull << xsrc->esb_shift) * xsrc->nr_irqs; + + munmap(xsrc->esb_mmap, esb_len); +} + +static void xive_source_kvm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + XiveSourceClass *xsc =3D XIVE_SOURCE_CLASS(klass); + + dc->desc =3D "sPAPR XIVE KVM Interrupt Source"; + dc->realize =3D xive_source_kvm_realize; + dc->unrealize =3D xive_source_kvm_unrealize; + + xsc->synchronize_state =3D xive_source_kvm_synchronize_state; + xsc->reset =3D xive_source_kvm_reset; + xsc->post_load =3D xive_source_kvm_post_load; +} + +static const TypeInfo xive_source_kvm_info =3D { + .name =3D TYPE_XIVE_SOURCE_KVM, + .parent =3D TYPE_XIVE_SOURCE, + .instance_size =3D sizeof(XiveSource), + .class_init =3D xive_source_kvm_class_init, + .class_size =3D sizeof(XiveSourceClass), +}; + +/* + * sPAPR XIVE Router (KVM) + */ +static int spapr_xive_kvm_set_eq_state(sPAPRXive *xive, CPUState *cs, bool= mask) +{ + XiveRouter *xrtr =3D XIVE_ROUTER(xive); + int ret; + int i; + + for (i =3D 0; i < XIVE_PRIORITY_MAX + 1; i++) { + XiveEQ eq; + uint8_t eq_blk; + uint32_t eq_idx; + + /* skip reserved EQs */ + if (!spapr_xive_eq_is_valid(i)) { + continue; + } + + spapr_xive_cpu_to_eq(xrtr, POWERPC_CPU(cs), i, &eq_blk, &eq_idx); + + ret =3D xive_router_get_eq(xrtr, eq_blk, eq_idx, &eq); + if (ret) { + error_report("XIVE: No EQ for CPU %ld priority %d", + kvm_arch_vcpu_id(cs), i); + return ret; + } + + if (!(eq.w0 & EQ_W0_VALID)) { + continue; + } + + /* If EQ is masked, all notification to the NVT will be stopped */ + if (mask) { + eq.w7 =3D SETFIELD(EQ_W7_F0_PRIORITY, 0ul, 0xFF); + } + + ret =3D kvm_set_one_reg(cs, KVM_REG_PPC_VP_EQ0 + i, &eq); + if (ret !=3D 0) { + error_report("KVM XIVE: failed to restore EQ state for CPU %ld= " + "priority %d: %s", kvm_arch_vcpu_id(cs), i, + strerror(errno)); + return ret; + } + } + + return 0; +} + +static int spapr_xive_kvm_get_eq_state(XiveRouter *xrtr, CPUState *cs) +{ + int ret; + int i; + + for (i =3D 0; i < XIVE_PRIORITY_MAX + 1; i++) { + XiveEQ eq =3D { 0 }; + uint8_t eq_blk; + uint32_t eq_idx; + + /* skip reserved EQs */ + if (!spapr_xive_eq_is_valid(i)) { + continue; + } + + ret =3D kvm_get_one_reg(cs, KVM_REG_PPC_VP_EQ0 + i, &eq); + if (ret !=3D 0) { + error_report("KVM XIVE: failed to save EQ state for CPU %ld " + "priority %d: %s", kvm_arch_vcpu_id(cs), i, + strerror(errno)); + return ret; + } + + if (!(eq.w0 & EQ_W0_VALID)) { + continue; + } + + spapr_xive_cpu_to_eq(xrtr, POWERPC_CPU(cs), i, &eq_blk, &eq_idx); + + ret =3D xive_router_set_eq(xrtr, eq_blk, eq_idx, &eq); + if (ret) { + error_report("XIVE: No EQ for CPU %ld priority %d", + kvm_arch_vcpu_id(cs), i); + return ret; + } + } + + return 0; +} + +static int spapr_xive_kvm_set_ive_state(sPAPRXive *xive) +{ + XiveSource *xsrc =3D &xive->source; + int i; + + for (i =3D 0; i < xsrc->nr_irqs; i++) { + XiveIVE *ive =3D &xive->ivt[i]; + Error *local_err =3D NULL; + + if (!(ive->w & IVE_VALID) || ive->w & IVE_MASKED) { + continue; + } + + kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_IVE, i, + ive, true, &local_err); + if (local_err) { + error_report_err(local_err); + return -1; + } + } + return 0; +} + +static void spapr_xive_kvm_get_ive_state(sPAPRXive *xive, Error **errp) +{ + XiveSource *xsrc =3D &xive->source; + Error *local_err =3D NULL; + int i; + + for (i =3D 0; i < xsrc->nr_irqs; i++) { + XiveIVE *ive =3D &xive->ivt[i]; + + if (!(ive->w & IVE_VALID)) { + continue; + } + + kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_IVE, i, + ive, false, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + } +} + +static void spapr_xive_kvm_sync_all(sPAPRXive *xive, Error **errp) +{ + XiveSource *xsrc =3D &xive->source; + Error *local_err =3D NULL; + int i; + + /* Quiesce the sources */ + for (i =3D 0; i < xsrc->nr_irqs; i++) { + XiveIVE *ive =3D &xive->ivt[i]; + + if (!(ive->w & IVE_VALID)) { + continue; + } + + /* Sync the source now in KVM */ + kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SYNC, i, + NULL, true, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + } +} + +/* + * XIVE save + * + * Migration needs to follow a specific sequence to make sure the + * different internal states are captured correctly. The sPAPRXive KVM + * model migration priority is higher to make sure its pre_save + * handler runs before the other XIVE models' pre_save. + * + * 1. mask all the sources by setting PQ=3D01, which returns the + * previous value and save it. + * 2. XIVE sync to stabilize the queues + * 3. Mask the EQs to stop VP notification (OPAL support) + * 4. XIVE sync again + * 5. Dump the EQs + * 6. Dump the thread context (IPB) + * + * Rollback to restore current configuration + * + * 1. unmask EQs + * 2. unmask sources + */ +static void spapr_xive_kvm_pre_save(sPAPRXive *xive) +{ + XiveSource *xsrc =3D &xive->source; + uint8_t *eq_priorities; + CPUState *cs; + int i; + int ret; + + /* Quiesce the sources */ + for (i =3D 0; i < xsrc->nr_irqs; i++) { + uint8_t pq; + + /* Mask and save PQ locally */ + pq =3D xive_esb_read(xsrc, i, XIVE_ESB_SET_PQ_01); + xive_source_esb_set(xsrc, i, pq); + } + + /* Now, sync the sources in KVM */ + spapr_xive_kvm_sync_all(xive, &error_fatal); + + /* Get the IVT (There are no inflight data, could be done earlier ?) */ + spapr_xive_kvm_get_ive_state(xive, &error_fatal); + + /* + * This EQ backup table is not strictly needed, we could restore + * the priority using the EQ index % 8 + */ + eq_priorities =3D g_malloc0(xive->nr_eqs); + + /* Get the EQs a first time to save priorities */ + CPU_FOREACH(cs) { + /* TODO: do we need to use run_on_cpu() ? */ + ret =3D spapr_xive_kvm_get_eq_state(XIVE_ROUTER(xive), cs); + if (ret) { + goto out; + } + } + + for (i =3D 0; i < xive->nr_eqs; i++) { + eq_priorities[i] =3D GETFIELD(EQ_W7_F0_PRIORITY, xive->eqdt[i].w7); + } + + /* Mask all the EQs to stop notifications to the NVT. + * + * TODO: We need OPAL support to mask an EQ, stop queueing and + * keep the internal settings + */ + CPU_FOREACH(cs) { + int ret =3D spapr_xive_kvm_set_eq_state(xive, cs, true); + if (ret) { + goto out; + } + } + + /* And sync again */ + spapr_xive_kvm_sync_all(xive, &error_fatal); + + /* Get the EQs for real now. We want the EQ index and the toggle bit */ + CPU_FOREACH(cs) { + spapr_xive_kvm_get_eq_state(XIVE_ROUTER(xive), cs); + } + + /* And restore the priorities in the EQ dumped state */ + for (i =3D 0; i < xive->nr_eqs; i++) { + xive->eqdt[i].w7 =3D SETFIELD(EQ_W7_F0_PRIORITY, 0ul, eq_prioritie= s[i]); + } + + /* Get the VP thread contexts. The IPB is what we want */ + CPU_FOREACH(cs) { + PowerPCCPU *cpu =3D POWERPC_CPU(cs); + XiveTCTX *tctx =3D XIVE_TCTX_KVM(cpu->intc); + + ret =3D xive_tctx_kvm_get_state(tctx); + if (ret) { + goto out; + } + } + + /* We should be done now. We can roll back */ + + /* Restore EQs to their initial state. They were masked */ + CPU_FOREACH(cs) { + int ret =3D spapr_xive_kvm_set_eq_state(xive, cs, false); + if (ret) { + goto out; + } + } + + /* Restore the sources to their initial state */ + for (i =3D 0; i < xsrc->nr_irqs; i++) { + uint8_t pq =3D xive_source_esb_get(xsrc, i); + if (xive_esb_read(xsrc, i, XIVE_ESB_SET_PQ_00 + (pq << 8)) !=3D 0x= 1) { + error_report("XIVE: IRQ %d has an invalid state", i); + } + } + +out: + g_free(eq_priorities); +} + +/* + * XIVE restore + * + * post_load is simpler and only needs to restore the different state + * in the correct order. sPAPRXive model has the highest priority and + * if handles first the XIVE routing internal tables: EQDT and IVT. + * + * The source ESB PQ bits are restored by the KVM XiveSource. The + * thread interrupt context registers are handled by the KVM XiveTCTX + * model. + */ +static int spapr_xive_kvm_post_load(sPAPRXive *xive, int version_id) +{ + XiveSource *xsrc =3D &xive->source; + CPUState *cs; + int ret; + + /* Set the EQs first. The IVE targetting depends on it. */ + CPU_FOREACH(cs) { + int ret =3D spapr_xive_kvm_set_eq_state(xive, cs, false); + if (ret) { + return ret; + } + } + + /* + * Create the interrupt sources from a KVM perspective. This is + * needed for targetting which is done next + */ + xive_source_kvm_reset(xsrc); + + /* Restore the IVE targetting, if any */ + ret =3D spapr_xive_kvm_set_ive_state(xive); + if (ret) { + return ret; + } + + return 0; +} + +static void spapr_xive_kvm_eq_do_synchronize_state(CPUState *cs, + run_on_cpu_data arg) +{ + spapr_xive_kvm_get_eq_state(XIVE_ROUTER(arg.host_ptr), cs); +} + +static void spapr_xive_kvm_synchronize_state(sPAPRXive *xive) +{ + CPUState *cs; + + spapr_xive_kvm_get_ive_state(xive, &error_fatal); + + CPU_FOREACH(cs) { + run_on_cpu(cs, spapr_xive_kvm_eq_do_synchronize_state, + RUN_ON_CPU_HOST_PTR(xive)); + } +} + +static void spapr_xive_kvm_instance_init(Object *obj) +{ + sPAPRXive *xive =3D SPAPR_XIVE_KVM(obj); + + /* We need a KVM flavored source */ + object_initialize(&xive->source, sizeof(xive->source), + TYPE_XIVE_SOURCE_KVM); + object_property_add_child(obj, "source", OBJECT(&xive->source), NULL); + + /* No KVM support for EQ ESBs. OPAL doesn't either */ + object_initialize(&xive->eq_source, sizeof(xive->eq_source), + TYPE_XIVE_EQ_SOURCE); + object_property_add_child(obj, "eq_source", OBJECT(&xive->eq_source), = NULL); +} + +static void spapr_xive_kvm_realize(DeviceState *dev, Error **errp) +{ + sPAPRXive *xive =3D SPAPR_XIVE_KVM(dev); + Error *local_err =3D NULL; + size_t tima_len; + + if (!kvm_enabled() || !kvmppc_has_cap_xive()) { + error_setg(errp, + "IRQ_XIVE capability must be present for KVM XIVE devic= e"); + return; + } + + /* First, create a KVM XIVE device */ + xive->fd =3D kvm_create_device(kvm_state, KVM_DEV_TYPE_XIVE, false); + if (xive->fd < 0) { + error_setg_errno(errp, -xive->fd, "error creating KVM XIVE device"= ); + return; + } + + /* + * Inform KVM where we will map the source ESB pages. This is + * needed but the hcall H_INT_GET_SOURCE_INFO which returns the + * source characteristics, among which the ESB page address. + */ + kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_CTRL, KVM_DEV_XIVE_VC_BAS= E, + &xive->vc_base, true, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + /* + * Setup the local IVT and EQT tables and the local KVM source + * which will map the sources ESB pages + */ + spapr_xive_common_realize(xive, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + /* Map the TIMA pages */ + tima_len =3D 4ull << TM_SHIFT; + xive->tm_mmap =3D spapr_xive_kvm_mmap(xive, KVM_DEV_XIVE_GET_TIMA_FD, + tima_len, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + memory_region_init_ram_device_ptr(&xive->tm_mmio, OBJECT(xive), + "xive.tima", tima_len, xive->tm_mmap= ); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &xive->tm_mmio); + + /* All done. */ + + /* May be set these globals in the sPAPR IRQ backend instead */ + kvm_kernel_irqchip =3D true; + kvm_msi_via_irqfd_allowed =3D true; + kvm_gsi_direct_mapping =3D true; +} + +static void spapr_xive_kvm_unrealize(DeviceState *dev, Error **errp) +{ + sPAPRXive *xive =3D SPAPR_XIVE_KVM(dev); + + close(xive->fd); + xive->fd =3D -1; + + munmap(xive->tm_mmap, 4ull << TM_SHIFT); +} + +static void spapr_xive_kvm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + sPAPRXiveClass *sxc =3D SPAPR_XIVE_CLASS(klass); + + dc->desc =3D "sPAPR XIVE KVM Interrupt Controller"; + dc->realize =3D spapr_xive_kvm_realize; + dc->unrealize =3D spapr_xive_kvm_unrealize; + + sxc->synchronize_state =3D spapr_xive_kvm_synchronize_state; + sxc->pre_save =3D spapr_xive_kvm_pre_save; + sxc->post_load =3D spapr_xive_kvm_post_load; +} + +static const TypeInfo spapr_xive_kvm_info =3D { + .name =3D TYPE_SPAPR_XIVE_KVM, + .parent =3D TYPE_SPAPR_XIVE, + .instance_init =3D spapr_xive_kvm_instance_init, + .instance_size =3D sizeof(sPAPRXive), + .class_init =3D spapr_xive_kvm_class_init, + .class_size =3D sizeof(sPAPRXiveClass), +}; + +static void xive_kvm_register_types(void) +{ + type_register_static(&spapr_xive_kvm_info); + type_register_static(&xive_source_kvm_info); + type_register_static(&xive_tctx_kvm_info); +} + +type_init(xive_kvm_register_types) diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 745c78024d6f..a5d89c6ac55f 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -575,16 +575,28 @@ static void spapr_irq_init_xive(sPAPRMachineState *sp= apr, uint32_t nr_servers, sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(machine); int i; =20 - /* We don't have KVM support yet, so check for irqchip=3Don */ - if (kvm_enabled() && machine_kernel_irqchip_required(machine)) { - error_report("kernel_irqchip requested. no XIVE support"); - exit(1); + if (kvm_enabled()) { + if (machine_kernel_irqchip_allowed(machine)) { + spapr->xive_tctx_type =3D TYPE_XIVE_TCTX_KVM; + spapr->xive =3D spapr_xive_create(spapr, TYPE_SPAPR_XIVE_KVM, + smc->irq->nr_irqs, nr_servers, + errp); + } + + if (machine_kernel_irqchip_required(machine) && !spapr->xive) { + error_prepend(errp, "kernel_irqchip requested but unavailable:= "); + return; + } } =20 - spapr->xive =3D spapr_xive_create(spapr, TYPE_SPAPR_XIVE, smc->irq->nr= _irqs, - nr_servers, errp); if (!spapr->xive) { - return; + spapr->xive =3D spapr_xive_create(spapr, TYPE_SPAPR_XIVE, + smc->irq->nr_irqs, nr_servers, err= p); + if (!spapr->xive) { + return; + } + spapr->xive_tctx_type =3D TYPE_XIVE_TCTX; + spapr_xive_hcall_init(spapr); } =20 /* @@ -597,9 +609,6 @@ static void spapr_irq_init_xive(sPAPRMachineState *spap= r, uint32_t nr_servers, for (i =3D 0; i < nr_servers; ++i) { spapr_irq_alloc(spapr, SPAPR_IRQ_IPI, i, errp); } - - spapr->xive_tctx_type =3D TYPE_XIVE_TCTX; - spapr_xive_hcall_init(spapr); } =20 /* diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index eacd26836ebf..dd4d69db2bdd 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -39,6 +39,7 @@ obj-$(CONFIG_XICS_SPAPR) +=3D xics_spapr.o obj-$(CONFIG_XICS_KVM) +=3D xics_kvm.o obj-$(CONFIG_XIVE) +=3D xive.o obj-$(CONFIG_XIVE_SPAPR) +=3D spapr_xive.o spapr_xive_hcall.o +obj-$(CONFIG_XIVE_KVM) +=3D spapr_xive_kvm.o obj-$(CONFIG_POWERNV) +=3D xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) +=3D allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) +=3D s390_flic.o --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528388309145661.9133597576321; Thu, 7 Jun 2018 09:18:29 -0700 (PDT) Received: from localhost ([::1]:58978 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxcB-0004Iv-CR for importer@patchew.org; Thu, 07 Jun 2018 12:18:19 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39439) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxDK-0003JI-TG for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxDG-0004Wz-6x for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:38 -0400 Received: from 10.mo5.mail-out.ovh.net ([46.105.52.148]:36154) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxDG-0004WH-0g for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:34 -0400 Received: from player169.ha.ovh.net (unknown [10.109.108.82]) by mo5.mail-out.ovh.net (Postfix) with ESMTP id CBEF01BDFEA for ; Thu, 7 Jun 2018 17:52:32 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 659C358009A; Thu, 7 Jun 2018 17:52:27 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:50:00 +0200 Message-Id: <20180607155003.1580-26-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6106881096263830355 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.52.148 Subject: [Qemu-devel] [PATCH v4 25/28] spapr: fix XICS migration 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Extend the sPAPR IRQ backend with a new handler to handle XICS post_load() specificities. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/spapr_irq.h | 1 + hw/ppc/spapr.c | 9 ++------- hw/ppc/spapr_irq.c | 24 ++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index 85829928a9c4..1ca35ffc13cd 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -47,6 +47,7 @@ typedef struct sPAPRIrq { void *fdt, uint32_t phandle); Object *(*cpu_intc_create)(sPAPRMachineState *spapr, Object *cpu, Error **errp); + void (*post_load)(sPAPRMachineState *spapr); } sPAPRIrq; =20 extern sPAPRIrq spapr_irq_legacy; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 2774b53f169e..025d5af84def 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1689,6 +1689,7 @@ static int spapr_pre_load(void *opaque) static int spapr_post_load(void *opaque, int version_id) { sPAPRMachineState *spapr =3D (sPAPRMachineState *)opaque; + sPAPRMachineClass *smc =3D SPAPR_MACHINE_GET_CLASS(spapr); int err =3D 0; =20 err =3D spapr_caps_post_migration(spapr); @@ -1696,13 +1697,7 @@ static int spapr_post_load(void *opaque, int version= _id) return err; } =20 - if (!object_dynamic_cast(OBJECT(spapr->ics), TYPE_ICS_KVM)) { - CPUState *cs; - CPU_FOREACH(cs) { - PowerPCCPU *cpu =3D POWERPC_CPU(cs); - icp_resend(ICP(cpu->intc)); - } - } + smc->irq->post_load(spapr); =20 /* In earlier versions, there was no separate qdev for the PAPR * RTC, so the RTC offset was stored directly in sPAPREnvironment. diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index a5d89c6ac55f..5f445e17d125 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -254,6 +254,17 @@ static Object *spapr_irq_cpu_intc_create_legacy(sPAPRM= achineState *spapr, return icp_create(cpu, spapr->icp_type, XICS_FABRIC(spapr), errp); } =20 +static void spapr_irq_post_load_legacy(sPAPRMachineState *spapr) +{ + if (!object_dynamic_cast(OBJECT(spapr->ics), TYPE_ICS_KVM)) { + CPUState *cs; + CPU_FOREACH(cs) { + PowerPCCPU *cpu =3D POWERPC_CPU(cs); + icp_resend(ICP(cpu->intc)); + } + } +} + sPAPRIrq spapr_irq_legacy =3D { .nr_irqs =3D XICS_IRQS_SPAPR, .ov5 =3D 0x0, /* XICS only */ @@ -266,6 +277,7 @@ sPAPRIrq spapr_irq_legacy =3D { .print_info =3D spapr_irq_print_info_legacy, .dt_populate =3D spapr_irq_dt_populate_legacy, .cpu_intc_create =3D spapr_irq_cpu_intc_create_legacy, + .post_load =3D spapr_irq_post_load_legacy, }; =20 /* @@ -487,6 +499,11 @@ static Object *spapr_irq_cpu_intc_create_xics(sPAPRMac= hineState *spapr, return spapr_irq_cpu_intc_create_legacy(spapr, cpu, errp); } =20 +static void spapr_irq_post_load_xics(sPAPRMachineState *spapr) +{ + spapr_irq_post_load_legacy(spapr); +} + /* * XICS IRQ number space * @@ -534,6 +551,7 @@ sPAPRIrq spapr_irq_xics =3D { .print_info =3D spapr_irq_print_info_xics, .dt_populate =3D spapr_irq_dt_populate_xics, .cpu_intc_create =3D spapr_irq_cpu_intc_create_xics, + .post_load =3D spapr_irq_post_load_xics, }; =20 /* @@ -716,6 +734,11 @@ static Object *spapr_irq_cpu_intc_create_xive(sPAPRMac= hineState *spapr, XIVE_ROUTER(spapr->xive), errp); } =20 +static void spapr_irq_post_load_xive(sPAPRMachineState *spapr) +{ + ; +} + /* * XIVE IRQ number space * @@ -765,6 +788,7 @@ sPAPRIrq spapr_irq_xive =3D { .print_info =3D spapr_irq_print_info_xive, .dt_populate =3D spapr_irq_dt_populate_xive, .cpu_intc_create =3D spapr_irq_cpu_intc_create_xive, + .post_load =3D spapr_irq_post_load_xive, }; =20 /* --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528387593093679.7286770921262; Thu, 7 Jun 2018 09:06:33 -0700 (PDT) Received: from localhost ([::1]:58858 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxQm-0000Sd-67 for importer@patchew.org; Thu, 07 Jun 2018 12:06:32 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39478) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxDQ-0003Oe-HN for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:46 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxDM-0004aA-6x for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:44 -0400 Received: from 6.mo5.mail-out.ovh.net ([178.32.119.138]:35576) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxDL-0004ZE-SW for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:40 -0400 Received: from player169.ha.ovh.net (unknown [10.109.120.69]) by mo5.mail-out.ovh.net (Postfix) with ESMTP id 6AA391BBDAD for ; Thu, 7 Jun 2018 17:52:38 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id D48A45800B8; Thu, 7 Jun 2018 17:52:32 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:50:01 +0200 Message-Id: <20180607155003.1580-27-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6108569947378649939 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 178.32.119.138 Subject: [Qemu-devel] [PATCH v4 26/28] pnv: add a physical mapping array describing MMIO ranges in each chip 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Based on previous work done in skiboot, the physical mapping array helps in calculating the MMIO ranges of each controller depending on the chip id and the chip type. This is will be particularly useful for the P9 models which use less the XSCOM bus and rely more on MMIOs. A link on the chip is now necessary to calculate MMIO BARs and sizes. This is why such a link is introduced in the PSIHB model. Signed-off-by: C=C3=A9dric Le Goater Reviewed-by: Philippe Mathieu-Daud=C3=A9 Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/pnv.h | 51 ++++++++++++++++++++++++++++++++++--------------= -- hw/ppc/pnv.c | 53 ++++++++++++++++++++++++++++++++++++++++++++----= ---- hw/ppc/pnv_psi.c | 15 ++++++++++++--- hw/ppc/pnv_xscom.c | 8 ++++---- 4 files changed, 96 insertions(+), 31 deletions(-) diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index 90759240a7b1..ffa4a0899705 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -53,7 +53,6 @@ typedef struct PnvChip { uint64_t cores_mask; void *cores; =20 - hwaddr xscom_base; MemoryRegion xscom_mmio; MemoryRegion xscom; AddressSpace xscom_as; @@ -64,6 +63,18 @@ typedef struct PnvChip { PnvOCC occ; } PnvChip; =20 +typedef enum PnvPhysMapType { + PNV_MAP_XSCOM, + PNV_MAP_ICP, + PNV_MAP_PSIHB, + PNV_MAP_PSIHB_FSP, +} PnvPhysMapType; + +typedef struct PnvPhysMapEntry { + uint64_t base; + uint64_t size; +} PnvPhysMapEntry; + typedef struct PnvChipClass { /*< private >*/ SysBusDeviceClass parent_class; @@ -73,9 +84,10 @@ typedef struct PnvChipClass { uint64_t chip_cfam_id; uint64_t cores_mask; =20 - hwaddr xscom_base; + const PnvPhysMapEntry *phys_map; =20 uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id); + uint64_t (*map_base)(const PnvChip *chip, PnvPhysMapType type); } PnvChipClass; =20 #define PNV_CHIP_TYPE_SUFFIX "-" TYPE_PNV_CHIP @@ -159,9 +171,21 @@ void pnv_bmc_powerdown(IPMIBmc *bmc); /* * POWER8 MMIO base addresses */ -#define PNV_XSCOM_SIZE 0x800000000ull -#define PNV_XSCOM_BASE(chip) \ - (chip->xscom_base + ((uint64_t)(chip)->chip_id) * PNV_XSCOM_SIZE) +static inline uint64_t pnv_map_size(const PnvChip *chip, PnvPhysMapType ty= pe) +{ + PnvChipClass *pcc =3D PNV_CHIP_GET_CLASS(chip); + const PnvPhysMapEntry *map =3D &pcc->phys_map[type]; + + return map->size; +} + +static inline uint64_t pnv_map_base(const PnvChip *chip, PnvPhysMapType ty= pe) +{ + return PNV_CHIP_GET_CLASS(chip)->map_base(chip, type); +} + +#define PNV_XSCOM_SIZE(chip) pnv_map_size(chip, PNV_MAP_XSCOM) +#define PNV_XSCOM_BASE(chip) pnv_map_base(chip, PNV_MAP_XSCOM) =20 /* * XSCOM 0x20109CA defines the ICP BAR: @@ -177,18 +201,13 @@ void pnv_bmc_powerdown(IPMIBmc *bmc); * 0xffffe02200000000 -> 0x0003ffff80800000 * 0xffffe02600000000 -> 0x0003ffff80900000 */ -#define PNV_ICP_SIZE 0x0000000000100000ull -#define PNV_ICP_BASE(chip) \ - (0x0003ffff80000000ull + (uint64_t) PNV_CHIP_INDEX(chip) * PNV_ICP_SIZ= E) - +#define PNV_ICP_SIZE(chip) pnv_map_size(chip, PNV_MAP_ICP) +#define PNV_ICP_BASE(chip) pnv_map_base(chip, PNV_MAP_ICP) =20 -#define PNV_PSIHB_SIZE 0x0000000000100000ull -#define PNV_PSIHB_BASE(chip) \ - (0x0003fffe80000000ull + (uint64_t)PNV_CHIP_INDEX(chip) * PNV_PSIHB_SI= ZE) +#define PNV_PSIHB_SIZE(chip) pnv_map_size(chip, PNV_MAP_PSIHB) +#define PNV_PSIHB_BASE(chip) pnv_map_base(chip, PNV_MAP_PSIHB) =20 -#define PNV_PSIHB_FSP_SIZE 0x0000000100000000ull -#define PNV_PSIHB_FSP_BASE(chip) \ - (0x0003ffe000000000ull + (uint64_t)PNV_CHIP_INDEX(chip) * \ - PNV_PSIHB_FSP_SIZE) +#define PNV_PSIHB_FSP_SIZE(chip) pnv_map_size(chip, PNV_MAP_PSIHB_FSP) +#define PNV_PSIHB_FSP_BASE(chip) pnv_map_base(chip, PNV_MAP_PSIHB_FSP) =20 #endif /* _PPC_PNV_H */ diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 031488131629..77caaea64b2f 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -712,6 +712,24 @@ static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, ui= nt32_t core_id) */ #define POWER9_CORE_MASK (0xffffffffffffffull) =20 +/* + * POWER8 MMIOs + */ +static const PnvPhysMapEntry pnv_chip_power8_phys_map[] =3D { + [PNV_MAP_XSCOM] =3D { 0x0003fc0000000000ull, 0x0000000800000000ull= }, + [PNV_MAP_ICP] =3D { 0x0003ffff80000000ull, 0x0000000000100000ull= }, + [PNV_MAP_PSIHB] =3D { 0x0003fffe80000000ull, 0x0000000000100000ull= }, + [PNV_MAP_PSIHB_FSP] =3D { 0x0003ffe000000000ull, 0x0000000100000000ull= }, +}; + +static uint64_t pnv_chip_map_base_p8(const PnvChip *chip, PnvPhysMapType t= ype) +{ + PnvChipClass *pcc =3D PNV_CHIP_GET_CLASS(chip); + const PnvPhysMapEntry *map =3D &pcc->phys_map[type]; + + return map->base + chip->chip_id * map->size; +} + static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) { DeviceClass *dc =3D DEVICE_CLASS(klass); @@ -721,7 +739,8 @@ static void pnv_chip_power8e_class_init(ObjectClass *kl= ass, void *data) k->chip_cfam_id =3D 0x221ef04980000000ull; /* P8 Murano DD2.1 */ k->cores_mask =3D POWER8E_CORE_MASK; k->core_pir =3D pnv_chip_core_pir_p8; - k->xscom_base =3D 0x003fc0000000000ull; + k->map_base =3D pnv_chip_map_base_p8; + k->phys_map =3D pnv_chip_power8_phys_map; dc->desc =3D "PowerNV Chip POWER8E"; } =20 @@ -734,7 +753,8 @@ static void pnv_chip_power8_class_init(ObjectClass *kla= ss, void *data) k->chip_cfam_id =3D 0x220ea04980000000ull; /* P8 Venice DD2.0 */ k->cores_mask =3D POWER8_CORE_MASK; k->core_pir =3D pnv_chip_core_pir_p8; - k->xscom_base =3D 0x003fc0000000000ull; + k->map_base =3D pnv_chip_map_base_p8; + k->phys_map =3D pnv_chip_power8_phys_map; dc->desc =3D "PowerNV Chip POWER8"; } =20 @@ -747,10 +767,27 @@ static void pnv_chip_power8nvl_class_init(ObjectClass= *klass, void *data) k->chip_cfam_id =3D 0x120d304980000000ull; /* P8 Naples DD1.0 */ k->cores_mask =3D POWER8_CORE_MASK; k->core_pir =3D pnv_chip_core_pir_p8; - k->xscom_base =3D 0x003fc0000000000ull; + k->map_base =3D pnv_chip_map_base_p8; + k->phys_map =3D pnv_chip_power8_phys_map; dc->desc =3D "PowerNV Chip POWER8NVL"; } =20 +/* + * POWER9 MMIOs + */ +static const PnvPhysMapEntry pnv_chip_power9_phys_map[] =3D { + [PNV_MAP_XSCOM] =3D { 0x000603fc00000000ull, 0x0000000400000000ull= }, +}; + +/* Each chip has a 4TB range for its MMIOs */ +static uint64_t pnv_chip_map_base_p9(const PnvChip *chip, PnvPhysMapType t= ype) +{ + PnvChipClass *pcc =3D PNV_CHIP_GET_CLASS(chip); + const PnvPhysMapEntry *map =3D &pcc->phys_map[type]; + + return map->base + ((uint64_t) chip->chip_id << 42); +} + static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) { DeviceClass *dc =3D DEVICE_CLASS(klass); @@ -760,7 +797,8 @@ static void pnv_chip_power9_class_init(ObjectClass *kla= ss, void *data) k->chip_cfam_id =3D 0x220d104900008000ull; /* P9 Nimbus DD2.0 */ k->cores_mask =3D POWER9_CORE_MASK; k->core_pir =3D pnv_chip_core_pir_p9; - k->xscom_base =3D 0x00603fc00000000ull; + k->map_base =3D pnv_chip_map_base_p9; + k->phys_map =3D pnv_chip_power9_phys_map; dc->desc =3D "PowerNV Chip POWER9"; } =20 @@ -797,15 +835,14 @@ static void pnv_chip_core_sanitize(PnvChip *chip, Err= or **errp) static void pnv_chip_init(Object *obj) { PnvChip *chip =3D PNV_CHIP(obj); - PnvChipClass *pcc =3D PNV_CHIP_GET_CLASS(chip); - - chip->xscom_base =3D pcc->xscom_base; =20 object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC); object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL); =20 object_initialize(&chip->psi, sizeof(chip->psi), TYPE_PNV_PSI); object_property_add_child(obj, "psi", OBJECT(&chip->psi), NULL); + object_property_add_const_link(OBJECT(&chip->psi), "chip", obj, + &error_abort); object_property_add_const_link(OBJECT(&chip->psi), "xics", OBJECT(qdev_get_machine()), &error_abor= t); =20 @@ -829,7 +866,7 @@ static void pnv_chip_icp_realize(PnvChip *chip, Error *= *errp) XICSFabric *xi =3D XICS_FABRIC(qdev_get_machine()); =20 name =3D g_strdup_printf("icp-%x", chip->chip_id); - memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE); + memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE(c= hip)); sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip->icp_mmio); g_free(name); =20 diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 5b969127c303..882b5d4b9f99 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -465,11 +465,20 @@ static void pnv_psi_realize(DeviceState *dev, Error *= *errp) Object *obj; Error *err =3D NULL; unsigned int i; + PnvChip *chip; + + obj =3D object_property_get_link(OBJECT(dev), "chip", &err); + if (!obj) { + error_propagate(errp, err); + error_prepend(errp, "required link 'chip' not found: "); + return; + } + chip =3D PNV_CHIP(obj); =20 obj =3D object_property_get_link(OBJECT(dev), "xics", &err); if (!obj) { - error_setg(errp, "%s: required link 'xics' not found: %s", - __func__, error_get_pretty(err)); + error_propagate(errp, err); + error_prepend(errp, "required link 'xics' not found: "); return; } =20 @@ -497,7 +506,7 @@ static void pnv_psi_realize(DeviceState *dev, Error **e= rrp) =20 /* Initialize MMIO region */ memory_region_init_io(&psi->regs_mr, OBJECT(dev), &psi_mmio_ops, psi, - "psihb", PNV_PSIHB_SIZE); + "psihb", PNV_PSIHB_SIZE(chip)); =20 /* Default BAR for MMIO region */ pnv_psi_set_bar(psi, psi->bar | PSIHB_BAR_EN); diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index 46fae41f32b0..20ffc233174c 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -50,7 +50,7 @@ static void xscom_complete(CPUState *cs, uint64_t hmer_bi= ts) =20 static uint32_t pnv_xscom_pcba(PnvChip *chip, uint64_t addr) { - addr &=3D (PNV_XSCOM_SIZE - 1); + addr &=3D (PNV_XSCOM_SIZE(chip) - 1); =20 if (pnv_chip_is_power9(chip)) { return addr >> 3; @@ -179,10 +179,10 @@ void pnv_xscom_realize(PnvChip *chip, Error **errp) =20 name =3D g_strdup_printf("xscom-%x", chip->chip_id); memory_region_init_io(&chip->xscom_mmio, OBJECT(chip), &pnv_xscom_ops, - chip, name, PNV_XSCOM_SIZE); + chip, name, PNV_XSCOM_SIZE(chip)); sysbus_init_mmio(sbd, &chip->xscom_mmio); =20 - memory_region_init(&chip->xscom, OBJECT(chip), name, PNV_XSCOM_SIZE); + memory_region_init(&chip->xscom, OBJECT(chip), name, PNV_XSCOM_SIZE(ch= ip)); address_space_init(&chip->xscom_as, &chip->xscom, name); g_free(name); } @@ -225,7 +225,7 @@ static const char compat_p9[] =3D "ibm,power9-xscom\0ib= m,xscom"; int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset) { uint64_t reg[] =3D { cpu_to_be64(PNV_XSCOM_BASE(chip)), - cpu_to_be64(PNV_XSCOM_SIZE) }; + cpu_to_be64(PNV_XSCOM_SIZE(chip)) }; int xscom_offset; ForeachPopulateArgs args; char *name; --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528388491473142.29403241202215; Thu, 7 Jun 2018 09:21:31 -0700 (PDT) Received: from localhost ([::1]:59006 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxfG-0006sa-Id for importer@patchew.org; Thu, 07 Jun 2018 12:21:30 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39512) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxDW-0003Sy-4Y for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:54 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxDR-0004d0-En for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:50 -0400 Received: from 5.mo177.mail-out.ovh.net ([46.105.39.154]:39613) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxDR-0004cK-7t for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:45 -0400 Received: from player169.ha.ovh.net (unknown [10.109.108.113]) by mo177.mail-out.ovh.net (Postfix) with ESMTP id EBF8FB5978 for ; Thu, 7 Jun 2018 17:52:43 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id 7ABB75800A7; Thu, 7 Jun 2018 17:52:38 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:50:02 +0200 Message-Id: <20180607155003.1580-28-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6109977322101312339 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.39.154 Subject: [Qemu-devel] [PATCH v4 27/28] ppc: externalize ppc_get_vcpu_by_pir() 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" We will use it to get the CPU interrupt presenter in XIVE. Signed-off-by: C=C3=A9dric Le Goater --- include/hw/ppc/ppc.h | 1 + hw/ppc/pnv.c | 16 ---------------- hw/ppc/ppc.c | 16 ++++++++++++++++ 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h index ff0ac306be72..c8e54544e563 100644 --- a/include/hw/ppc/ppc.h +++ b/include/hw/ppc/ppc.h @@ -4,6 +4,7 @@ #include "target/ppc/cpu-qom.h" =20 void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level); +PowerPCCPU *ppc_get_vcpu_by_pir(int pir); =20 /* PowerPC hardware exceptions management helpers */ typedef void (*clk_setup_cb)(void *opaque, uint32_t freq); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 77caaea64b2f..e7bc4534e63d 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1030,22 +1030,6 @@ static void pnv_ics_resend(XICSFabric *xi) } } =20 -static PowerPCCPU *ppc_get_vcpu_by_pir(int pir) -{ - CPUState *cs; - - CPU_FOREACH(cs) { - PowerPCCPU *cpu =3D POWERPC_CPU(cs); - CPUPPCState *env =3D &cpu->env; - - if (env->spr_cb[SPR_PIR].default_value =3D=3D pir) { - return cpu; - } - } - - return NULL; -} - static ICPState *pnv_icp_get(XICSFabric *xi, int pir) { PowerPCCPU *cpu =3D ppc_get_vcpu_by_pir(pir); diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index ec4be25f4994..9292f986eba7 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -1358,3 +1358,19 @@ void PPC_debug_write (void *opaque, uint32_t addr, u= int32_t val) break; } } + +PowerPCCPU *ppc_get_vcpu_by_pir(int pir) +{ + CPUState *cs; + + CPU_FOREACH(cs) { + PowerPCCPU *cpu =3D POWERPC_CPU(cs); + CPUPPCState *env =3D &cpu->env; + + if (env->spr_cb[SPR_PIR].default_value =3D=3D pir) { + return cpu; + } + } + + return NULL; +} --=20 2.13.6 From nobody Sat May 4 00:32:28 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528388637426435.9044321205215; Thu, 7 Jun 2018 09:23:57 -0700 (PDT) Received: from localhost ([::1]:59022 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxhc-0000RI-DH for importer@patchew.org; Thu, 07 Jun 2018 12:23:56 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39558) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQxDe-0003aP-Jd for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:53:05 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQxDX-0004g9-L1 for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:58 -0400 Received: from 9.mo177.mail-out.ovh.net ([46.105.72.238]:49037) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fQxDX-0004ew-0g for qemu-devel@nongnu.org; Thu, 07 Jun 2018 11:52:51 -0400 Received: from player169.ha.ovh.net (unknown [10.109.120.81]) by mo177.mail-out.ovh.net (Postfix) with ESMTP id 93053B59EE for ; Thu, 7 Jun 2018 17:52:49 +0200 (CEST) Received: from zorba.kaod.org.com (deibp9eh1--blueice1n0.emea.ibm.com [195.212.29.162]) (Authenticated sender: clg@kaod.org) by player169.ha.ovh.net (Postfix) with ESMTPSA id F261858009A; Thu, 7 Jun 2018 17:52:43 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-ppc@nongnu.org Date: Thu, 7 Jun 2018 17:50:03 +0200 Message-Id: <20180607155003.1580-29-clg@kaod.org> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180607155003.1580-1-clg@kaod.org> References: <20180607155003.1580-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 6111666170683099987 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedthedrjeejgdelgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 46.105.72.238 Subject: [Qemu-devel] [PATCH v4 28/28] ppc/pnv: add XIVE support 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: Greg Kurz , qemu-devel@nongnu.org, =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" This is simple model of the POWER9 XIVE interrupt controller for the PowerNV machine. XIVE for baremetal is a complex controller and the model only addresses the needs of the skiboot firmware. * Overall architecture XIVE Interrupt Controller +-------------------------------------+ IPIs | +---------+ +---------+ +---------+ | +--------+ | |VC | |CQ | |PC |----> | CORES | | | esb | | | | |----> | | | | ive | | Bridge | | |----> | | | |SC eqd | | | | vpd | | | | +------+ | +---------+ +----+----+ +---------+ | +--+-+-+-+ | RAM | +------------------|------------------+ | | | | | | | | | | | | | | | | | +---------------------v--------------------------v-v-v---+ = other | <---+ Power Bus +----> = chips | esb | +-----------+-----------------------+--------------------+ | ive | | | | eqd | | | | vpd | +---+----+ +---+----+ +------+ |SC | |SC | | | | | | 2-bits | | 2-bits | | local | | VC | +--------+ +--------+ PCIe NX,NPU,CAPI SC: Source Controller (aka. IVSE) VC: Virtualization Controller (aka. IVRE) CQ: Common Queue (Bridge) PC: Presentation Controller (aka. IVPE) 2-bits: source state machine esb: Event State Buffer (Array of PQ bits in an IVSE) ive: Interrupt Virtualization Entry eqd: Event Queue Descriptor vpd: Virtual Processor Descriptor It is composed of three sub-engines : - Interrupt Virtualization Source Engine (IVSE), or Source Controller (SC). These are found in PCI PHBs, in the PSI host bridge controller, but also inside the main controller for the core IPIs and other sub-chips (NX, CAP, NPU) of the chip/processor. They are configured to feed the IVRE with events. - Interrupt Virtualization Routing Engine (IVRE) or Virtualization Controller (VC). Its job is to match an event source with an Event Queue (EQ). - Interrupt Virtualization Presentation Engine (IVPE) or Presentation Controller (PC). It maintains the interrupt context state of each thread and handles the delivery of the external exception to the thread. * XIVE internal tables Each of the sub-engines uses a set of tables to redirect exceptions from event sources to CPU threads. +-------+ User or OS | EQ | or +------>|entries| Hypervisor | | .. | Memory | +-------+ | ^ | | +--------------------------------------------------+ | | Hypervisor +------+ +---+--+ +---+--+ +------+ Memory | ESB | | IVT | | EQDT | | VPDT | (skiboot) +----+-+ +----+-+ +----+-+ +------+ ^ | ^ | ^ | ^ | | | | | | | +--------------------------------------------------+ | | | | | | | | | | | | | | +-----|--|--------|--|--------|--|-+ +-|-----+ +-----= -+ | | | | | | | | | | tctx| |Threa= d| IPI or ----+ + v + v + v |---| + .. |-----> = | HW events | | | | | = | | IVRE | | IVPE | +-----= -+ +----------------------------------+ +-------+ The IVSE have a 2-bits, P for pending and Q for queued, state machine for each source that allows events to be triggered. They are stored in an array, the Event State Buffer (ESB) and controlled by MMIOs. If the event is let through, the IVRE looks up in the Interrupt Virtualization Entry (IVE) table for an Event Queue Descriptor (EQD) configured for the source. Each Event Queue Descriptor defines a notification path to a CPU and an in-memory Event Queue, in which will be pushed an EQ data for the OS to pull. The IVPE determines if a Virtual Processor (VP) can handle the event by scanning the thread contexts of the VPs dispatched on the processor HW threads. It maintains the interrupt context state of each thread in a Virtual Processor Descriptor (VPD) table. * QEMU model for PowerNV The PowerNV model reuses the common XIVE framework developed for sPAPR and the fundamentals aspects are quite the same. The difference are outlined below. The controller initial BAR configuration is performed using the XSCOM bus from there, MMIO are used for further configuration. The MMIO regions exposed are : - Interrupt controller registers - ESB pages for IPIs and EQs - Presenter MMIO (Not used) - Thread Interrupt Management Area MMIO, direct and indirect Virtualization Controller MMIO region containing the IPI ESB pages and EQ ESB pages is sub-divided into "sets" which map portions of the VC region to the different ESB pages. It is configured at runtime through the EDT set translation table to let the firmware decide how to split the address space between IPI ESB pages and EQ ESB pages. The XIVE tables are now in the machine RAM and not in the hypervisor anymore. The firmware (skiboot) configures these tables using Virtual Structure Descriptor defining the characteristics of each table : SBE, IVE, EQD and VPD. These are later used to access the virtual interrupt entries. The internal cache of these tables in the interrupt controller is updated and invalidated using a set of registers. Signed-off-by: C=C3=A9dric Le Goater --- hw/intc/pnv_xive_regs.h | 314 ++++++++++ include/hw/ppc/pnv.h | 22 + include/hw/ppc/pnv_xive.h | 92 +++ include/hw/ppc/pnv_xscom.h | 3 + include/hw/ppc/xive.h | 1 + hw/intc/pnv_xive.c | 1485 ++++++++++++++++++++++++++++++++++++++++= ++++ hw/intc/xive.c | 63 +- hw/ppc/pnv.c | 42 +- hw/ppc/pnv_core.c | 28 +- hw/intc/Makefile.objs | 2 +- 10 files changed, 2034 insertions(+), 18 deletions(-) create mode 100644 hw/intc/pnv_xive_regs.h create mode 100644 include/hw/ppc/pnv_xive.h create mode 100644 hw/intc/pnv_xive.c diff --git a/hw/intc/pnv_xive_regs.h b/hw/intc/pnv_xive_regs.h new file mode 100644 index 000000000000..509d5a18cdde --- /dev/null +++ b/hw/intc/pnv_xive_regs.h @@ -0,0 +1,314 @@ +/* + * QEMU PowerPC XIVE interrupt controller model + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef PPC_PNV_XIVE_REGS_H +#define PPC_PNV_XIVE_REGS_H + +/* IC register offsets 0x0 - 0x400 */ +#define CQ_SWI_CMD_HIST 0x020 +#define CQ_SWI_CMD_POLL 0x028 +#define CQ_SWI_CMD_BCAST 0x030 +#define CQ_SWI_CMD_ASSIGN 0x038 +#define CQ_SWI_CMD_BLK_UPD 0x040 +#define CQ_SWI_RSP 0x048 +#define X_CQ_CFG_PB_GEN 0x0a +#define CQ_CFG_PB_GEN 0x050 +#define CQ_INT_ADDR_OPT PPC_BITMASK(14, 15) +#define X_CQ_IC_BAR 0x10 +#define X_CQ_MSGSND 0x0b +#define CQ_MSGSND 0x058 +#define CQ_CNPM_SEL 0x078 +#define CQ_IC_BAR 0x080 +#define CQ_IC_BAR_VALID PPC_BIT(0) +#define CQ_IC_BAR_64K PPC_BIT(1) +#define X_CQ_TM1_BAR 0x12 +#define CQ_TM1_BAR 0x90 +#define X_CQ_TM2_BAR 0x014 +#define CQ_TM2_BAR 0x0a0 +#define CQ_TM_BAR_VALID PPC_BIT(0) +#define CQ_TM_BAR_64K PPC_BIT(1) +#define X_CQ_PC_BAR 0x16 +#define CQ_PC_BAR 0x0b0 +#define CQ_PC_BAR_VALID PPC_BIT(0) +#define X_CQ_PC_BARM 0x17 +#define CQ_PC_BARM 0x0b8 +#define CQ_PC_BARM_MASK PPC_BITMASK(26, 38) +#define X_CQ_VC_BAR 0x18 +#define CQ_VC_BAR 0x0c0 +#define CQ_VC_BAR_VALID PPC_BIT(0) +#define X_CQ_VC_BARM 0x19 +#define CQ_VC_BARM 0x0c8 +#define CQ_VC_BARM_MASK PPC_BITMASK(21, 37) +#define X_CQ_TAR 0x1e +#define CQ_TAR 0x0f0 +#define CQ_TAR_TBL_AUTOINC PPC_BIT(0) +#define CQ_TAR_TSEL PPC_BITMASK(12, 15) +#define CQ_TAR_TSEL_BLK PPC_BIT(12) +#define CQ_TAR_TSEL_MIG PPC_BIT(13) +#define CQ_TAR_TSEL_VDT PPC_BIT(14) +#define CQ_TAR_TSEL_EDT PPC_BIT(15) +#define CQ_TAR_TSEL_INDEX PPC_BITMASK(26, 31) +#define X_CQ_TDR 0x1f +#define CQ_TDR 0x0f8 +#define CQ_TDR_VDT_VALID PPC_BIT(0) +#define CQ_TDR_VDT_BLK PPC_BITMASK(11, 15) +#define CQ_TDR_VDT_INDEX PPC_BITMASK(28, 31) +#define CQ_TDR_EDT_TYPE PPC_BITMASK(0, 1) +#define CQ_TDR_EDT_INVALID 0 +#define CQ_TDR_EDT_IPI 1 +#define CQ_TDR_EDT_EQ 2 +#define CQ_TDR_EDT_BLK PPC_BITMASK(12, 15) +#define CQ_TDR_EDT_INDEX PPC_BITMASK(26, 31) +#define X_CQ_PBI_CTL 0x20 +#define CQ_PBI_CTL 0x100 +#define CQ_PBI_PC_64K PPC_BIT(5) +#define CQ_PBI_VC_64K PPC_BIT(6) +#define CQ_PBI_LNX_TRIG PPC_BIT(7) +#define CQ_PBI_FORCE_TM_LOCAL PPC_BIT(22) +#define CQ_PBO_CTL 0x108 +#define CQ_AIB_CTL 0x110 +#define X_CQ_RST_CTL 0x23 +#define CQ_RST_CTL 0x118 +#define X_CQ_FIRMASK 0x33 +#define CQ_FIRMASK 0x198 +#define X_CQ_FIRMASK_AND 0x34 +#define CQ_FIRMASK_AND 0x1a0 +#define X_CQ_FIRMASK_OR 0x35 +#define CQ_FIRMASK_OR 0x1a8 + +/* PC LBS1 register offsets 0x400 - 0x800 */ +#define X_PC_TCTXT_CFG 0x100 +#define PC_TCTXT_CFG 0x400 +#define PC_TCTXT_CFG_BLKGRP_EN PPC_BIT(0) +#define PC_TCTXT_CFG_TARGET_EN PPC_BIT(1) +#define PC_TCTXT_CFG_LGS_EN PPC_BIT(2) +#define PC_TCTXT_CFG_STORE_ACK PPC_BIT(3) +#define PC_TCTXT_CFG_HARD_CHIPID_BLK PPC_BIT(8) +#define PC_TCTXT_CHIPID_OVERRIDE PPC_BIT(9) +#define PC_TCTXT_CHIPID PPC_BITMASK(12, 15) +#define PC_TCTXT_INIT_AGE PPC_BITMASK(30, 31) +#define X_PC_TCTXT_TRACK 0x101 +#define PC_TCTXT_TRACK 0x408 +#define PC_TCTXT_TRACK_EN PPC_BIT(0) +#define X_PC_TCTXT_INDIR0 0x104 +#define PC_TCTXT_INDIR0 0x420 +#define PC_TCTXT_INDIR_VALID PPC_BIT(0) +#define PC_TCTXT_INDIR_THRDID PPC_BITMASK(9, 15) +#define X_PC_TCTXT_INDIR1 0x105 +#define PC_TCTXT_INDIR1 0x428 +#define X_PC_TCTXT_INDIR2 0x106 +#define PC_TCTXT_INDIR2 0x430 +#define X_PC_TCTXT_INDIR3 0x107 +#define PC_TCTXT_INDIR3 0x438 +#define X_PC_THREAD_EN_REG0 0x108 +#define PC_THREAD_EN_REG0 0x440 +#define X_PC_THREAD_EN_REG0_SET 0x109 +#define PC_THREAD_EN_REG0_SET 0x448 +#define X_PC_THREAD_EN_REG0_CLR 0x10a +#define PC_THREAD_EN_REG0_CLR 0x450 +#define X_PC_THREAD_EN_REG1 0x10c +#define PC_THREAD_EN_REG1 0x460 +#define X_PC_THREAD_EN_REG1_SET 0x10d +#define PC_THREAD_EN_REG1_SET 0x468 +#define X_PC_THREAD_EN_REG1_CLR 0x10e +#define PC_THREAD_EN_REG1_CLR 0x470 +#define X_PC_GLOBAL_CONFIG 0x110 +#define PC_GLOBAL_CONFIG 0x480 +#define PC_GCONF_INDIRECT PPC_BIT(32) +#define PC_GCONF_CHIPID_OVR PPC_BIT(40) +#define PC_GCONF_CHIPID PPC_BITMASK(44, 47) +#define X_PC_VSD_TABLE_ADDR 0x111 +#define PC_VSD_TABLE_ADDR 0x488 +#define X_PC_VSD_TABLE_DATA 0x112 +#define PC_VSD_TABLE_DATA 0x490 +#define X_PC_AT_KILL 0x116 +#define PC_AT_KILL 0x4b0 +#define PC_AT_KILL_VALID PPC_BIT(0) +#define PC_AT_KILL_BLOCK_ID PPC_BITMASK(27, 31) +#define PC_AT_KILL_OFFSET PPC_BITMASK(48, 60) +#define X_PC_AT_KILL_MASK 0x117 +#define PC_AT_KILL_MASK 0x4b8 + +/* PC LBS2 register offsets */ +#define X_PC_VPC_CACHE_ENABLE 0x161 +#define PC_VPC_CACHE_ENABLE 0x708 +#define PC_VPC_CACHE_EN_MASK PPC_BITMASK(0, 31) +#define X_PC_VPC_SCRUB_TRIG 0x162 +#define PC_VPC_SCRUB_TRIG 0x710 +#define X_PC_VPC_SCRUB_MASK 0x163 +#define PC_VPC_SCRUB_MASK 0x718 +#define PC_SCRUB_VALID PPC_BIT(0) +#define PC_SCRUB_WANT_DISABLE PPC_BIT(1) +#define PC_SCRUB_WANT_INVAL PPC_BIT(2) +#define PC_SCRUB_BLOCK_ID PPC_BITMASK(27, 31) +#define PC_SCRUB_OFFSET PPC_BITMASK(45, 63) +#define X_PC_VPC_CWATCH_SPEC 0x167 +#define PC_VPC_CWATCH_SPEC 0x738 +#define PC_VPC_CWATCH_CONFLICT PPC_BIT(0) +#define PC_VPC_CWATCH_FULL PPC_BIT(8) +#define PC_VPC_CWATCH_BLOCKID PPC_BITMASK(27, 31) +#define PC_VPC_CWATCH_OFFSET PPC_BITMASK(45, 63) +#define X_PC_VPC_CWATCH_DAT0 0x168 +#define PC_VPC_CWATCH_DAT0 0x740 +#define X_PC_VPC_CWATCH_DAT1 0x169 +#define PC_VPC_CWATCH_DAT1 0x748 +#define X_PC_VPC_CWATCH_DAT2 0x16a +#define PC_VPC_CWATCH_DAT2 0x750 +#define X_PC_VPC_CWATCH_DAT3 0x16b +#define PC_VPC_CWATCH_DAT3 0x758 +#define X_PC_VPC_CWATCH_DAT4 0x16c +#define PC_VPC_CWATCH_DAT4 0x760 +#define X_PC_VPC_CWATCH_DAT5 0x16d +#define PC_VPC_CWATCH_DAT5 0x768 +#define X_PC_VPC_CWATCH_DAT6 0x16e +#define PC_VPC_CWATCH_DAT6 0x770 +#define X_PC_VPC_CWATCH_DAT7 0x16f +#define PC_VPC_CWATCH_DAT7 0x778 + +/* VC0 register offsets 0x800 - 0xFFF */ +#define X_VC_GLOBAL_CONFIG 0x200 +#define VC_GLOBAL_CONFIG 0x800 +#define VC_GCONF_INDIRECT PPC_BIT(32) +#define X_VC_VSD_TABLE_ADDR 0x201 +#define VC_VSD_TABLE_ADDR 0x808 +#define X_VC_VSD_TABLE_DATA 0x202 +#define VC_VSD_TABLE_DATA 0x810 +#define VC_IVE_ISB_BLOCK_MODE 0x818 +#define VC_EQD_BLOCK_MODE 0x820 +#define VC_VPS_BLOCK_MODE 0x828 +#define X_VC_IRQ_CONFIG_IPI 0x208 +#define VC_IRQ_CONFIG_IPI 0x840 +#define VC_IRQ_CONFIG_MEMB_EN PPC_BIT(45) +#define VC_IRQ_CONFIG_MEMB_SZ PPC_BITMASK(46, 51) +#define VC_IRQ_CONFIG_HW 0x848 +#define VC_IRQ_CONFIG_CASCADE1 0x850 +#define VC_IRQ_CONFIG_CASCADE2 0x858 +#define VC_IRQ_CONFIG_REDIST 0x860 +#define VC_IRQ_CONFIG_IPI_CASC 0x868 +#define X_VC_AIB_TX_ORDER_TAG2 0x22d +#define VC_AIB_TX_ORDER_TAG2_REL_TF PPC_BIT(20) +#define VC_AIB_TX_ORDER_TAG2 0x890 +#define X_VC_AT_MACRO_KILL 0x23e +#define VC_AT_MACRO_KILL 0x8b0 +#define X_VC_AT_MACRO_KILL_MASK 0x23f +#define VC_AT_MACRO_KILL_MASK 0x8b8 +#define VC_KILL_VALID PPC_BIT(0) +#define VC_KILL_TYPE PPC_BITMASK(14, 15) +#define VC_KILL_IRQ 0 +#define VC_KILL_IVC 1 +#define VC_KILL_SBC 2 +#define VC_KILL_EQD 3 +#define VC_KILL_BLOCK_ID PPC_BITMASK(27, 31) +#define VC_KILL_OFFSET PPC_BITMASK(48, 60) +#define X_VC_EQC_CACHE_ENABLE 0x211 +#define VC_EQC_CACHE_ENABLE 0x908 +#define VC_EQC_CACHE_EN_MASK PPC_BITMASK(0, 15) +#define X_VC_EQC_SCRUB_TRIG 0x212 +#define VC_EQC_SCRUB_TRIG 0x910 +#define X_VC_EQC_SCRUB_MASK 0x213 +#define VC_EQC_SCRUB_MASK 0x918 +#define X_VC_EQC_CWATCH_SPEC 0x215 +#define VC_EQC_CONFIG 0x920 +#define X_VC_EQC_CONFIG 0x214 +#define VC_EQC_CONF_SYNC_IPI PPC_BIT(32) +#define VC_EQC_CONF_SYNC_HW PPC_BIT(33) +#define VC_EQC_CONF_SYNC_ESC1 PPC_BIT(34) +#define VC_EQC_CONF_SYNC_ESC2 PPC_BIT(35) +#define VC_EQC_CONF_SYNC_REDI PPC_BIT(36) +#define VC_EQC_CONF_EQP_INTERLEAVE PPC_BIT(38) +#define VC_EQC_CONF_ENABLE_END_s_BIT PPC_BIT(39) +#define VC_EQC_CONF_ENABLE_END_u_BIT PPC_BIT(40) +#define VC_EQC_CONF_ENABLE_END_c_BIT PPC_BIT(41) +#define VC_EQC_CONF_ENABLE_MORE_QSZ PPC_BIT(42) +#define VC_EQC_CONF_SKIP_ESCALATE PPC_BIT(43) +#define VC_EQC_CWATCH_SPEC 0x928 +#define VC_EQC_CWATCH_CONFLICT PPC_BIT(0) +#define VC_EQC_CWATCH_FULL PPC_BIT(8) +#define VC_EQC_CWATCH_BLOCKID PPC_BITMASK(28, 31) +#define VC_EQC_CWATCH_OFFSET PPC_BITMASK(40, 63) +#define X_VC_EQC_CWATCH_DAT0 0x216 +#define VC_EQC_CWATCH_DAT0 0x930 +#define X_VC_EQC_CWATCH_DAT1 0x217 +#define VC_EQC_CWATCH_DAT1 0x938 +#define X_VC_EQC_CWATCH_DAT2 0x218 +#define VC_EQC_CWATCH_DAT2 0x940 +#define X_VC_EQC_CWATCH_DAT3 0x219 +#define VC_EQC_CWATCH_DAT3 0x948 +#define X_VC_IVC_SCRUB_TRIG 0x222 +#define VC_IVC_SCRUB_TRIG 0x990 +#define X_VC_IVC_SCRUB_MASK 0x223 +#define VC_IVC_SCRUB_MASK 0x998 +#define X_VC_SBC_SCRUB_TRIG 0x232 +#define VC_SBC_SCRUB_TRIG 0xa10 +#define X_VC_SBC_SCRUB_MASK 0x233 +#define VC_SBC_SCRUB_MASK 0xa18 +#define VC_SCRUB_VALID PPC_BIT(0) +#define VC_SCRUB_WANT_DISABLE PPC_BIT(1) +#define VC_SCRUB_WANT_INVAL PPC_BIT(2) /* EQC and SBC only */ +#define VC_SCRUB_BLOCK_ID PPC_BITMASK(28, 31) +#define VC_SCRUB_OFFSET PPC_BITMASK(40, 63) +#define X_VC_IVC_CACHE_ENABLE 0x221 +#define VC_IVC_CACHE_ENABLE 0x988 +#define VC_IVC_CACHE_EN_MASK PPC_BITMASK(0, 15) +#define X_VC_SBC_CACHE_ENABLE 0x231 +#define VC_SBC_CACHE_ENABLE 0xa08 +#define VC_SBC_CACHE_EN_MASK PPC_BITMASK(0, 15) +#define VC_IVC_CACHE_SCRUB_TRIG 0x990 +#define VC_IVC_CACHE_SCRUB_MASK 0x998 +#define VC_SBC_CACHE_ENABLE 0xa08 +#define VC_SBC_CACHE_SCRUB_TRIG 0xa10 +#define VC_SBC_CACHE_SCRUB_MASK 0xa18 +#define VC_SBC_CONFIG 0xa20 +#define X_VC_SBC_CONFIG 0x234 +#define VC_SBC_CONF_CPLX_CIST PPC_BIT(44) +#define VC_SBC_CONF_CIST_BOTH PPC_BIT(45) +#define VC_SBC_CONF_NO_UPD_PRF PPC_BIT(59) + +/* VC1 register offsets */ + +/* VSD Table address register definitions (shared) */ +#define VST_ADDR_AUTOINC PPC_BIT(0) +#define VST_TABLE_SELECT PPC_BITMASK(13, 15) +#define VST_TSEL_IVT 0 +#define VST_TSEL_SBE 1 +#define VST_TSEL_EQDT 2 +#define VST_TSEL_VPDT 3 +#define VST_TSEL_IRQ 4 /* VC only */ +#define VST_TABLE_BLOCK PPC_BITMASK(27, 31) + +/* Number of queue overflow pages */ +#define VC_QUEUE_OVF_COUNT 6 + +/* Bits in a VSD entry. + * + * Note: the address is naturally aligned, we don't use a PPC_BITMASK, + * but just a mask to apply to the address before OR'ing it in. + * + * Note: VSD_FIRMWARE is a SW bit ! It hijacks an unused bit in the + * VSD and is only meant to be used in indirect mode ! + */ +#define VSD_MODE PPC_BITMASK(0, 1) +#define VSD_MODE_SHARED 1 +#define VSD_MODE_EXCLUSIVE 2 +#define VSD_MODE_FORWARD 3 +#define VSD_ADDRESS_MASK 0x0ffffffffffff000ull +#define VSD_MIGRATION_REG PPC_BITMASK(52, 55) +#define VSD_INDIRECT PPC_BIT(56) +#define VSD_TSIZE PPC_BITMASK(59, 63) +#define VSD_FIRMWARE PPC_BIT(2) /* Read warning above */ + +#define VC_EQC_SYNC_MASK \ + (VC_EQC_CONF_SYNC_IPI | \ + VC_EQC_CONF_SYNC_HW | \ + VC_EQC_CONF_SYNC_ESC1 | \ + VC_EQC_CONF_SYNC_ESC2 | \ + VC_EQC_CONF_SYNC_REDI) + + +#endif /* PPC_PNV_XIVE_REGS_H */ diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index ffa4a0899705..cf86ab816f22 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -25,6 +25,7 @@ #include "hw/ppc/pnv_lpc.h" #include "hw/ppc/pnv_psi.h" #include "hw/ppc/pnv_occ.h" +#include "hw/ppc/pnv_xive.h" =20 #define TYPE_PNV_CHIP "pnv-chip" #define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP) @@ -61,6 +62,8 @@ typedef struct PnvChip { PnvLpcController lpc; PnvPsi psi; PnvOCC occ; + + PnvXive *xive; } PnvChip; =20 typedef enum PnvPhysMapType { @@ -68,6 +71,10 @@ typedef enum PnvPhysMapType { PNV_MAP_ICP, PNV_MAP_PSIHB, PNV_MAP_PSIHB_FSP, + PNV_MAP_XIVE_VC, + PNV_MAP_XIVE_PC, + PNV_MAP_XIVE_IC, + PNV_MAP_XIVE_TM, } PnvPhysMapType; =20 typedef struct PnvPhysMapEntry { @@ -210,4 +217,19 @@ static inline uint64_t pnv_map_base(const PnvChip *chi= p, PnvPhysMapType type) #define PNV_PSIHB_FSP_SIZE(chip) pnv_map_size(chip, PNV_MAP_PSIHB_FSP) #define PNV_PSIHB_FSP_BASE(chip) pnv_map_base(chip, PNV_MAP_PSIHB_FSP) =20 +/* + * POWER9 MMIO base addresses + */ +#define PNV_XIVE_VC_SIZE(chip) pnv_map_size(chip, PNV_MAP_XIVE_VC) +#define PNV_XIVE_VC_BASE(chip) pnv_map_base(chip, PNV_MAP_XIVE_VC) + +#define PNV_XIVE_PC_SIZE(chip) pnv_map_size(chip, PNV_MAP_XIVE_PC) +#define PNV_XIVE_PC_BASE(chip) pnv_map_base(chip, PNV_MAP_XIVE_PC) + +#define PNV_XIVE_IC_SIZE(chip) pnv_map_size(chip, PNV_MAP_XIVE_IC) +#define PNV_XIVE_IC_BASE(chip) pnv_map_base(chip, PNV_MAP_XIVE_IC) + +#define PNV_XIVE_TM_SIZE(chip) pnv_map_size(chip, PNV_MAP_XIVE_TM) +#define PNV_XIVE_TM_BASE(chip) pnv_map_base(chip, PNV_MAP_XIVE_TM) + #endif /* _PPC_PNV_H */ diff --git a/include/hw/ppc/pnv_xive.h b/include/hw/ppc/pnv_xive.h new file mode 100644 index 000000000000..573be7b16065 --- /dev/null +++ b/include/hw/ppc/pnv_xive.h @@ -0,0 +1,92 @@ +/* + * QEMU PowerPC XIVE interrupt controller model + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef PPC_PNV_XIVE_H +#define PPC_PNV_XIVE_H + +#include "hw/sysbus.h" +#include "hw/ppc/xive.h" + +#define TYPE_PNV_XIVE "pnv-xive" +#define PNV_XIVE(obj) OBJECT_CHECK(PnvXive, (obj), TYPE_PNV_XIVE) + +#define XIVE_BLOCK_MAX 16 + +typedef struct PnvXive { + XiveRouter parent_obj; + + /* Can be overridden by XIVE configuration */ + uint32_t thread_chip_id; + uint32_t chip_id; + + /* Interrupt controller regs */ + uint64_t regs[0x300]; + MemoryRegion xscom_regs; + + /* For IPIs and accelerator interrupts */ + uint32_t nr_irqs; + XiveSource source; + + uint32_t nr_eqs; + XiveEQSource eq_source; + + /* Cache update registers */ + uint64_t eqc_watch[4]; + uint64_t vpc_watch[8]; + + /* Virtual Structure Table Descriptors : IVT, SBE, EQDT, VPDT, IRQ */ + uint64_t vsds[5][XIVE_BLOCK_MAX]; + + /* Set Translation tables */ + bool set_xlate_autoinc; + uint64_t set_xlate_index; + uint64_t set_xlate; + uint64_t set_xlate_blk[16]; /* Block Scope Table (0-15) */ + uint64_t set_xlate_mig[16]; /* Migration Register Table (1-15) */ + uint64_t set_xlate_vdt[16]; /* VDT Domain Table (0-15) */ + uint64_t set_xlate_edt[64]; /* EDT Domain Table (0-63) */ + + /* Interrupt controller MMIO */ + hwaddr ic_base; + uint32_t ic_shift; + MemoryRegion ic_mmio; + MemoryRegion ic_reg_mmio; + MemoryRegion ic_notify_mmio; + + /* VC memory regions */ + hwaddr vc_base; + uint64_t vc_size; + uint32_t vc_shift; + MemoryRegion vc_mmio; + hwaddr ipi_base; + hwaddr eq_base; + + /* PC memory regions */ + hwaddr pc_base; + uint64_t pc_size; + uint32_t pc_shift; + MemoryRegion pc_mmio; + + /* TIMA memory regions */ + hwaddr tm_base; + uint32_t tm_shift; + MemoryRegion tm_mmio; + MemoryRegion tm_mmio_indirect; + + /* CPU for indirect TIMA access */ + PowerPCCPU *cpu_ind; +} PnvXive; + +void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon); + +typedef struct PnvChip PnvChip; + +void pnv_chip_xive_realize(PnvChip *chip, Error **errp); + +#endif /* PPC_PNV_XIVE_H */ diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h index 255b26a5aaf6..f4b1649ffffa 100644 --- a/include/hw/ppc/pnv_xscom.h +++ b/include/hw/ppc/pnv_xscom.h @@ -73,6 +73,9 @@ typedef struct PnvXScomInterfaceClass { #define PNV_XSCOM_OCC_BASE 0x0066000 #define PNV_XSCOM_OCC_SIZE 0x6000 =20 +#define PNV_XSCOM_XIVE_BASE 0x5013000 +#define PNV_XSCOM_XIVE_SIZE 0x300 + extern void pnv_xscom_realize(PnvChip *chip, Error **errp); extern int pnv_dt_xscom(PnvChip *chip, void *fdt, int offset); =20 diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index a2c1cc6b5126..29c780605c33 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -235,6 +235,7 @@ int xive_router_get_vp(XiveRouter *xrtr, uint8_t vp_blk= , uint32_t vp_idx, XiveVP *vp); int xive_router_set_vp(XiveRouter *xrtr, uint8_t vp_blk, uint32_t vp_idx, XiveVP *vp); +void xive_router_notify(XiveFabric *xf, uint32_t lisn); =20 /* * XIVE EQ ESBs diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c new file mode 100644 index 000000000000..43b7fea8a0f2 --- /dev/null +++ b/hw/intc/pnv_xive.c @@ -0,0 +1,1485 @@ +/* + * QEMU PowerPC XIVE interrupt controller model + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "target/ppc/cpu.h" +#include "sysemu/cpus.h" +#include "sysemu/dma.h" +#include "monitor/monitor.h" +#include "hw/ppc/fdt.h" +#include "hw/ppc/pnv.h" +#include "hw/ppc/pnv_xscom.h" +#include "hw/ppc/pnv_xive.h" +#include "hw/ppc/xive_regs.h" +#include "hw/ppc/ppc.h" + +#include + +#include "pnv_xive_regs.h" + +#define GIRQ_TO_BLK(__g) (((__g) >> 20) & 0xf) +#define GIRQ_TO_IDX(__g) ((__g) & 0x000fffff) +#define BLKIDX_TO_GIRQ(__b, __i) (((uint32_t)(__b)) << 20 | (__i)) + +/* + * Virtual structures table accessors + */ +typedef struct XiveVstInfo { + const char *name; + uint32_t size; + uint32_t max_blocks; +} XiveVstInfo; + +static const XiveVstInfo vst_infos[] =3D { + [VST_TSEL_IVT] =3D { "IVT", sizeof(XiveIVE), 16 }, + [VST_TSEL_SBE] =3D { "SBE", 0, 16 }, + [VST_TSEL_EQDT] =3D { "EQDT", sizeof(XiveEQ), 16 }, + [VST_TSEL_VPDT] =3D { "VPDT", sizeof(XiveVP), 32 }, + + /* Interrupt fifo backing store table : + * + * 0 - IPI, + * 1 - HWD, + * 2 - First escalate, + * 3 - Second escalate, + * 4 - Redistribution, + * 5 - IPI cascaded queue ? + */ + [VST_TSEL_IRQ] =3D { "IRQ", 0, 6 }, +}; + +/* + * Find a remote XIVE IC. The VST accesses are done through MMIO but + * this is much simpler and it is not a strong model violation. + */ +static PnvXive *pnv_xive_get_ic(uint8_t blk) +{ + PnvMachineState *pnv =3D PNV_MACHINE(qdev_get_machine()); + int i; + + for (i =3D 0; i < pnv->num_chips; i++) { + PnvXive *xive =3D pnv->chips[i]->xive; + bool chip_override =3D + xive->regs[PC_GLOBAL_CONFIG >> 3] & PC_GCONF_CHIPID_OVR; + + if (chip_override) { + if (xive->chip_id =3D=3D blk) { + return xive; + } + } else { + ; /* TODO: Block scope support */ + } + } + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: unknown chip with block id %d !?= \n", + blk); + return NULL; +} + +static uint64_t pnv_xive_vst_addr(PnvXive *xive, uint8_t type, uint8_t blk, + uint32_t idx) +{ + uint64_t vs_per_page =3D (1ull << (xive->vc_shift + 1)) / + vst_infos[type].size; + uint64_t vsd; + uint64_t vst_addr; + uint64_t vsd_addr; + uint64_t page_addr; + + if (blk >=3D vst_infos[type].max_blocks) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid block id %d for VST" + " %s %d !?\n", blk, vst_infos[type].name, idx); + return 0; + } + + vsd =3D xive->vsds[type][blk]; + vst_addr =3D vsd & VSD_ADDRESS_MASK; + + /* Remote VST accesses */ + if (GETFIELD(VSD_MODE, vsd) =3D=3D VSD_MODE_FORWARD) { + PnvXive *xive =3D pnv_xive_get_ic(blk); + + return xive ? pnv_xive_vst_addr(xive, type, blk, idx) : 0; + } + + if (!(VSD_INDIRECT & vsd)) { + return vst_addr + idx * vst_infos[type].size; + } + + vsd_addr =3D vst_addr + (idx / vs_per_page); + vsd =3D ldq_be_dma(&address_space_memory, vsd_addr); + + /* We don't support nested indirect tables */ + if (VSD_INDIRECT & vsd) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: found a nested indirect" + " table at index %d\n", idx); + return 0; + } + + page_addr =3D vsd & VSD_ADDRESS_MASK; + if (!page_addr) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid %s entry %x/%x !?\n", + vst_infos[type].name, blk, idx); + return 0; + } + + return page_addr + (idx % vs_per_page) * vst_infos[type].size; +} + +static int pnv_xive_get_eq(XiveRouter *xrtr, uint8_t blk, uint32_t idx, + XiveEQ *eq) +{ + PnvXive *xive =3D PNV_XIVE(xrtr); + uint64_t eq_addr =3D pnv_xive_vst_addr(xive, VST_TSEL_EQDT, blk, idx); + + if (!eq_addr) { + return -1; + } + + cpu_physical_memory_read(eq_addr, eq, sizeof(XiveEQ)); + eq->w0 =3D be32_to_cpu(eq->w0); + eq->w1 =3D be32_to_cpu(eq->w1); + eq->w2 =3D be32_to_cpu(eq->w2); + eq->w3 =3D be32_to_cpu(eq->w3); + eq->w4 =3D be32_to_cpu(eq->w4); + eq->w5 =3D be32_to_cpu(eq->w5); + eq->w6 =3D be32_to_cpu(eq->w6); + eq->w7 =3D be32_to_cpu(eq->w7); + + return 0; +} + +static int pnv_xive_set_eq(XiveRouter *xrtr, uint8_t blk, uint32_t idx, + XiveEQ *in_eq) +{ + PnvXive *xive =3D PNV_XIVE(xrtr); + XiveEQ eq; + uint64_t eq_addr =3D pnv_xive_vst_addr(xive, VST_TSEL_EQDT, blk, idx); + + if (!eq_addr) { + return -1; + } + + eq.w0 =3D cpu_to_be32(in_eq->w0); + eq.w1 =3D cpu_to_be32(in_eq->w1); + eq.w2 =3D cpu_to_be32(in_eq->w2); + eq.w3 =3D cpu_to_be32(in_eq->w3); + eq.w4 =3D cpu_to_be32(in_eq->w4); + eq.w5 =3D cpu_to_be32(in_eq->w5); + eq.w6 =3D cpu_to_be32(in_eq->w6); + eq.w7 =3D cpu_to_be32(in_eq->w7); + cpu_physical_memory_write(eq_addr, &eq, sizeof(XiveEQ)); + return 0; +} + +static int pnv_xive_eq_update(PnvXive *xive, uint8_t blk, uint32_t idx) +{ + uint64_t eq_addr =3D pnv_xive_vst_addr(xive, VST_TSEL_EQDT, blk, idx); + + if (!eq_addr) { + return -1; + } + + cpu_physical_memory_write(eq_addr, xive->eqc_watch, sizeof(XiveEQ)); + return 0; +} + +static int pnv_xive_get_vp(XiveRouter *xrtr, uint8_t blk, uint32_t idx, + XiveVP *vp) +{ + PnvXive *xive =3D PNV_XIVE(xrtr); + uint64_t vp_addr =3D pnv_xive_vst_addr(xive, VST_TSEL_VPDT, blk, idx); + + if (!vp_addr) { + return -1; + } + + cpu_physical_memory_read(vp_addr, vp, sizeof(XiveVP)); + vp->w0 =3D cpu_to_be32(vp->w0); + vp->w1 =3D cpu_to_be32(vp->w1); + vp->w2 =3D cpu_to_be32(vp->w2); + vp->w3 =3D cpu_to_be32(vp->w3); + vp->w4 =3D cpu_to_be32(vp->w4); + vp->w5 =3D cpu_to_be32(vp->w5); + vp->w6 =3D cpu_to_be32(vp->w6); + vp->w7 =3D cpu_to_be32(vp->w7); + + return 0; +} + +static int pnv_xive_set_vp(XiveRouter *xrtr, uint8_t blk, uint32_t idx, + XiveVP *in_vp) +{ + PnvXive *xive =3D PNV_XIVE(xrtr); + XiveVP vp; + uint64_t vp_addr =3D pnv_xive_vst_addr(xive, VST_TSEL_VPDT, blk, idx); + + if (!vp_addr) { + return -1; + } + + vp.w0 =3D cpu_to_be32(in_vp->w0); + vp.w1 =3D cpu_to_be32(in_vp->w1); + vp.w2 =3D cpu_to_be32(in_vp->w2); + vp.w3 =3D cpu_to_be32(in_vp->w3); + vp.w4 =3D cpu_to_be32(in_vp->w4); + vp.w5 =3D cpu_to_be32(in_vp->w5); + vp.w6 =3D cpu_to_be32(in_vp->w6); + vp.w7 =3D cpu_to_be32(in_vp->w7); + cpu_physical_memory_write(vp_addr, &vp, sizeof(XiveVP)); + return 0; +} + +static int pnv_xive_vp_update(PnvXive *xive, uint8_t blk, uint32_t idx) +{ + uint64_t vp_addr =3D pnv_xive_vst_addr(xive, VST_TSEL_VPDT, blk, idx); + + if (!vp_addr) { + return -1; + } + + cpu_physical_memory_write(vp_addr, xive->vpc_watch, sizeof(XiveVP)); + return 0; +} + +static int pnv_xive_get_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive) +{ + PnvXive *xive =3D PNV_XIVE(xrtr); + uint8_t blk =3D GIRQ_TO_BLK(lisn); + uint32_t idx =3D GIRQ_TO_IDX(lisn); + uint64_t ive_addr; + + /* TODO: check when are remote IVE lookups needed */ + if (pnv_xive_get_ic(blk) !=3D xive) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Remote IVE %x lookup not " + "supported\n", lisn); + return -1; + } + + ive_addr =3D pnv_xive_vst_addr(xive, VST_TSEL_IVT, blk, idx); + if (!ive_addr) { + return -1; + } + + ive->w &=3D ~IVE_VALID; + *((uint64_t *) ive) =3D ldq_be_dma(&address_space_memory, ive_addr); + return 0; +} + +static int pnv_xive_set_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive) +{ + /* All done. We don't use the state bit table in memory */ + return 0; +} + +static int pnv_xive_ive_update(PnvXive *xive, uint32_t idx) +{ + /* All done. We don't use the state bit table in memory */ + return 0; +} + + +/* + * Virtual Structure Tables (VST) configuration + */ +static void pnv_xive_table_set_exclusive(PnvXive *xive, uint8_t type, + uint8_t blk, uint64_t vsd) +{ + uint32_t size =3D 1 << (GETFIELD(VSD_TSIZE, vsd) + 12); + + if (!size) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid %s table\n", + vst_infos[type].name); + return; + } + + switch (type) { + case VST_TSEL_IVT: + break; + + case VST_TSEL_EQDT: + /* + * FIXME: skiboot sets the EQDT as indirect with 64K subpages, + * which is too big for the VC MMIO region. I believe this is + * an indexing error. + */ + vsd &=3D ~VSD_TSIZE; + vsd |=3D SETFIELD(VSD_TSIZE, 0ull, 0); + break; + + case VST_TSEL_VPDT: + /* FIXME: skiboot sets the VPDT as indirect with 64K subpages. */ + vsd &=3D ~VSD_TSIZE; + vsd |=3D SETFIELD(VSD_TSIZE, 0ull, 0); + break; + + case VST_TSEL_SBE: + /* + * contains the backing store pages for the source state + * bits. The XiveSource model does not use it. + */ + break; + + case VST_TSEL_IRQ: /* VC only */ + /* + * These tables contains the backing store pages for the + * interrupt fifos of the VC sub-engine in case of overflow + * but we don't model the fifos. + */ + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid table type %d\n", ty= pe); + return; + } + + /* Keep the VSD for later use */ + xive->vsds[type][blk] =3D vsd; +} + +/* + * Both PC and VC sub-engines are configured as each use the Virtual + * Structure Tables : SBE, IVE, EQD and VPD. + */ +static void pnv_xive_table_set_data(PnvXive *xive, uint64_t vsd, bool pc_e= ngine) +{ + uint8_t mode =3D GETFIELD(VSD_MODE, vsd); + uint8_t type =3D GETFIELD(VST_TABLE_SELECT, + xive->regs[VC_VSD_TABLE_ADDR >> 3]); + uint8_t blk =3D GETFIELD(VST_TABLE_BLOCK, + xive->regs[VC_VSD_TABLE_ADDR >> 3]); + bool gconf_indirect =3D pc_engine ? + xive->regs[VC_GLOBAL_CONFIG >> 3] & VC_GCONF_INDIRECT : + xive->regs[PC_GLOBAL_CONFIG >> 3] & PC_GCONF_INDIRECT; + + if (type > VST_TSEL_IRQ) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/IC: invalid table type %d\n", + type); + return; + } + + if (blk >=3D vst_infos[type].max_blocks) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/IC: invalid block id %d for" + " %s table", blk, vst_infos[type].name); + return; + } + + if ((VSD_INDIRECT & vsd) && !gconf_indirect) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/IC: invalid %s indirect table= \n", + vst_infos[type].name); + return; + } + + /* + * Only take the VC configuration into account because the + * XiveRouter model combines both VC and PC sub-engines + */ + if (pc_engine) { + return; + } + + switch (mode) { + case VSD_MODE_FORWARD: + /* Only record the descriptor for remote ICs. */ + xive->vsds[type][blk] =3D vsd; + break; + + case VSD_MODE_EXCLUSIVE: + pnv_xive_table_set_exclusive(xive, type, blk, vsd); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/IC: invalid table mode %d\n", + mode); + return; + } +} + +/* + * IPI and EQ sources realize routines + * + * The setting of the MMIO regions of the IPIs and EQs ESB pages make + * the assumption that the EDT set translation table defines + * contiguous range for each but this is not true. + * + * Instead we should be using a top level VC MMIO region dispatching + * on two different address space depending on the EDT set translation + * table. For later. + */ +#define PNV_XIVE_SET_XLATE_SIZE (8ull << 30) + +static uint64_t pnv_xive_set_xlate_edt_size(PnvXive *xive, uint64_t type) +{ + uint64_t size =3D 0; + int i; + + for (i =3D 0; i < ARRAY_SIZE(xive->set_xlate_edt); i++) { + uint64_t edt_type =3D GETFIELD(CQ_TDR_EDT_TYPE, xive->set_xlate_ed= t[i]); + + if (edt_type =3D=3D type) { + size +=3D PNV_XIVE_SET_XLATE_SIZE; + } + } + + return size; +} + +static void pnv_xive_source_realize(PnvXive *xive, Error **errp) +{ + XiveSource *xsrc =3D &xive->source; + Error *local_err =3D NULL; + uint64_t ipi_mmio_size =3D pnv_xive_set_xlate_edt_size(xive, CQ_TDR_ED= T_IPI); + + /* Two pages per IRQ */ + xive->nr_irqs =3D ipi_mmio_size / (1ull << (xive->vc_shift + 1)); + xive->ipi_base =3D xive->vc_base; + + object_property_set_int(OBJECT(xsrc), xive->nr_irqs, "nr-irqs", + &error_fatal); + object_property_add_const_link(OBJECT(xsrc), "xive", OBJECT(xive), + &error_fatal); + object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + qdev_set_parent_bus(DEVICE(xsrc), sysbus_get_default()); + + /* + * Install the ESB MMIO region in the overall VC region. + * + * TODO: Use an IPI ESB address_space + */ + memory_region_add_subregion(&xive->vc_mmio, 0, &xsrc->esb_mmio); + + /* Start in clean state */ + device_reset(DEVICE(&xive->source)); +} + +static void pnv_xive_eq_source_realize(PnvXive *xive, Error **errp) +{ + XiveEQSource *eq_xsrc =3D &xive->eq_source; + Error *local_err =3D NULL; + uint64_t ipi_mmio_size =3D pnv_xive_set_xlate_edt_size(xive, CQ_TDR_ED= T_IPI); + uint64_t eq_mmio_size =3D pnv_xive_set_xlate_edt_size(xive, CQ_TDR_EDT= _EQ); + + /* Two pages per EQ: ESn and ESe */ + xive->nr_eqs =3D eq_mmio_size / (1ull << (xive->vc_shift + 1)); + xive->eq_base =3D xive->vc_base + ipi_mmio_size; + + object_property_set_int(OBJECT(eq_xsrc), xive->nr_eqs, "nr-eqs", + &error_fatal); + object_property_add_const_link(OBJECT(eq_xsrc), "xive", OBJECT(xive), + &error_fatal); + object_property_set_bool(OBJECT(eq_xsrc), true, "realized", &local_err= ); + if (local_err) { + error_propagate(errp, local_err); + return; + } + qdev_set_parent_bus(DEVICE(eq_xsrc), sysbus_get_default()); + + /* + * Install the EQ ESB MMIO region in the overall VC region + * + * TODO: Use an EQ ESB address_space + */ + memory_region_add_subregion(&xive->vc_mmio, ipi_mmio_size, + &eq_xsrc->esb_mmio); +} + +/* + * XIVE Set Translation Table configuration + */ +static int pnv_xive_set_xlate_update(PnvXive *xive, uint64_t val) +{ + uint8_t index =3D xive->set_xlate_autoinc ? + xive->set_xlate_index++ : xive->set_xlate_index; + uint8_t max_index; + uint64_t *xlate_table; + + switch (xive->set_xlate) { + case CQ_TAR_TSEL_BLK: + max_index =3D ARRAY_SIZE(xive->set_xlate_blk); + xlate_table =3D xive->set_xlate_blk; + break; + case CQ_TAR_TSEL_MIG: + max_index =3D ARRAY_SIZE(xive->set_xlate_mig); + xlate_table =3D xive->set_xlate_mig; + break; + case CQ_TAR_TSEL_EDT: + max_index =3D ARRAY_SIZE(xive->set_xlate_edt); + xlate_table =3D xive->set_xlate_edt; + break; + case CQ_TAR_TSEL_VDT: + max_index =3D ARRAY_SIZE(xive->set_xlate_vdt); + xlate_table =3D xive->set_xlate_vdt; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid xlate table set %d\n= ", + (int) xive->set_xlate); + return -1; + } + + if (index >=3D max_index) { + return -1; + } + + xlate_table[index] =3D val; + + /* + * When we are done setting the EDT set translation table, create + * the source objects for PnvXive. + */ + if (xive->set_xlate =3D=3D CQ_TAR_TSEL_EDT && index =3D=3D max_index -= 1) { + pnv_xive_source_realize(xive, &error_fatal); + pnv_xive_eq_source_realize(xive, &error_fatal); + } + + return 0; +} + +static int pnv_xive_set_xlate_select(PnvXive *xive, uint64_t val) +{ + xive->set_xlate_autoinc =3D val & CQ_TAR_TBL_AUTOINC; + xive->set_xlate =3D val & CQ_TAR_TSEL; + xive->set_xlate_index =3D GETFIELD(CQ_TAR_TSEL_INDEX, val); + + return 0; +} + +/* + * Accesses to the TIMA can be done from the indirect range and the + * thread id (PIR) has to be configured in the IC. Used For resets. + */ +static void pnv_xive_thread_indirect_set(PnvXive *xive, uint64_t val) +{ + int pir =3D GETFIELD(PC_TCTXT_INDIR_THRDID, xive->regs[PC_TCTXT_INDIR0= >> 3]); + + if (val & PC_TCTXT_INDIR_VALID) { + if (xive->cpu_ind) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/IC: indirect access alrea= dy" + " set for invalid PIR %d", pir); + } + + pir =3D GETFIELD(PC_TCTXT_INDIR_THRDID, val) & 0xff; + xive->cpu_ind =3D ppc_get_vcpu_by_pir(pir); + if (!xive->cpu_ind) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/IC: invalid PIR %d for" + " indirect access\n", pir); + } + } else { + xive->cpu_ind =3D NULL; + } +} + +/* + * Interrupt Controller registers MMIO + */ +static void pnv_xive_ic_reg_write(PnvXive *xive, uint32_t offset, uint64_t= val, + bool mmio) +{ + MemoryRegion *sysmem =3D get_system_memory(); + uint32_t reg =3D offset >> 3; + + switch (offset) { + + /* + * XIVE CQ (PowerBus bridge) settings + */ + case CQ_MSGSND: /* msgsnd for doorbells */ + case CQ_FIRMASK_OR: /* FIR error reporting */ + case CQ_PBI_CTL: + if (val & CQ_PBI_PC_64K) { + xive->pc_shift =3D 16; + } + if (val & CQ_PBI_VC_64K) { + xive->vc_shift =3D 16; + } + break; + case CQ_CFG_PB_GEN: /* PowerBus General Configuration */ + /* + * TODO: CQ_INT_ADDR_OPT for 1-block-per-chip mode + */ + xive->regs[reg] =3D val; + break; + + /* + * XIVE Virtualization Controller settings + */ + case VC_GLOBAL_CONFIG: + xive->regs[reg] =3D val; + break; + + /* + * XIVE Presenter Controller settings + */ + case PC_GLOBAL_CONFIG: + /* Overrides Int command Chip ID with the Chip ID field */ + if (val & PC_GCONF_CHIPID_OVR) { + xive->chip_id =3D GETFIELD(PC_GCONF_CHIPID, val); + } + xive->regs[reg] =3D val; + break; + case PC_TCTXT_CFG: + /* + * TODO: PC_TCTXT_CFG_BLKGRP_EN for block group support + * TODO: PC_TCTXT_CFG_HARD_CHIPID_BLK + */ + + /* + * Moves the chipid into block field for hardwired CAM + * compares Block offset value is adjusted to 0b0..01 & ThrdId + */ + if (val & PC_TCTXT_CHIPID_OVERRIDE) { + xive->thread_chip_id =3D GETFIELD(PC_TCTXT_CHIPID, val); + } + break; + case PC_TCTXT_TRACK: /* Enable block tracking (DD2) */ + xive->regs[reg] =3D val; + break; + + /* + * Misc settings + */ + case VC_EQC_CONFIG: /* enable silent escalation */ + case VC_SBC_CONFIG: /* Store EOI configuration */ + case VC_AIB_TX_ORDER_TAG2: + xive->regs[reg] =3D val; + break; + + /* + * XIVE BAR settings (XSCOM only) + */ + case CQ_RST_CTL: + /* resets all bars */ + break; + case CQ_IC_BAR: /* IC BAR and page size. 8 * 64k */ + xive->ic_shift =3D val & CQ_IC_BAR_64K ? 16 : 12; + if (!(val & CQ_IC_BAR_VALID)) { + xive->ic_base =3D 0; + if (xive->regs[reg] & CQ_IC_BAR_VALID) { + memory_region_del_subregion(&xive->ic_mmio, + &xive->ic_reg_mmio); + memory_region_del_subregion(&xive->ic_mmio, + &xive->ic_notify_mmio); + memory_region_del_subregion(sysmem, &xive->ic_mmio); + memory_region_del_subregion(sysmem, &xive->tm_mmio_indirec= t); + } + } else { + xive->ic_base =3D val & ~(CQ_IC_BAR_VALID | CQ_IC_BAR_64K); + if (!(xive->regs[reg] & CQ_IC_BAR_VALID)) { + memory_region_add_subregion(sysmem, xive->ic_base, + &xive->ic_mmio); + memory_region_add_subregion(&xive->ic_mmio, 0, + &xive->ic_reg_mmio); + memory_region_add_subregion(&xive->ic_mmio, + 1ul << xive->ic_shift, + &xive->ic_notify_mmio); + memory_region_add_subregion(sysmem, + xive->ic_base + (4ull << xive->ic_shift= ), + &xive->tm_mmio_indirect); + } + } + xive->regs[reg] =3D val; + break; + case CQ_TM1_BAR: /* TM BAR and page size. 4 * 64k */ + case CQ_TM2_BAR: /* second TM BAR is for hotplug use */ + xive->tm_shift =3D val & CQ_TM_BAR_64K ? 16 : 12; + if (!(val & CQ_TM_BAR_VALID)) { + xive->tm_base =3D 0; + if (xive->regs[reg] & CQ_TM_BAR_VALID) { + memory_region_del_subregion(sysmem, &xive->tm_mmio); + } + } else { + xive->tm_base =3D val & ~(CQ_TM_BAR_VALID | CQ_TM_BAR_64K); + if (!(xive->regs[reg] & CQ_TM_BAR_VALID)) { + memory_region_add_subregion(sysmem, xive->tm_base, + &xive->tm_mmio); + } + } + xive->regs[reg] =3D val; + break; + case CQ_PC_BAR: + if (!(val & CQ_PC_BAR_VALID)) { + xive->pc_base =3D 0; + if (xive->regs[reg] & CQ_PC_BAR_VALID) { + memory_region_del_subregion(sysmem, &xive->pc_mmio); + } + } else { + xive->pc_base =3D val & ~(CQ_PC_BAR_VALID); + if (!(xive->regs[reg] & CQ_PC_BAR_VALID)) { + memory_region_add_subregion(sysmem, xive->pc_base, + &xive->pc_mmio); + } + } + xive->regs[reg] =3D val; + break; + case CQ_PC_BARM: /* TODO: PC BAR size */ + xive->pc_size =3D (~val + 1) & CQ_PC_BARM_MASK; + xive->regs[reg] =3D val; + break; + case CQ_VC_BAR: + if (!(val & CQ_VC_BAR_VALID)) { + xive->vc_base =3D 0; + if (xive->regs[reg] & CQ_VC_BAR_VALID) { + memory_region_del_subregion(sysmem, &xive->vc_mmio); + } + } else { + xive->vc_base =3D val & ~(CQ_VC_BAR_VALID); + if (!(xive->regs[reg] & CQ_VC_BAR_VALID)) { + memory_region_add_subregion(sysmem, xive->vc_base, + &xive->vc_mmio); + } + } + xive->regs[reg] =3D val; + break; + case CQ_VC_BARM: /* TODO: VC BAR size */ + xive->vc_size =3D (~val + 1) & CQ_VC_BARM_MASK; + xive->regs[reg] =3D val; + break; + + + /* + * XIVE Set Translation Table settings. Defines the MMIO regions + * for the ESB pages of the IPIs and of the EQs + */ + case CQ_TAR: /* Set Translation Table Address */ + pnv_xive_set_xlate_select(xive, val); + break; + case CQ_TDR: /* Set Translation Table Data */ + pnv_xive_set_xlate_update(xive, val); + break; + + /* + * XIVE VC and PC virtual structure table settings + */ + case VC_VSD_TABLE_ADDR: + case PC_VSD_TABLE_ADDR: /* Virtual table selector */ + xive->regs[reg] =3D val; + break; + case VC_VSD_TABLE_DATA: /* Virtual table setting */ + case PC_VSD_TABLE_DATA: + pnv_xive_table_set_data(xive, val, offset =3D=3D PC_VSD_TABLE_DATA= ); + break; + + /* + * Interrupt fifo overflow in memory backing store. We don't model + * the VC interrupt fifos. Just ignore. + */ + case VC_IRQ_CONFIG_IPI: + case VC_IRQ_CONFIG_HW: + case VC_IRQ_CONFIG_CASCADE1: + case VC_IRQ_CONFIG_CASCADE2: + case VC_IRQ_CONFIG_REDIST: + case VC_IRQ_CONFIG_IPI_CASC: + xive->regs[reg] =3D val; + break; + + /* + * XIVE hardware thread enablement + */ + case PC_THREAD_EN_REG0_SET: /* Physical Thread Enable */ + case PC_THREAD_EN_REG1_SET: /* Physical Thread Enable (fused core) */ + xive->regs[reg] |=3D val; + break; + case PC_THREAD_EN_REG0_CLR: + xive->regs[PC_THREAD_EN_REG0_SET >> 3] &=3D ~val; + break; + case PC_THREAD_EN_REG1_CLR: + xive->regs[PC_THREAD_EN_REG1_SET >> 3] &=3D ~val; + break; + + /* + * Indirect TIMA access set up. Defines the CPU to use. + */ + case PC_TCTXT_INDIR0: + pnv_xive_thread_indirect_set(xive, val); + xive->regs[reg] =3D val; + break; + case PC_TCTXT_INDIR1: + case PC_TCTXT_INDIR2: + case PC_TCTXT_INDIR3: + /* TODO: check what PC_TCTXT_INDIR[123] are for */ + xive->regs[reg] =3D val; + break; + + /* + * XIVE PC & VC cache updates for IVE, VPD and EQD + */ + case PC_VPC_SCRUB_MASK: + case PC_VPC_CWATCH_SPEC: + case VC_EQC_SCRUB_MASK: + case VC_EQC_CWATCH_SPEC: + case VC_IVC_SCRUB_MASK: + xive->regs[reg] =3D val; + break; + case VC_IVC_SCRUB_TRIG: + pnv_xive_ive_update(xive, GETFIELD(VC_SCRUB_OFFSET, val)); + break; + case PC_VPC_CWATCH_DAT0: + case PC_VPC_CWATCH_DAT1: + case PC_VPC_CWATCH_DAT2: + case PC_VPC_CWATCH_DAT3: + case PC_VPC_CWATCH_DAT4: + case PC_VPC_CWATCH_DAT5: + case PC_VPC_CWATCH_DAT6: + case PC_VPC_CWATCH_DAT7: + xive->vpc_watch[(offset - PC_VPC_CWATCH_DAT0) / 8] =3D cpu_to_be64= (val); + break; + case PC_VPC_SCRUB_TRIG: + pnv_xive_vp_update(xive, GETFIELD(PC_SCRUB_BLOCK_ID, val), + GETFIELD(PC_SCRUB_OFFSET, val)); + break; + case VC_EQC_CWATCH_DAT0: + case VC_EQC_CWATCH_DAT1: + case VC_EQC_CWATCH_DAT2: + case VC_EQC_CWATCH_DAT3: + xive->eqc_watch[(offset - VC_EQC_CWATCH_DAT0) / 8] =3D cpu_to_be64= (val); + break; + case VC_EQC_SCRUB_TRIG: + pnv_xive_eq_update(xive, GETFIELD(VC_SCRUB_BLOCK_ID, val), + GETFIELD(VC_SCRUB_OFFSET, val)); + break; + + /* + * XIVE PC & VC cache invalidation + */ + case PC_AT_KILL: + xive->regs[reg] |=3D val; + break; + case VC_AT_MACRO_KILL: + xive->regs[reg] |=3D val; + break; + case PC_AT_KILL_MASK: + case VC_AT_MACRO_KILL_MASK: + xive->regs[reg] =3D val; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/IC: invalid writing to reg=3D= 0x%08x" + " mmio=3D%d\n", offset, mmio); + } +} + +static uint64_t pnv_xive_ic_reg_read(PnvXive *xive, uint32_t offset, bool = mmio) +{ + uint64_t val =3D 0; + uint32_t reg =3D offset >> 3; + + switch (offset) { + case CQ_CFG_PB_GEN: + case CQ_IC_BAR: + case CQ_TM1_BAR: + case CQ_TM2_BAR: + case CQ_PC_BAR: + case CQ_PC_BARM: + case CQ_VC_BAR: + case CQ_VC_BARM: + case CQ_TAR: + case CQ_TDR: + case CQ_PBI_CTL: + + case PC_TCTXT_CFG: + case PC_TCTXT_TRACK: + case PC_TCTXT_INDIR0: + case PC_TCTXT_INDIR1: + case PC_TCTXT_INDIR2: + case PC_TCTXT_INDIR3: + case PC_GLOBAL_CONFIG: + + case PC_VPC_SCRUB_MASK: + case PC_VPC_CWATCH_SPEC: + case PC_VPC_CWATCH_DAT0: + case PC_VPC_CWATCH_DAT1: + case PC_VPC_CWATCH_DAT2: + case PC_VPC_CWATCH_DAT3: + case PC_VPC_CWATCH_DAT4: + case PC_VPC_CWATCH_DAT5: + case PC_VPC_CWATCH_DAT6: + case PC_VPC_CWATCH_DAT7: + + case VC_GLOBAL_CONFIG: + case VC_AIB_TX_ORDER_TAG2: + + case VC_IRQ_CONFIG_IPI: + case VC_IRQ_CONFIG_HW: + case VC_IRQ_CONFIG_CASCADE1: + case VC_IRQ_CONFIG_CASCADE2: + case VC_IRQ_CONFIG_REDIST: + case VC_IRQ_CONFIG_IPI_CASC: + + case VC_EQC_SCRUB_MASK: + case VC_EQC_CWATCH_DAT0: + case VC_EQC_CWATCH_DAT1: + case VC_EQC_CWATCH_DAT2: + case VC_EQC_CWATCH_DAT3: + + case VC_EQC_CWATCH_SPEC: + case VC_IVC_SCRUB_MASK: + case VC_SBC_CONFIG: + case VC_AT_MACRO_KILL_MASK: + case VC_VSD_TABLE_ADDR: + case PC_VSD_TABLE_ADDR: + case VC_VSD_TABLE_DATA: + case PC_VSD_TABLE_DATA: + val =3D xive->regs[reg]; + break; + + case CQ_MSGSND: /* Identifies which cores have msgsnd enabled. + * Say all have. */ + val =3D 0xffffff0000000000; + break; + + /* + * XIVE PC & VC cache updates for IVE, VPD and EQD + */ + case PC_VPC_SCRUB_TRIG: + case VC_IVC_SCRUB_TRIG: + case VC_EQC_SCRUB_TRIG: + xive->regs[reg] &=3D ~VC_SCRUB_VALID; + val =3D xive->regs[reg]; + break; + + /* + * XIVE PC & VC cache invalidation + */ + case PC_AT_KILL: + xive->regs[reg] &=3D ~PC_AT_KILL_VALID; + val =3D xive->regs[reg]; + break; + case VC_AT_MACRO_KILL: + xive->regs[reg] &=3D ~VC_KILL_VALID; + val =3D xive->regs[reg]; + break; + + /* + * XIVE synchronisation + */ + case VC_EQC_CONFIG: + val =3D VC_EQC_SYNC_MASK; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/IC: invalid read reg=3D0x%08x" + " mmio=3D%d\n", offset, mmio); + } + + return val; +} + +static void pnv_xive_ic_reg_write_mmio(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + pnv_xive_ic_reg_write(opaque, addr, val, true); +} + +static uint64_t pnv_xive_ic_reg_read_mmio(void *opaque, hwaddr addr, + unsigned size) +{ + return pnv_xive_ic_reg_read(opaque, addr, true); +} + +static const MemoryRegionOps pnv_xive_ic_reg_ops =3D { + .read =3D pnv_xive_ic_reg_read_mmio, + .write =3D pnv_xive_ic_reg_write_mmio, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + }, + .impl =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + }, +}; + +/* + * Interrupt Controller MMIO: Notify port page (write only) + */ +#define PNV_XIVE_FORWARD_IPI 0x800 /* Forward IPI */ +#define PNV_XIVE_FORWARD_HW 0x880 /* Forward HW */ +#define PNV_XIVE_FORWARD_OS_ESC 0x900 /* Forward OS escalation */ +#define PNV_XIVE_FORWARD_HW_ESC 0x980 /* Forward Hyp escalation */ +#define PNV_XIVE_FORWARD_REDIS 0xa00 /* Forward Redistribution */ +#define PNV_XIVE_RESERVED5 0xa80 /* Cache line 5 PowerBUS operati= on */ +#define PNV_XIVE_RESERVED6 0xb00 /* Cache line 6 PowerBUS operati= on */ +#define PNV_XIVE_RESERVED7 0xb80 /* Cache line 7 PowerBUS operati= on */ + +/* VC synchronisation */ +#define PNV_XIVE_SYNC_IPI 0xc00 /* Sync IPI */ +#define PNV_XIVE_SYNC_HW 0xc80 /* Sync HW */ +#define PNV_XIVE_SYNC_OS_ESC 0xd00 /* Sync OS escalation */ +#define PNV_XIVE_SYNC_HW_ESC 0xd80 /* Sync Hyp escalation */ +#define PNV_XIVE_SYNC_REDIS 0xe00 /* Sync Redistribution */ + +/* PC synchronisation */ +#define PNV_XIVE_SYNC_PULL 0xe80 /* Sync pull context */ +#define PNV_XIVE_SYNC_PUSH 0xf00 /* Sync push context */ +#define PNV_XIVE_SYNC_VPC 0xf80 /* Sync remove VPC store */ + +static void pnv_xive_ic_hw_trigger(PnvXive *xive, hwaddr addr, uint64_t va= l) +{ + XiveFabricClass *xfc =3D XIVE_FABRIC_GET_CLASS(xive); + uint32_t ive_idx, ive_blk; + + /* The block Encoding on the PowerBUS is in a different bit range */ + ive_idx =3D GIRQ_TO_IDX(val); + ive_blk =3D (val >> 28) & 0xf; + val =3D BLKIDX_TO_GIRQ(ive_blk, ive_idx); + + xfc->notify(XIVE_FABRIC(xive), val); +} + +static void pnv_xive_ic_notify_write(void *opaque, hwaddr addr, uint64_t v= al, + unsigned size) +{ + /* VC: HW triggers */ + switch (addr) { + case 0x000 ... 0x7FF: + pnv_xive_ic_hw_trigger(opaque, addr, val); + break; + + /* VC: Forwarded IRQs */ + case PNV_XIVE_FORWARD_IPI: + case PNV_XIVE_FORWARD_HW: + case PNV_XIVE_FORWARD_OS_ESC: + case PNV_XIVE_FORWARD_HW_ESC: + case PNV_XIVE_FORWARD_REDIS: + /* TODO: forwarded IRQs. Should be like HW triggers */ + qemu_log_mask(LOG_UNIMP, "XIVE/IC: forwarded at @0x%"HWADDR_PRIx + " IRQ 0x%"PRIx64"\n", addr, val); + break; + + /* VC syncs */ + case PNV_XIVE_SYNC_IPI: + case PNV_XIVE_SYNC_HW: + case PNV_XIVE_SYNC_OS_ESC: + case PNV_XIVE_SYNC_HW_ESC: + case PNV_XIVE_SYNC_REDIS: + break; + + /* PC sync */ + case PNV_XIVE_SYNC_PULL: + case PNV_XIVE_SYNC_PUSH: + case PNV_XIVE_SYNC_VPC: + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/IC: invalid sync @%" + HWADDR_PRIx"\n", addr); + } +} + +static uint64_t pnv_xive_ic_notify_read(void *opaque, hwaddr addr, + unsigned size) +{ + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/IC: invalid notify read @%" + HWADDR_PRIx"\n", addr); + return -1; +} + +static const MemoryRegionOps pnv_xive_ic_notify_ops =3D { + .read =3D pnv_xive_ic_notify_read, + .write =3D pnv_xive_ic_notify_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + }, + .impl =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + }, +}; + +/* + * Interrupt controller MMIO region. The layout is compatible between + * 4K and 64K pages : + * + * Page 0 sub-engine BARs + * 0x000 - 0x3FF IC registers + * 0x400 - 0x7FF PC registers + * 0x800 - 0xFFF VC registers + * + * Page 1 Notify page + * 0x000 - 0x7FF HW interrupt triggers (PSI, PHB) + * 0x800 - 0xFFF forwards and syncs + * + * Page 2 LSI Trigger page (writes only) (not modeled) + * Page 3 LSI SB EOI page (reads only) (not modeled) + * + * Page 4-7 indirect TIMA (aliased to TIMA region) + */ +static void pnv_xive_ic_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/IC: invalid write @%" + HWADDR_PRIx"\n", addr); +} + +static uint64_t pnv_xive_ic_read(void *opaque, hwaddr addr, unsigned size) +{ + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/IC: invalid read @%" + HWADDR_PRIx"\n", addr); + return -1; +} + +static const MemoryRegionOps pnv_xive_ic_ops =3D { + .read =3D pnv_xive_ic_read, + .write =3D pnv_xive_ic_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + }, + .impl =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + }, +}; + +/* + * Interrupt controller XSCOM region. Load accesses are nearly all + * done all through the MMIO region. + */ +static uint64_t pnv_xive_xscom_read(void *opaque, hwaddr addr, unsigned si= ze) +{ + switch (addr >> 3) { + case X_VC_EQC_CONFIG: + /* + * This is the only XSCOM load done in skiboot. Bizarre. To be + * checked. + */ + return VC_EQC_SYNC_MASK; + default: + return pnv_xive_ic_reg_read(opaque, addr, false); + } +} + +static void pnv_xive_xscom_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + pnv_xive_ic_reg_write(opaque, addr, val, false); +} + +static const MemoryRegionOps pnv_xive_xscom_ops =3D { + .read =3D pnv_xive_xscom_read, + .write =3D pnv_xive_xscom_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + }, + .impl =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + } +}; + +/* + * Virtualization Controller MMIO region containing the IPI ESB pages + * and EQ ESB pages. The region is sub-divided into "sets" which map + * portions of the VC region to the different ESB pages. It is + * configured at runtime through the EDT set translation table to let + * the firmware decide how to split the address space between IPI ESB + * pages and EQ ESB pages. + */ +static uint64_t pnv_xive_vc_read(void *opaque, hwaddr offset, + unsigned size) +{ + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/VC: invalid read @%" + HWADDR_PRIx"\n", offset); + + /* if out of scope, specs says to return all ones */ + return -1; +} + +static void pnv_xive_vc_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/VC: invalid write @%" + HWADDR_PRIx" val=3D0x%"PRIx64"\n", offset, value); +} + +static const MemoryRegionOps pnv_xive_vc_ops =3D { + .read =3D pnv_xive_vc_read, + .write =3D pnv_xive_vc_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + }, + .impl =3D { + .min_access_size =3D 8, + .max_access_size =3D 8, + }, +}; + +/* + * Presenter Controller MMIO region. This is used by the Virtualization + * Controller to update the IPB in the VPD table when required. Not + * implemented yet. + */ +static uint64_t pnv_xive_pc_read(void *opaque, hwaddr addr, + unsigned size) +{ + qemu_log_mask(LOG_GUEST_ERROR, "XIVE/PC: invalid read @%"HWADDR_PRIx"\= n", + addr); + return -1; +} + +static void pnv_xive_pc_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + qemu_log_mask(LOG_UNIMP, "XIVE/PC: invalid write to VC @%"HWADDR_PRIx"= \n", + addr); +} + +static const MemoryRegionOps pnv_xive_pc_ops =3D { + .read =3D pnv_xive_pc_read, + .write =3D pnv_xive_pc_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 8, + }, + .impl =3D { + .min_access_size =3D 1, + .max_access_size =3D 8, + }, +}; + +void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon) +{ + int i; + XiveRouter *xrtr =3D XIVE_ROUTER(xive); + + monitor_printf(mon, "IVE Table\n"); + for (i =3D 0; i < xive->nr_irqs; i++) { + XiveIVE ive; + uint32_t lisn =3D BLKIDX_TO_GIRQ(xive->chip_id, i); + + xive_router_get_ive(xrtr, lisn, &ive); + xive_router_print_ive(xrtr, lisn, &ive, mon); + } + + xive_source_pic_print_info(&xive->source, + BLKIDX_TO_GIRQ(xive->chip_id, 0), mon); +} + +static void pnv_xive_reset(DeviceState *dev) +{ + PnvXive *xive =3D PNV_XIVE(dev); + PnvChip *chip =3D PNV_CHIP(object_property_get_link(OBJECT(dev), "chip= ", + &error_fatal)); + + /* + * Use the chip id to identify the XIVE interrupt controller. It + * can be overriden by configuration at runtime. + */ + xive->chip_id =3D xive->thread_chip_id =3D chip->chip_id; + + /* Default page size. Should be changed at runtime to 64k */ + xive->ic_shift =3D xive->vc_shift =3D xive->pc_shift =3D 12; + + /* + * PowerNV XIVE sources are realized at runtime when the set + * translation tables are configured. + */ + if (DEVICE(&xive->source)->realized) { + object_property_set_bool(OBJECT(&xive->source), false, "realized", + &error_fatal); + } + + if (DEVICE(&xive->eq_source)->realized) { + object_property_set_bool(OBJECT(&xive->eq_source), false, "realize= d", + &error_fatal); + } +} + +/* + * The VC sub-engine incorporates a source controller for the IPIs + * which forward event notification to the router. + */ +static void pnv_xive_notify(XiveFabric *xf, uint32_t srcno) +{ + PnvXive *xive =3D PNV_XIVE(xf); + + xive_router_notify(xf, BLKIDX_TO_GIRQ(xive->chip_id, srcno)); +} + +static void pnv_xive_init(Object *obj) +{ + PnvXive *xive =3D PNV_XIVE(obj); + + object_initialize(&xive->source, sizeof(xive->source), TYPE_XIVE_SOURC= E); + object_property_add_child(obj, "source", OBJECT(&xive->source), NULL); + + object_initialize(&xive->eq_source, sizeof(xive->eq_source), + TYPE_XIVE_EQ_SOURCE); + object_property_add_child(obj, "eq_source", OBJECT(&xive->eq_source), = NULL); +} + +static void pnv_xive_realize(DeviceState *dev, Error **errp) +{ + PnvXive *xive =3D PNV_XIVE(dev); + Object *obj; + Error *err =3D NULL; + PnvChip *chip; + + obj =3D object_property_get_link(OBJECT(dev), "chip", &err); + if (!obj) { + error_propagate(errp, err); + error_prepend(errp, "required link 'chip' not found: "); + return; + } + chip =3D PNV_CHIP(obj); + + /* Default page size. Should be changed at runtime to 64k */ + xive->ic_shift =3D xive->vc_shift =3D xive->pc_shift =3D 12; + + /* XSCOM region, used for initial configuration of the BARs */ + memory_region_init_io(&xive->xscom_regs, OBJECT(dev), &pnv_xive_xscom_= ops, + xive, "xscom-xive", PNV_XSCOM_XIVE_SIZE << 3); + + /* Interrupt controller MMIO region */ + memory_region_init_io(&xive->ic_mmio, OBJECT(dev), &pnv_xive_ic_ops, x= ive, + "xive.ic", PNV_XIVE_IC_SIZE(chip)); + memory_region_init_io(&xive->ic_reg_mmio, OBJECT(dev), &pnv_xive_ic_re= g_ops, + xive, "xive.ic.reg", 1 << xive->ic_shift); + memory_region_init_io(&xive->ic_notify_mmio, OBJECT(dev), + &pnv_xive_ic_notify_ops, + xive, "xive.ic.notify", 1 << xive->ic_shift); + + /* The Pervasive LSI trigger and EOI pages are not modeled */ + + /* + * Overall Virtualization Controller MMIO region containing the + * IPI ESB pages and EQ ESB pages. The layout is defined by the + * EDT set translation table. + */ + memory_region_init_io(&xive->vc_mmio, OBJECT(xive), &pnv_xive_vc_ops, = xive, + "xive.vc", PNV_XIVE_VC_SIZE(chip)); + + /* Presenter Controller MMIO region (not used for the moment) */ + memory_region_init_io(&xive->pc_mmio, OBJECT(xive), &pnv_xive_pc_ops, = xive, + "xive.pc", PNV_XIVE_PC_SIZE(chip)); + + /* Thread Interrupt Management Area, direct an indirect */ + memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &xive_tm_ops, + &xive->cpu_ind, "xive.tima", PNV_XIVE_TM_SIZE(ch= ip)); + memory_region_init_alias(&xive->tm_mmio_indirect, OBJECT(xive), + "xive.tima.indirect", + &xive->tm_mmio, 0, PNV_XIVE_TM_SIZE(chip)); +} + +static int pnv_xive_dt_xscom(PnvXScomInterface *dev, void *fdt, + int xscom_offset) +{ + const char compat[] =3D "ibm,power9-xive-x"; + char *name; + int offset; + uint32_t lpc_pcba =3D PNV_XSCOM_XIVE_BASE; + uint32_t reg[] =3D { + cpu_to_be32(lpc_pcba), + cpu_to_be32(PNV_XSCOM_XIVE_SIZE) + }; + + name =3D g_strdup_printf("xive@%x", lpc_pcba); + offset =3D fdt_add_subnode(fdt, xscom_offset, name); + _FDT(offset); + g_free(name); + + _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)))); + _FDT((fdt_setprop(fdt, offset, "compatible", compat, + sizeof(compat)))); + return 0; +} + +static Property pnv_xive_properties[] =3D { + DEFINE_PROP_UINT64("ic-bar", PnvXive, ic_base, 0), + DEFINE_PROP_UINT64("vc-bar", PnvXive, vc_base, 0), + DEFINE_PROP_UINT64("pc-bar", PnvXive, pc_base, 0), + DEFINE_PROP_UINT64("tm-bar", PnvXive, tm_base, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pnv_xive_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + PnvXScomInterfaceClass *xdc =3D PNV_XSCOM_INTERFACE_CLASS(klass); + XiveRouterClass *xrc =3D XIVE_ROUTER_CLASS(klass); + XiveFabricClass *xfc =3D XIVE_FABRIC_CLASS(klass); + + xdc->dt_xscom =3D pnv_xive_dt_xscom; + + dc->desc =3D "PowerNV XIVE Interrupt Controller"; + dc->realize =3D pnv_xive_realize; + dc->props =3D pnv_xive_properties; + dc->reset =3D pnv_xive_reset; + + xrc->get_ive =3D pnv_xive_get_ive; + xrc->set_ive =3D pnv_xive_set_ive; + xrc->get_eq =3D pnv_xive_get_eq; + xrc->set_eq =3D pnv_xive_set_eq; + xrc->get_vp =3D pnv_xive_get_vp; + xrc->set_vp =3D pnv_xive_set_vp; + + xfc->notify =3D pnv_xive_notify; +}; + +static const TypeInfo pnv_xive_info =3D { + .name =3D TYPE_PNV_XIVE, + .parent =3D TYPE_XIVE_ROUTER, + .instance_init =3D pnv_xive_init, + .instance_size =3D sizeof(PnvXive), + .class_init =3D pnv_xive_class_init, + .interfaces =3D (InterfaceInfo[]) { + { TYPE_PNV_XSCOM_INTERFACE }, + { } + } +}; + +static void pnv_xive_register_types(void) +{ + type_register_static(&pnv_xive_info); +} + +type_init(pnv_xive_register_types) + +void pnv_chip_xive_realize(PnvChip *chip, Error **errp) +{ + Object *obj; + Error *local_err =3D NULL; + + obj =3D object_new(TYPE_PNV_XIVE); + qdev_set_parent_bus(DEVICE(obj), sysbus_get_default()); + + object_property_add_child(OBJECT(chip), "xive", obj, &error_abort); + object_property_add_const_link(obj, "chip", OBJECT(chip), &error_abort= ); + object_property_set_int(obj, PNV_XIVE_IC_BASE(chip), "ic-bar", + &error_fatal); + object_property_set_int(obj, PNV_XIVE_VC_BASE(chip), "vc-bar", + &error_fatal); + object_property_set_int(obj, PNV_XIVE_PC_BASE(chip), "pc-bar", + &error_fatal); + object_property_set_int(obj, PNV_XIVE_TM_BASE(chip), "tm-bar", + &error_fatal); + object_property_set_bool(obj, true, "realized", &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + chip->xive =3D PNV_XIVE(obj); + + pnv_xscom_add_subregion(chip, PNV_XSCOM_XIVE_BASE, + &chip->xive->xscom_regs); +} diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 4d073c37bbda..66141028ef80 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -51,6 +51,8 @@ static uint8_t exception_mask(uint8_t ring) switch (ring) { case TM_QW1_OS: return TM_QW1_NSR_EO; + case TM_QW3_HV_PHYS: + return TM_QW3_NSR_HE; default: g_assert_not_reached(); } @@ -85,7 +87,17 @@ static void xive_tctx_notify(XiveTCTX *tctx, uint8_t rin= g) uint8_t *regs =3D &tctx->regs[ring]; =20 if (regs[TM_PIPR] < regs[TM_CPPR]) { - regs[TM_NSR] |=3D exception_mask(ring); + switch (ring) { + case TM_QW1_OS: + regs[TM_NSR] |=3D TM_QW1_NSR_EO; + break; + case TM_QW3_HV_PHYS: + regs[TM_NSR] |=3D SETFIELD(TM_QW3_NSR_HE, regs[TM_NSR], + TM_QW3_NSR_HE_PHYS); + break; + default: + g_assert_not_reached(); + } qemu_irq_raise(tctx->output); } } @@ -116,6 +128,38 @@ static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t= ring, uint8_t cppr) #define XIVE_TM_OS_PAGE 0x2 #define XIVE_TM_USER_PAGE 0x3 =20 +static void xive_tm_set_hv_cppr(XiveTCTX *tctx, hwaddr offset, + uint64_t value, unsigned size) +{ + xive_tctx_set_cppr(tctx, TM_QW3_HV_PHYS, value & 0xff); +} + +static uint64_t xive_tm_ack_hv_reg(XiveTCTX *tctx, hwaddr offset, unsigned= size) +{ + return xive_tctx_accept(tctx, TM_QW3_HV_PHYS); +} + +static uint64_t xive_tm_pull_pool_ctx(XiveTCTX *tctx, hwaddr offset, + unsigned size) +{ + uint64_t ret; + + ret =3D tctx->regs[TM_QW2_HV_POOL + TM_WORD2] & TM_QW2W2_POOL_CAM; + tctx->regs[TM_QW2_HV_POOL + TM_WORD2] &=3D ~TM_QW2W2_POOL_CAM; + return ret; +} + +static void xive_tm_vt_push(XiveTCTX *tctx, hwaddr offset, + uint64_t value, unsigned size) +{ + tctx->regs[TM_QW3_HV_PHYS + TM_WORD2] =3D value & 0xff; +} + +static uint64_t xive_tm_vt_poll(XiveTCTX *tctx, hwaddr offset, unsigned si= ze) +{ + return tctx->regs[TM_QW3_HV_PHYS + TM_WORD2] & 0xff; +} + /* * Define an access map for each page of the TIMA that we will use in * the memory region ops to filter values when doing loads and stores @@ -295,10 +339,16 @@ static const XiveTmOp xive_tm_operations[] =3D { * effects */ { XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr, NULL= }, + { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive_tm_set_hv_cppr, N= ULL }, + { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push, NULL= }, + { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL, xive_tm_vt_poll= }, =20 /* MMIOs above 2K : special operations with side effects */ { XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL, xive_tm_ack_os_reg = }, { XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, N= ULL }, + { XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL, xive_tm_ack_hv_reg = }, + { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL, xive_tm_pull_pool_c= tx }, + { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL, xive_tm_pull_pool_c= tx }, }; =20 static const XiveTmOp *xive_tm_find_op(hwaddr offset, unsigned size, bool = write) @@ -327,7 +377,8 @@ static const XiveTmOp *xive_tm_find_op(hwaddr offset, u= nsigned size, bool write) static void xive_tm_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - PowerPCCPU *cpu =3D POWERPC_CPU(current_cpu); + PowerPCCPU **cpuptr =3D opaque; + PowerPCCPU *cpu =3D *cpuptr ? *cpuptr : POWERPC_CPU(current_cpu); XiveTCTX *tctx =3D XIVE_TCTX(cpu->intc); const XiveTmOp *xto; =20 @@ -366,7 +417,8 @@ static void xive_tm_write(void *opaque, hwaddr offset, =20 static uint64_t xive_tm_read(void *opaque, hwaddr offset, unsigned size) { - PowerPCCPU *cpu =3D POWERPC_CPU(current_cpu); + PowerPCCPU **cpuptr =3D opaque; + PowerPCCPU *cpu =3D *cpuptr ? *cpuptr : POWERPC_CPU(current_cpu); XiveTCTX *tctx =3D XIVE_TCTX(cpu->intc); const XiveTmOp *xto; =20 @@ -508,6 +560,9 @@ static void xive_tctx_reset(void *dev) */ tctx->regs[TM_QW1_OS + TM_PIPR] =3D ipb_to_pipr(tctx->regs[TM_QW1_OS + TM_IPB]); + tctx->regs[TM_QW3_HV_PHYS + TM_PIPR] =3D + ipb_to_pipr(tctx->regs[TM_QW3_HV_PHYS + TM_IPB]); + =20 /* The OS CAM is pushed by the hypervisor when the VP is scheduled * to run on a HW thread. On QEMU, when running a pseries machine, @@ -1488,7 +1543,7 @@ static void xive_router_eq_notify(XiveRouter *xrtr, u= int8_t eq_blk, /* TODO: Auto EOI. */ } =20 -static void xive_router_notify(XiveFabric *xf, uint32_t lisn) +void xive_router_notify(XiveFabric *xf, uint32_t lisn) { XiveRouter *xrtr =3D XIVE_ROUTER(xf); XiveIVE ive; diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index e7bc4534e63d..447480558fdb 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -301,7 +301,10 @@ static void pnv_dt_chip(PnvChip *chip, void *fdt) pnv_dt_core(chip, pnv_core, fdt); =20 /* Interrupt Control Presenters (ICP). One per core. */ - pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_thread= s); + if (!pnv_chip_is_power9(chip)) { + pnv_dt_icp(chip, fdt, pnv_core->pir, + CPU_CORE(pnv_core)->nr_threads); + } } =20 if (chip->ram_size) { @@ -777,6 +780,10 @@ static void pnv_chip_power8nvl_class_init(ObjectClass = *klass, void *data) */ static const PnvPhysMapEntry pnv_chip_power9_phys_map[] =3D { [PNV_MAP_XSCOM] =3D { 0x000603fc00000000ull, 0x0000000400000000ull= }, + [PNV_MAP_XIVE_VC] =3D { 0x0006010000000000ull, 0x0000008000000000ull= }, + [PNV_MAP_XIVE_PC] =3D { 0x0006018000000000ull, 0x0000001000000000ull= }, + [PNV_MAP_XIVE_IC] =3D { 0x0006030203100000ull, 0x0000000000080000ull= }, + [PNV_MAP_XIVE_TM] =3D { 0x0006030203180000ull, 0x0000000000040000ull= }, }; =20 /* Each chip has a 4TB range for its MMIOs */ @@ -908,6 +915,15 @@ static void pnv_chip_realize(DeviceState *dev, Error *= *errp) } sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip)); =20 + /* XIVE Interrupt Controller on P9 (before the cores) */ + if (pnv_chip_is_power9(chip)) { + pnv_chip_xive_realize(chip, &error); + if (error) { + error_propagate(errp, error); + return; + } + } + /* Cores */ pnv_chip_core_sanitize(chip, &error); if (error) { @@ -940,6 +956,8 @@ static void pnv_chip_realize(DeviceState *dev, Error **= errp) "pir", &error_fatal); object_property_add_const_link(OBJECT(pnv_core), "xics", qdev_get_machine(), &error_fatal); + object_property_add_const_link(OBJECT(pnv_core), "chip", + OBJECT(chip), &error_fatal); object_property_set_bool(OBJECT(pnv_core), true, "realized", &error_fatal); object_unref(OBJECT(pnv_core)); @@ -963,10 +981,12 @@ static void pnv_chip_realize(DeviceState *dev, Error = **errp) =20 /* Interrupt Management Area. This is the memory region holding * all the Interrupt Control Presenter (ICP) registers */ - pnv_chip_icp_realize(chip, &error); - if (error) { - error_propagate(errp, error); - return; + if (!pnv_chip_is_power9(chip)) { + pnv_chip_icp_realize(chip, &error); + if (error) { + error_propagate(errp, error); + return; + } } =20 /* Processor Service Interface (PSI) Host Bridge */ @@ -1047,11 +1067,19 @@ static void pnv_pic_print_info(InterruptStatsProvid= er *obj, CPU_FOREACH(cs) { PowerPCCPU *cpu =3D POWERPC_CPU(cs); =20 - icp_pic_print_info(ICP(cpu->intc), mon); + if (!pnv_is_power9(pnv)) { + icp_pic_print_info(ICP(cpu->intc), mon); + } else { + xive_tctx_pic_print_info(XIVE_TCTX(cpu->intc), mon); + } } =20 for (i =3D 0; i < pnv->num_chips; i++) { - ics_pic_print_info(&pnv->chips[i]->psi.ics, mon); + if (!pnv_is_power9(pnv)) { + ics_pic_print_info(&pnv->chips[i]->psi.ics, mon); + } else { + pnv_xive_pic_print_info(pnv->chips[i]->xive, mon); + } } } =20 diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index cbb64ad9e7e0..3a8d55342308 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -121,11 +121,13 @@ static const MemoryRegionOps pnv_core_xscom_ops =3D { .endianness =3D DEVICE_BIG_ENDIAN, }; =20 -static void pnv_core_realize_child(Object *child, XICSFabric *xi, Error **= errp) +static void pnv_core_realize_child(Object *child, XICSFabric *xi, PnvChip = *chip, + Error **errp) { Error *local_err =3D NULL; CPUState *cs =3D CPU(child); PowerPCCPU *cpu =3D POWERPC_CPU(cs); + PnvMachineState *pnv =3D PNV_MACHINE(xi); =20 object_property_set_bool(child, true, "realized", &local_err); if (local_err) { @@ -133,13 +135,18 @@ static void pnv_core_realize_child(Object *child, XIC= SFabric *xi, Error **errp) return; } =20 - cpu->intc =3D icp_create(child, TYPE_PNV_ICP, xi, &local_err); + pnv_cpu_init(cpu, &local_err); if (local_err) { error_propagate(errp, local_err); return; } =20 - pnv_cpu_init(cpu, &local_err); + if (!pnv_is_power9(pnv)) { + cpu->intc =3D icp_create(child, TYPE_PNV_ICP, xi, &local_err); + } else { + cpu->intc =3D xive_tctx_create(child, TYPE_XIVE_TCTX, + XIVE_ROUTER(chip->xive), &local_err); + } if (local_err) { error_propagate(errp, local_err); return; @@ -157,11 +164,19 @@ static void pnv_core_realize(DeviceState *dev, Error = **errp) int i, j; char name[32]; Object *xi; + Object *chip; =20 xi =3D object_property_get_link(OBJECT(dev), "xics", &local_err); if (!xi) { - error_setg(errp, "%s: required link 'xics' not found: %s", - __func__, error_get_pretty(local_err)); + error_propagate(errp, local_err); + error_prepend(errp, "required link 'xics' not found: "); + return; + } + + chip =3D object_property_get_link(OBJECT(dev), "chip", &local_err); + if (!chip) { + error_propagate(errp, local_err); + error_prepend(errp, "required link 'chip' not found: "); return; } =20 @@ -184,7 +199,8 @@ static void pnv_core_realize(DeviceState *dev, Error **= errp) for (j =3D 0; j < cc->nr_threads; j++) { obj =3D pc->threads + j * size; =20 - pnv_core_realize_child(obj, XICS_FABRIC(xi), &local_err); + pnv_core_realize_child(obj, XICS_FABRIC(xi), PNV_CHIP(chip), + &local_err); if (local_err) { goto err; } diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index dd4d69db2bdd..145bfaf44014 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -40,7 +40,7 @@ obj-$(CONFIG_XICS_KVM) +=3D xics_kvm.o obj-$(CONFIG_XIVE) +=3D xive.o obj-$(CONFIG_XIVE_SPAPR) +=3D spapr_xive.o spapr_xive_hcall.o obj-$(CONFIG_XIVE_KVM) +=3D spapr_xive_kvm.o -obj-$(CONFIG_POWERNV) +=3D xics_pnv.o +obj-$(CONFIG_POWERNV) +=3D xics_pnv.o pnv_xive.o obj-$(CONFIG_ALLWINNER_A10_PIC) +=3D allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) +=3D s390_flic.o obj-$(CONFIG_S390_FLIC_KVM) +=3D s390_flic_kvm.o --=20 2.13.6