From patchwork Wed Jul 5 17:13:27 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?C=C3=A9dric_Le_Goater?= X-Patchwork-Id: 784782 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3x2npb2qSbz9s7B for ; Thu, 6 Jul 2017 03:26:15 +1000 (AEST) Received: from localhost ([::1]:47331 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dSo45-0005So-3J for incoming@patchwork.ozlabs.org; Wed, 05 Jul 2017 13:26:13 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41672) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dSnth-0004K2-9f for qemu-devel@nongnu.org; Wed, 05 Jul 2017 13:15:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dSntd-0003LK-56 for qemu-devel@nongnu.org; Wed, 05 Jul 2017 13:15:29 -0400 Received: from 6.mo3.mail-out.ovh.net ([188.165.43.173]:38992) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dSntc-0003KT-Rv for qemu-devel@nongnu.org; Wed, 05 Jul 2017 13:15:25 -0400 Received: from player158.ha.ovh.net (b6.ovh.net [213.186.33.56]) by mo3.mail-out.ovh.net (Postfix) with ESMTP id 93C0BFCADA for ; Wed, 5 Jul 2017 19:15:23 +0200 (CEST) Received: from zorba.kaod.org.com (LFbn-1-10652-153.w90-89.abo.wanadoo.fr [90.89.238.153]) (Authenticated sender: clg@kaod.org) by player158.ha.ovh.net (Postfix) with ESMTPSA id 6B28662007E; Wed, 5 Jul 2017 19:15:17 +0200 (CEST) From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: David Gibson Date: Wed, 5 Jul 2017 19:13:27 +0200 Message-Id: <1499274819-15607-15-git-send-email-clg@kaod.org> X-Mailer: git-send-email 2.7.5 In-Reply-To: <1499274819-15607-1-git-send-email-clg@kaod.org> References: <1499274819-15607-1-git-send-email-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 2209860044219976678 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrfeelkedrudeigdduuddtucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuqfggjfdpvefjgfevmfevgfenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddm X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 188.165.43.173 Subject: [Qemu-devel] [RFC PATCH 14/26] ppc/xive: add MMIO handlers to the XIVE interrupt presenter 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: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , qemu-ppc@nongnu.org, Alexander Graf , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" The Thread Interrupt Management Area for the OS is mostly used to acknowledge interrupts and set the CPPR of the CPU. The TIMA is mapped at the same address for each CPU. 'current_cpu' is used to retrieve the targeted interrupt presenter object. Signed-off-by: Cédric Le Goater --- hw/intc/xive-internal.h | 4 ++ hw/intc/xive.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) diff --git a/hw/intc/xive-internal.h b/hw/intc/xive-internal.h index ba5e648a5258..5e8b78a1ea6a 100644 --- a/hw/intc/xive-internal.h +++ b/hw/intc/xive-internal.h @@ -200,6 +200,10 @@ struct XIVE { /* ESB and TIMA memory location */ hwaddr vc_base; MemoryRegion esb_iomem; + + uint32_t tm_shift; + hwaddr tm_base; + MemoryRegion tm_iomem; }; void xive_reset(void *dev); diff --git a/hw/intc/xive.c b/hw/intc/xive.c index c08a4f8efb58..82b2f0dcda0b 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -26,6 +26,180 @@ #include "xive-internal.h" +static uint8_t priority_to_ipb(uint8_t priority) +{ + return priority < XIVE_EQ_PRIORITY_COUNT ? 1 << (7 - priority) : 0; +} + +static uint64_t xive_icp_accept(XiveICPState *xicp) +{ + ICPState *icp = ICP(xicp); + uint8_t nsr = xicp->tima_os[TM_NSR]; + + qemu_irq_lower(icp->output); + + if (xicp->tima_os[TM_NSR] & TM_QW1_NSR_EO) { + uint8_t cppr = xicp->tima_os[TM_PIPR]; + + xicp->tima_os[TM_CPPR] = cppr; + + /* Reset the pending buffer bit */ + xicp->tima_os[TM_IPB] &= ~priority_to_ipb(cppr); + + /* Drop Exception bit for OS */ + xicp->tima_os[TM_NSR] &= ~TM_QW1_NSR_EO; + } + + return (nsr << 8) | xicp->tima_os[TM_CPPR]; +} + +static void xive_icp_set_cppr(XiveICPState *xicp, uint8_t cppr) +{ + if (cppr > XIVE_PRIORITY_MAX) { + cppr = 0xff; + } + + xicp->tima_os[TM_CPPR] = cppr; +} + +/* + * Thread Interrupt Management Area MMIO + */ +static uint64_t xive_tm_read_special(XiveICPState *icp, hwaddr offset, + unsigned size) +{ + uint64_t ret = -1; + + if (offset == TM_SPC_ACK_OS_REG && size == 2) { + ret = xive_icp_accept(icp); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid TIMA read @%" + HWADDR_PRIx" size %d\n", offset, size); + } + + return ret; +} + +static uint64_t xive_tm_read(void *opaque, hwaddr offset, unsigned size) +{ + PowerPCCPU *cpu = POWERPC_CPU(current_cpu); + XiveICPState *icp = XIVE_ICP(cpu->intc); + uint64_t ret = -1; + int i; + + if (offset >= TM_SPC_ACK_EBB) { + return xive_tm_read_special(icp, offset, size); + } + + if (offset & TM_QW1_OS) { + switch (size) { + case 1: + case 2: + case 4: + case 8: + if (QEMU_IS_ALIGNED(offset, size)) { + ret = 0; + for (i = 0; i < size; i++) { + ret |= icp->tima[offset + i] << (8 * i); + } + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "XIVE: invalid TIMA read alignment @%" + HWADDR_PRIx" size %d\n", offset, size); + } + break; + default: + g_assert_not_reached(); + } + } else { + qemu_log_mask(LOG_UNIMP, "XIVE: does handle non-OS TIMA ring @%" + HWADDR_PRIx"\n", offset); + } + + return ret; +} + +static bool xive_tm_is_readonly(uint8_t index) +{ + /* Let's be optimistic and prepare ground for HV mode support */ + switch (index) { + case TM_QW1_OS + TM_CPPR: + return false; + default: + return true; + } +} + +static void xive_tm_write_special(XiveICPState *xicp, hwaddr offset, + uint64_t value, unsigned size) +{ + if (offset == TM_SPC_SET_OS_PENDING && size == 1) { + xicp->tima_os[TM_IPB] |= priority_to_ipb(value & 0xff); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid TIMA write @%" + HWADDR_PRIx" size %d\n", offset, size); + } + + /* TODO: support TM_SPC_ACK_OS_EL */ +} + +static void xive_tm_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + PowerPCCPU *cpu = POWERPC_CPU(current_cpu); + XiveICPState *icp = XIVE_ICP(cpu->intc); + int i; + + if (offset >= TM_SPC_ACK_EBB) { + xive_tm_write_special(icp, offset, value, size); + return; + } + + if (offset & TM_QW1_OS) { + switch (size) { + case 1: + if (offset == TM_QW1_OS + TM_CPPR) { + xive_icp_set_cppr(icp, value & 0xff); + } + break; + case 4: + case 8: + if (QEMU_IS_ALIGNED(offset, size)) { + for (i = 0; i < size; i++) { + if (!xive_tm_is_readonly(offset + i)) { + icp->tima[offset + i] = (value >> (8 * i)) & 0xff; + } + } + } else { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid TIMA write @%" + HWADDR_PRIx" size %d\n", offset, size); + } + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid TIMA write @%" + HWADDR_PRIx" size %d\n", offset, size); + } + } else { + qemu_log_mask(LOG_UNIMP, "XIVE: does handle non-OS TIMA ring @%" + HWADDR_PRIx"\n", offset); + } +} + + +static const MemoryRegionOps xive_tm_ops = { + .read = xive_tm_read, + .write = xive_tm_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + static void xive_icp_reset(ICPState *icp) { XiveICPState *xicp = XIVE_ICP(icp); @@ -453,6 +627,11 @@ static const TypeInfo xive_ics_info = { #define P9_MMIO_BASE 0x006000000000000ull #define P9_CHIP_BASE(id) (P9_MMIO_BASE | (0x40000000000ull * (uint64_t) (id))) +/* Thread Interrupt Management Area MMIO */ +#define TM_BAR_DEFAULT 0x30203180000ull +#define TM_SHIFT 16 +#define TM_BAR_SIZE (XIVE_TM_RING_COUNT * (1 << TM_SHIFT)) + static uint64_t xive_esb_default_read(void *p, hwaddr offset, unsigned size) { qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n", @@ -541,6 +720,14 @@ static void xive_realize(DeviceState *dev, Error **errp) NULL, "xive.esb", VC_BAR_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &x->esb_iomem); + /* TM BAR. Same address for each chip */ + x->tm_base = (P9_MMIO_BASE | TM_BAR_DEFAULT); + x->tm_shift = TM_SHIFT; + + memory_region_init_io(&x->tm_iomem, OBJECT(x), &xive_tm_ops, x, + "xive.tm", TM_BAR_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &x->tm_iomem); + qemu_register_reset(xive_reset, dev); }