From patchwork Wed Mar 6 08:50:23 2019 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: 10840697 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 17ACE1669 for ; Wed, 6 Mar 2019 09:19:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id ED81E2D221 for ; Wed, 6 Mar 2019 09:19:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DF14A2D462; Wed, 6 Mar 2019 09:19:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id ED0E52D221 for ; Wed, 6 Mar 2019 09:19:26 +0000 (UTC) Received: from localhost ([127.0.0.1]:56926 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h1Sdu-0008DI-Bm for patchwork-qemu-devel@patchwork.kernel.org; Wed, 06 Mar 2019 04:15:14 -0500 Received: from eggs.gnu.org ([209.51.188.92]:55477) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h1SH5-0006dP-Dk for qemu-devel@nongnu.org; Wed, 06 Mar 2019 03:51:41 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1h1SH2-00022N-RU for qemu-devel@nongnu.org; Wed, 06 Mar 2019 03:51:39 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:52334) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1h1SGy-0001OK-PU for qemu-devel@nongnu.org; Wed, 06 Mar 2019 03:51:34 -0500 Received: from pps.filterd (m0098393.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x268mVmp040784 for ; Wed, 6 Mar 2019 03:50:59 -0500 Received: from e06smtp05.uk.ibm.com (e06smtp05.uk.ibm.com [195.75.94.101]) by mx0a-001b2d01.pphosted.com with ESMTP id 2r29ye3pds-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Wed, 06 Mar 2019 03:50:58 -0500 Received: from localhost by e06smtp05.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 6 Mar 2019 08:50:55 -0000 Received: from b06cxnps4075.portsmouth.uk.ibm.com (9.149.109.197) by e06smtp05.uk.ibm.com (192.168.101.135) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Wed, 6 Mar 2019 08:50:52 -0000 Received: from b06wcsmtp001.portsmouth.uk.ibm.com (b06wcsmtp001.portsmouth.uk.ibm.com [9.149.105.160]) by b06cxnps4075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x268opCH32768194 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 6 Mar 2019 08:50:51 GMT Received: from b06wcsmtp001.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CE7F3A405B; Wed, 6 Mar 2019 08:50:51 +0000 (GMT) Received: from b06wcsmtp001.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B203BA4054; Wed, 6 Mar 2019 08:50:51 +0000 (GMT) Received: from smtp.lab.toulouse-stg.fr.ibm.com (unknown [9.101.4.1]) by b06wcsmtp001.portsmouth.uk.ibm.com (Postfix) with ESMTP; Wed, 6 Mar 2019 08:50:51 +0000 (GMT) Received: from zorba.kaod.org.com (sig-9-145-0-135.uk.ibm.com [9.145.0.135]) by smtp.lab.toulouse-stg.fr.ibm.com (Postfix) with ESMTP id 35F57220158; Wed, 6 Mar 2019 09:50:51 +0100 (CET) From: =?utf-8?q?C=C3=A9dric_Le_Goater?= To: David Gibson Date: Wed, 6 Mar 2019 09:50:23 +0100 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190306085032.15744-1-clg@kaod.org> References: <20190306085032.15744-1-clg@kaod.org> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19030608-0020-0000-0000-0000031F224A X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19030608-0021-0000-0000-000021712F7C Message-Id: <20190306085032.15744-19-clg@kaod.org> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-03-06_06:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=8 phishscore=0 bulkscore=0 spamscore=0 clxscore=1034 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1903060061 X-MIME-Autoconverted: from 8bit to quoted-printable by mx0a-001b2d01.pphosted.com id x268mVmp040784 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] X-Received-From: 148.163.156.1 Subject: [Qemu-devel] [PATCH 18/27] ppc/pnv: add a LPC Controller model for POWER9 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: qemu-ppc@nongnu.org, qemu-devel@nongnu.org, =?utf-8?q?C=C3=A9dric_Le_Goa?= =?utf-8?q?ter?= Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP The LPC Controller on POWER9 is very similar to the one found on POWER8 but accesses are now done via on MMIOs, without the XSCOM and ECCB logic. The device tree is populated differently so we add a specific POWER9 routine for the purpose. SerIRQ routing is yet to be done. Signed-off-by: Cédric Le Goater --- include/hw/ppc/pnv.h | 4 + include/hw/ppc/pnv_lpc.h | 10 ++ hw/ppc/pnv.c | 29 +++++- hw/ppc/pnv_lpc.c | 200 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 240 insertions(+), 3 deletions(-) diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index 57d0337219be..2d68aabc212f 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -85,6 +85,7 @@ typedef struct Pnv9Chip { /*< public >*/ PnvXive xive; PnvPsi psi; + PnvLpcController lpc; } Pnv9Chip; typedef struct PnvChipClass { @@ -232,6 +233,9 @@ void pnv_bmc_powerdown(IPMIBmc *bmc); #define PNV9_XIVE_PC_SIZE 0x0000001000000000ull #define PNV9_XIVE_PC_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006018000000000ull) +#define PNV9_LPCM_SIZE 0x0000000100000000ull +#define PNV9_LPCM_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030000000000ull) + #define PNV9_PSIHB_SIZE 0x0000000000100000ull #define PNV9_PSIHB_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030203000000ull) diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h index 242baecdcb93..24fe23f0f63b 100644 --- a/include/hw/ppc/pnv_lpc.h +++ b/include/hw/ppc/pnv_lpc.h @@ -28,6 +28,10 @@ #define PNV8_LPC(obj) \ OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV8_LPC) +#define TYPE_PNV9_LPC TYPE_PNV_LPC "-POWER9" +#define PNV9_LPC(obj) \ + OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV9_LPC) + typedef struct PnvLpcController { DeviceState parent; @@ -86,6 +90,12 @@ typedef struct PnvLpcClass { DeviceRealize parent_realize; } PnvLpcClass; +/* + * Old compilers error on typdef forward declarations. Keep them happy. + */ +struct PnvChip; + ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp); +int pnv_dt_lpc(struct PnvChip *chip, void *fdt, int root_offset); #endif /* _PPC_PNV_LPC_H */ diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 7176e1b68d0e..895be470af67 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -306,6 +306,8 @@ static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt) if (chip->ram_size) { pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size); } + + pnv_dt_lpc(chip, fdt, 0); } static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off) @@ -422,8 +424,14 @@ static int pnv_chip_isa_offset(PnvChip *chip, void *fdt) char *name; int offset; - name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x", - (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE); + if (pnv_chip_is_power9(chip)) { + name = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0", + (uint64_t) PNV9_LPCM_BASE(chip)); + } else { + name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x", + (uint64_t) PNV_XSCOM_BASE(chip), + PNV_XSCOM_LPC_BASE); + } offset = fdt_path_offset(fdt, name); g_free(name); return offset; @@ -559,7 +567,8 @@ static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp) static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp) { - return NULL; + Pnv9Chip *chip9 = PNV9_CHIP(chip); + return pnv_lpc_isa_create(&chip9->lpc, false, errp); } static ISABus *pnv_isa_create(PnvChip *chip, Error **errp) @@ -954,6 +963,11 @@ static void pnv_chip_power9_instance_init(Object *obj) TYPE_PNV9_PSI, &error_abort, NULL); object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj, &error_abort); + + object_initialize_child(obj, "lpc", &chip9->lpc, sizeof(chip9->lpc), + TYPE_PNV9_LPC, &error_abort, NULL); + object_property_add_const_link(OBJECT(&chip9->lpc), "psi", + OBJECT(&chip9->psi), &error_abort); } static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) @@ -997,6 +1011,15 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) } pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE, &chip9->psi.xscom_regs); + + /* LPC */ + object_property_set_bool(OBJECT(&chip9->lpc), true, "realized", &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip), + &chip9->lpc.xscom_regs); } static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c index 3c509a30a0af..6df694e0abc1 100644 --- a/hw/ppc/pnv_lpc.c +++ b/hw/ppc/pnv_lpc.c @@ -118,6 +118,100 @@ static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset) return 0; } +/* POWER9 only */ +int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset) +{ + const char compat[] = "ibm,power9-lpcm-opb\0simple-bus"; + const char lpc_compat[] = "ibm,power9-lpc\0ibm,lpc"; + char *name; + int offset, lpcm_offset; + uint64_t lpcm_addr = PNV9_LPCM_BASE(chip); + uint32_t opb_ranges[8] = { 0, + cpu_to_be32(lpcm_addr >> 32), + cpu_to_be32((uint32_t)lpcm_addr), + cpu_to_be32(PNV9_LPCM_SIZE / 2), + cpu_to_be32(PNV9_LPCM_SIZE / 2), + cpu_to_be32(lpcm_addr >> 32), + cpu_to_be32(PNV9_LPCM_SIZE / 2), + cpu_to_be32(PNV9_LPCM_SIZE / 2), + }; + uint32_t opb_reg[4] = { cpu_to_be32(lpcm_addr >> 32), + cpu_to_be32((uint32_t)lpcm_addr), + cpu_to_be32(PNV9_LPCM_SIZE >> 32), + cpu_to_be32((uint32_t)PNV9_LPCM_SIZE), + }; + uint32_t reg[2]; + + /* + * OPB bus + */ + name = g_strdup_printf("lpcm-opb@%"PRIx64, lpcm_addr); + lpcm_offset = fdt_add_subnode(fdt, root_offset, name); + _FDT(lpcm_offset); + g_free(name); + + _FDT((fdt_setprop(fdt, lpcm_offset, "reg", opb_reg, sizeof(opb_reg)))); + _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#address-cells", 1))); + _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#size-cells", 1))); + _FDT((fdt_setprop(fdt, lpcm_offset, "compatible", compat, sizeof(compat)))); + _FDT((fdt_setprop_cell(fdt, lpcm_offset, "ibm,chip-id", chip->chip_id))); + _FDT((fdt_setprop(fdt, lpcm_offset, "ranges", opb_ranges, + sizeof(opb_ranges)))); + + /* + * OPB Master registers + */ + name = g_strdup_printf("opb-master@%x", LPC_OPB_REGS_OPB_ADDR); + offset = fdt_add_subnode(fdt, lpcm_offset, name); + _FDT(offset); + g_free(name); + + reg[0] = cpu_to_be32(LPC_OPB_REGS_OPB_ADDR); + reg[1] = cpu_to_be32(LPC_OPB_REGS_OPB_SIZE); + _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)))); + _FDT((fdt_setprop_string(fdt, offset, "compatible", + "ibm,power9-lpcm-opb-master"))); + + /* + * OPB arbitrer registers + */ + name = g_strdup_printf("opb-arbitrer@%x", LPC_OPB_REGS_OPBA_ADDR); + offset = fdt_add_subnode(fdt, lpcm_offset, name); + _FDT(offset); + g_free(name); + + reg[0] = cpu_to_be32(LPC_OPB_REGS_OPBA_ADDR); + reg[1] = cpu_to_be32(LPC_OPB_REGS_OPBA_SIZE); + _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)))); + _FDT((fdt_setprop_string(fdt, offset, "compatible", + "ibm,power9-lpcm-opb-arbiter"))); + + /* + * LPC Host Controller registers + */ + name = g_strdup_printf("lpc-controller@%x", LPC_HC_REGS_OPB_ADDR); + offset = fdt_add_subnode(fdt, lpcm_offset, name); + _FDT(offset); + g_free(name); + + reg[0] = cpu_to_be32(LPC_HC_REGS_OPB_ADDR); + reg[1] = cpu_to_be32(LPC_HC_REGS_OPB_SIZE); + _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)))); + _FDT((fdt_setprop_string(fdt, offset, "compatible", + "ibm,power9-lpc-controller"))); + + name = g_strdup_printf("lpc@0"); + offset = fdt_add_subnode(fdt, lpcm_offset, name); + _FDT(offset); + g_free(name); + _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2))); + _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1))); + _FDT((fdt_setprop(fdt, offset, "compatible", lpc_compat, + sizeof(lpc_compat)))); + + return 0; +} + /* * These read/write handlers of the OPB address space should be common * with the P9 LPC Controller which uses direct MMIOs. @@ -242,6 +336,74 @@ static const MemoryRegionOps pnv_lpc_xscom_ops = { .endianness = DEVICE_BIG_ENDIAN, }; +static uint64_t pnv_lpc_mmio_read(void *opaque, hwaddr addr, unsigned size) +{ + PnvLpcController *lpc = PNV_LPC(opaque); + uint64_t val = 0; + uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK; + MemTxResult result; + + switch (size) { + case 4: + val = address_space_ldl(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED, + &result); + break; + case 1: + val = address_space_ldub(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED, + &result); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%" + HWADDR_PRIx " invalid size %d\n", addr, size); + return 0; + } + + if (result != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%" + HWADDR_PRIx "\n", addr); + } + + return val; +} + +static void pnv_lpc_mmio_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + PnvLpcController *lpc = PNV_LPC(opaque); + uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK; + MemTxResult result; + + switch (size) { + case 4: + address_space_stl(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED, + &result); + break; + case 1: + address_space_stb(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED, + &result); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%" + HWADDR_PRIx " invalid size %d\n", addr, size); + return; + } + + if (result != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%" + HWADDR_PRIx "\n", addr); + } +} + +static const MemoryRegionOps pnv_lpc_mmio_ops = { + .read = pnv_lpc_mmio_read, + .write = pnv_lpc_mmio_write, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, + .endianness = DEVICE_BIG_ENDIAN, +}; + static void pnv_lpc_eval_irqs(PnvLpcController *lpc) { bool lpc_to_opb_irq = false; @@ -465,6 +627,43 @@ static const TypeInfo pnv_lpc_power8_info = { } }; +static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp) +{ + PnvLpcController *lpc = PNV_LPC(dev); + PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev); + Error *local_err = NULL; + + plc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + /* P9 uses a MMIO region */ + memory_region_init_io(&lpc->xscom_regs, OBJECT(lpc), &pnv_lpc_mmio_ops, + lpc, "lpcm", PNV9_LPCM_SIZE); +} + +static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PnvLpcClass *plc = PNV_LPC_CLASS(klass); + + dc->desc = "PowerNV LPC Controller POWER9"; + + plc->psi_irq = PSIHB9_IRQ_LPCHC; + + device_class_set_parent_realize(dc, pnv_lpc_power9_realize, + &plc->parent_realize); +} + +static const TypeInfo pnv_lpc_power9_info = { + .name = TYPE_PNV9_LPC, + .parent = TYPE_PNV_LPC, + .instance_size = sizeof(PnvLpcController), + .class_init = pnv_lpc_power9_class_init, +}; + static void pnv_lpc_realize(DeviceState *dev, Error **errp) { PnvLpcController *lpc = PNV_LPC(dev); @@ -540,6 +739,7 @@ static void pnv_lpc_register_types(void) { type_register_static(&pnv_lpc_info); type_register_static(&pnv_lpc_power8_info); + type_register_static(&pnv_lpc_power9_info); } type_init(pnv_lpc_register_types)