From nobody Fri Mar 14 13:05:52 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1738707531; cv=none; d=zohomail.com; s=zohoarc; b=CsHo449UVYqV4z0Onsr8vkZtnrt+OEo9eAxhh9fRmwL16s4IVDwWweboHwK9vnYqrEq3kVN8XoTvmsauCTX3TsNFrEF7XCywSdos5dYbKOUFX1XuvJQ3m8EnE7DiDNbLkz2Fm8lfy2kjivRDX6u67IOctPFwl419FmrzaIVWlo8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1738707531; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=FSrGXfm7OSUR5WFmKVUgNFqE4TBRxBpqXjWUNRDc+Dg=; b=bqcycMnawPqkN+v7M3c7fxP5yuiPkKyrtjjSB0WjUPBYFvMDvynDRbgyvYdhcobs1vAP6Kpgh6UIG2A+XXk2oKQuTRbtEPZ3tk45MbM4XlHAq/SLJ8dhyPlqNYmsMSI6Si9by4JWCBPGN40aoEqNs94zlRdddZuOKhej9VeKtko= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1738707531743226.30606165897336; Tue, 4 Feb 2025 14:18:51 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tfREg-0005UM-Ap; Tue, 04 Feb 2025 17:17:38 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tfREe-0005Tc-Cn for qemu-devel@nongnu.org; Tue, 04 Feb 2025 17:17:36 -0500 Received: from dfw.source.kernel.org ([139.178.84.217]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tfREb-0005QI-PO for qemu-devel@nongnu.org; Tue, 04 Feb 2025 17:17:36 -0500 Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by dfw.source.kernel.org (Postfix) with ESMTP id 051885C571B; Tue, 4 Feb 2025 22:16:51 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id A1296C4CEDF; Tue, 4 Feb 2025 22:17:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1738707450; bh=XqqcKTiqr37pWU6TZ9vOOlIFt2Td5Ilt6/cULAw4RFo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KS1ewTvHHQH8hnUtDTtUSswPQjjLcqtQyqxjLIN5PrAHV+kFMTua9sSFLhdx1Iph8 P5x4BQirjPXrZgy275BeTP0ka5iYDXsH2Ek/EsCiLBJutAXKs7wKfdI64EooiiW5Sz KiXrMlYvlPdKNAKfzt5CLBLyj6aCdC8TRVJ1RZymbX5XMlYrzPCr9cK7hjkOr9tXEp +4d4LbofEdti+DFo8t7wE3Ar3cBzc+9Nf62zmXBHrYeYPwTncde/NBM+OE9iJVObFZ QlaYxNm5PkggnJ2ucTezvHoiVibeWhOopYCDwqvVOdIPzQzGpsXgUkKWowm3iIOSK7 g5k7IlOAt/VPw== From: deller@kernel.org To: Richard Henderson , qemu-devel@nongnu.org Cc: Helge Deller Subject: [PATCH 1/6] hw/char: Add emulation of Diva GSP PCI management boards Date: Tue, 4 Feb 2025 23:17:21 +0100 Message-ID: <20250204221726.151287-2-deller@kernel.org> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20250204221726.151287-1-deller@kernel.org> References: <20250204221726.151287-1-deller@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=139.178.84.217; envelope-from=deller@kernel.org; helo=dfw.source.kernel.org X-Spam_score_int: -70 X-Spam_score: -7.1 X-Spam_bar: ------- X-Spam_report: (-7.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_HI=-5, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @kernel.org) X-ZM-MESSAGEID: 1738707533770019000 Content-Type: text/plain; charset="utf-8" From: Helge Deller The Diva GSP ("Guardian Service Processor") PCI boards are Remote Management cards for PA-RISC machines. They come with built-in 16550A UARTs for serial consoles and modem functionalities, as well as a mailbox-like memory area for hardware auto-reboot functionality. Latest generation HP PA-RISC server machines use those Diva cards for console output. Signed-off-by: Helge Deller --- MAINTAINERS | 1 + hw/char/Kconfig | 3 + hw/char/diva-gsp.c | 297 ++++++++++++++++++++++++++++++++++++++++++++ hw/char/meson.build | 1 + 4 files changed, 302 insertions(+) create mode 100644 hw/char/diva-gsp.c diff --git a/MAINTAINERS b/MAINTAINERS index bf737eb6db..e09a8d2791 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1193,6 +1193,7 @@ M: Richard Henderson M: Helge Deller S: Maintained F: configs/devices/hppa-softmmu/default.mak +F: hw/char/diva-gsp.c F: hw/display/artist.c F: hw/hppa/ F: hw/input/lasips2.c diff --git a/hw/char/Kconfig b/hw/char/Kconfig index 1dc20ee4c2..3f702565e6 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig @@ -66,6 +66,9 @@ config RENESAS_SCI config AVR_USART bool =20 +config DIVA_GSP + bool + config MCHP_PFSOC_MMUART bool select SERIAL diff --git a/hw/char/diva-gsp.c b/hw/char/diva-gsp.c new file mode 100644 index 0000000000..ecec1f7bb1 --- /dev/null +++ b/hw/char/diva-gsp.c @@ -0,0 +1,297 @@ +/* + * HP Diva GSP controller + * + * The Diva PCI boards are Remote Management cards for PA-RISC machines. + * They come with built-in 16550A multi UARTs for serial consoles + * and a mailbox-like memory area for hardware auto-reboot functionality. + * GSP stands for "Guardian Service Processor". Later products were market= ed + * "Management Processor" (MP). + * + * Diva cards are multifunctional cards. The first part, the aux port, + * is on physical machines not useable but we still try to mimic it here. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright (c) 2025 Helge Deller + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "hw/char/serial.h" +#include "hw/irq.h" +#include "hw/pci/pci_device.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "migration/vmstate.h" + +#define PCI_DEVICE_ID_HP_DIVA 0x1048 +/* various DIVA GSP cards: */ +#define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049 +#define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A +#define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B +#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1 +#define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223 +#define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226 +#define PCI_DEVICE_ID_HP_DIVA_POWERBAR 0x1227 +#define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282 +#define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290 +#define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301 +#define PCI_DEVICE_ID_HP_DIVA_HURRICANE 0x132a + + +#define PCI_SERIAL_MAX_PORTS 4 + +typedef struct PCIDivaSerialState { + PCIDevice dev; + MemoryRegion membar; /* for serial ports */ + MemoryRegion mailboxbar; /* for hardware mailbox */ + uint32_t subvendor; + uint32_t ports; + char *name[PCI_SERIAL_MAX_PORTS]; + SerialState state[PCI_SERIAL_MAX_PORTS]; + uint32_t level[PCI_SERIAL_MAX_PORTS]; + qemu_irq *irqs; + uint8_t prog_if; + bool disable; +} PCIDivaSerialState; + +static void diva_pci_exit(PCIDevice *dev) +{ + PCIDivaSerialState *pci =3D DO_UPCAST(PCIDivaSerialState, dev, dev); + SerialState *s; + int i; + + for (i =3D 0; i < pci->ports; i++) { + s =3D pci->state + i; + qdev_unrealize(DEVICE(s)); + memory_region_del_subregion(&pci->membar, &s->io); + g_free(pci->name[i]); + } + qemu_free_irqs(pci->irqs, pci->ports); +} + +static void multi_serial_irq_mux(void *opaque, int n, int level) +{ + PCIDivaSerialState *pci =3D opaque; + int i, pending =3D 0; + + pci->level[n] =3D level; + for (i =3D 0; i < pci->ports; i++) { + if (pci->level[i]) { + pending =3D 1; + } + } + pci_set_irq(&pci->dev, pending); +} + +struct diva_info { + unsigned int nports:4; /* number of serial ports */ + unsigned int omask:12; /* offset mask: BIT(1) -> offset 8 */ +}; + +static struct diva_info diva_get_diva_info(PCIDeviceClass *pc) +{ + switch (pc->subsystem_id) { + case PCI_DEVICE_ID_HP_DIVA_POWERBAR: + case PCI_DEVICE_ID_HP_DIVA_HURRICANE: + return (struct diva_info) { .nports =3D 1, + .omask =3D BIT(0) }; + case PCI_DEVICE_ID_HP_DIVA_TOSCA2: + return (struct diva_info) { .nports =3D 2, + .omask =3D BIT(0) | BIT(1) }; + case PCI_DEVICE_ID_HP_DIVA_TOSCA1: + case PCI_DEVICE_ID_HP_DIVA_HALFDOME: + case PCI_DEVICE_ID_HP_DIVA_KEYSTONE: + return (struct diva_info) { .nports =3D 3, + .omask =3D BIT(0) | BIT(1) | BIT(2) }; + case PCI_DEVICE_ID_HP_DIVA_EVEREST: /* e.g. in rp3410 */ + return (struct diva_info) { .nports =3D 3, + .omask =3D BIT(0) | BIT(2) | BIT(7) }; + case PCI_DEVICE_ID_HP_DIVA_MAESTRO: + return (struct diva_info) { .nports =3D 4, + .omask =3D BIT(0) | BIT(1) | BIT(2) | BIT(7) }; + } + g_assert_not_reached(); +} + + +static void diva_pci_realize(PCIDevice *dev, Error **errp) +{ + PCIDeviceClass *pc =3D PCI_DEVICE_GET_CLASS(dev); + PCIDivaSerialState *pci =3D DO_UPCAST(PCIDivaSerialState, dev, dev); + SerialState *s; + struct diva_info di =3D diva_get_diva_info(pc); + size_t i, offset =3D 0; + size_t portmask =3D di.omask; + + pci->dev.config[PCI_CLASS_PROG] =3D pci->prog_if; + pci->dev.config[PCI_INTERRUPT_PIN] =3D 0x01; + memory_region_init(&pci->membar, OBJECT(pci), "serial_ports", 4096); + pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &pci->me= mbar); + pci->irqs =3D qemu_allocate_irqs(multi_serial_irq_mux, pci, di.nports); + + for (i =3D 0; i < di.nports; i++) { + s =3D pci->state + i; + if (!qdev_realize(DEVICE(s), NULL, errp)) { + diva_pci_exit(dev); + return; + } + s->irq =3D pci->irqs[i]; + pci->name[i] =3D g_strdup_printf("uart #%zu", i + 1); + memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, + pci->name[i], 8); + + /* calculate offset of given port based on bitmask */ + while ((portmask & BIT(0)) =3D=3D 0) { + offset +=3D 8; + portmask >>=3D 1; + } + memory_region_add_subregion(&pci->membar, offset, &s->io); + offset +=3D 8; + portmask >>=3D 1; + pci->ports++; + } + + /* mailbox bar */ + memory_region_init(&pci->mailboxbar, OBJECT(pci), "mailbox", 128 * KiB= ); + pci_register_bar(&pci->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_PREFETCH, &pci->mailboxbar); +} + +static const VMStateDescription vmstate_pci_diva =3D { + .name =3D "pci-diva-serial", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (const VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, PCIDivaSerialState), + VMSTATE_STRUCT_ARRAY(state, PCIDivaSerialState, PCI_SERIAL_MAX_POR= TS, + 0, vmstate_serial, SerialState), + VMSTATE_UINT32_ARRAY(level, PCIDivaSerialState, PCI_SERIAL_MAX_POR= TS), + VMSTATE_BOOL(disable, PCIDivaSerialState), + VMSTATE_END_OF_LIST() + } +}; + +static const Property diva_serial_properties[] =3D { + DEFINE_PROP_BOOL("disable", PCIDivaSerialState, disable, false), + DEFINE_PROP_CHR("chardev1", PCIDivaSerialState, state[0].chr), + DEFINE_PROP_CHR("chardev2", PCIDivaSerialState, state[1].chr), + DEFINE_PROP_CHR("chardev3", PCIDivaSerialState, state[2].chr), + DEFINE_PROP_CHR("chardev4", PCIDivaSerialState, state[3].chr), + DEFINE_PROP_UINT8("prog_if", PCIDivaSerialState, prog_if, 0x02), + DEFINE_PROP_UINT32("subvendor", PCIDivaSerialState, subvendor, + PCI_DEVICE_ID_HP_DIVA_TOSCA1), +}; + +static void diva_serial_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + PCIDeviceClass *pc =3D PCI_DEVICE_CLASS(klass); + pc->realize =3D diva_pci_realize; + pc->exit =3D diva_pci_exit; + pc->vendor_id =3D PCI_VENDOR_ID_HP; + pc->device_id =3D PCI_DEVICE_ID_HP_DIVA; + pc->subsystem_vendor_id =3D PCI_VENDOR_ID_HP; + pc->subsystem_id =3D PCI_DEVICE_ID_HP_DIVA_TOSCA1; + pc->revision =3D 3; + pc->class_id =3D PCI_CLASS_COMMUNICATION_SERIAL; + dc->vmsd =3D &vmstate_pci_diva; + device_class_set_props(dc, diva_serial_properties); + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); +} + +static void diva_serial_init(Object *o) +{ + PCIDevice *dev =3D PCI_DEVICE(o); + PCIDivaSerialState *pms =3D DO_UPCAST(PCIDivaSerialState, dev, dev); + struct diva_info di =3D diva_get_diva_info(PCI_DEVICE_GET_CLASS(dev)); + size_t i; + + for (i =3D 0; i < di.nports; i++) { + object_initialize_child(o, "serial[*]", &pms->state[i], TYPE_SERIA= L); + } +} + + +/* Diva-aux is the driver for portion 0 of the multifunction PCI device */ + +struct DivaAuxState { + PCIDevice dev; + MemoryRegion mem; + qemu_irq irq; +}; + +#define TYPE_DIVA_AUX "diva-aux" +OBJECT_DECLARE_SIMPLE_TYPE(DivaAuxState, DIVA_AUX) + +static void diva_aux_realize(PCIDevice *dev, Error **errp) +{ + DivaAuxState *pci =3D DO_UPCAST(DivaAuxState, dev, dev); + + pci->dev.config[PCI_CLASS_PROG] =3D 0x02; + pci->dev.config[PCI_INTERRUPT_PIN] =3D 0x01; + pci->irq =3D pci_allocate_irq(&pci->dev); + + memory_region_init(&pci->mem, OBJECT(pci), "mem", 16); + pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &pci->me= m); +} + +static void diva_aux_exit(PCIDevice *dev) +{ + DivaAuxState *pci =3D DO_UPCAST(DivaAuxState, dev, dev); + qemu_free_irq(pci->irq); +} + +static void diva_aux_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + PCIDeviceClass *pc =3D PCI_DEVICE_CLASS(klass); + pc->realize =3D diva_aux_realize; + pc->exit =3D diva_aux_exit; + pc->vendor_id =3D PCI_VENDOR_ID_HP; + pc->device_id =3D PCI_DEVICE_ID_HP_DIVA_AUX; + pc->subsystem_vendor_id =3D PCI_VENDOR_ID_HP; + pc->subsystem_id =3D 0x1291; + pc->revision =3D 1; + pc->class_id =3D PCI_CLASS_COMMUNICATION_MULTISERIAL; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->user_creatable =3D false; +} + +static void diva_aux_init(Object *o) +{ +} + +static const TypeInfo diva_aux_info =3D { + .name =3D TYPE_DIVA_AUX, + .parent =3D TYPE_PCI_DEVICE, + .instance_size =3D sizeof(DivaAuxState), + .instance_init =3D diva_aux_init, + .class_init =3D diva_aux_class_initfn, + .interfaces =3D (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, +}; + + + +static const TypeInfo diva_serial_pci_info =3D { + .name =3D "diva-gsp", + .parent =3D TYPE_PCI_DEVICE, + .instance_size =3D sizeof(PCIDivaSerialState), + .instance_init =3D diva_serial_init, + .class_init =3D diva_serial_class_initfn, + .interfaces =3D (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, +}; + +static void diva_pci_register_type(void) +{ + type_register_static(&diva_serial_pci_info); + type_register_static(&diva_aux_info); +} + +type_init(diva_pci_register_type) diff --git a/hw/char/meson.build b/hw/char/meson.build index ed3529cbbb..86ee808cae 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -20,6 +20,7 @@ system_ss.add(when: 'CONFIG_SHAKTI_UART', if_true: files(= 'shakti_uart.c')) system_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-console= .c')) system_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen_console.c')) system_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_uartlite.c')) +system_ss.add(when: 'CONFIG_DIVA_GSP', if_true: files('diva-gsp.c')) =20 system_ss.add(when: 'CONFIG_AVR_USART', if_true: files('avr_usart.c')) system_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_uart.c')) --=20 2.47.0