From patchwork Sun Dec 3 21:28:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sergey Kambalin X-Patchwork-Id: 1871100 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=TKwrcrwc; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Sk0Vd54Hpz23mf for ; Mon, 4 Dec 2023 08:36:41 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1r9u2D-0001xK-Um; Sun, 03 Dec 2023 16:29:53 -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 1r9u1p-0001Rw-6M; Sun, 03 Dec 2023 16:29:32 -0500 Received: from mail-yb1-xb29.google.com ([2607:f8b0:4864:20::b29]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1r9u1m-0005RH-4J; Sun, 03 Dec 2023 16:29:28 -0500 Received: by mail-yb1-xb29.google.com with SMTP id 3f1490d57ef6-db3a09e96daso2128220276.3; Sun, 03 Dec 2023 13:29:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1701638964; x=1702243764; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=IA89nY8jxlWQU5cEQQofnym1Upjf0MuK6dyCKlAlClw=; b=TKwrcrwcXUVfHuqQCVKC2vzpjRxfTajT12srcn+BkWCDq1xr5oepYONJ+ZfZWNsRSB OIpbfm4Vkm/3TC1fa5XoW06R3Mp9P/olK3TydT/jrDaNCv1sT1xRoYCKB5XvKh+K62Cp k8xPBoSsVndQ9q9Ey15h9UqiGM0crrF6TvglXqDkPBOL4VimIfPNK0TaJr6kLGPjPU17 S1eHh6ZiJF6jOGkSqjyB2ZkPt87fMg5oJbJduFHq4h5WcHKzKpJDhngrg/X9q+e3XZey 8o4Rl+BvGtQG/9xi8+rzaVJoQPK0vLh4IBAgKyvCtu6ObB0/VdL7R8hEqGakcHl/6uc6 sqaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701638964; x=1702243764; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=IA89nY8jxlWQU5cEQQofnym1Upjf0MuK6dyCKlAlClw=; b=E7J2I5iRamMuYSzFSQ1Hc5dd1husR64LwkeuDIJtQvzXY1In2BbfP0hxRmonsik6l3 cJOGydvuteh5c1h/+BX4GAMy40G09OWe+kTs67UsQjFCfyN8Hj7eX3cCVUySkacD2xZq o4bfyUmuKxQ+CEQZBHoeKAqN/WrG+Uq2yq5OqyYk0aBf8NgWWhRZELW/qI6EdQ7muyG+ tZX+ZL5PYvY+4hOhsfRO0Azfm92L9Xx3AgN7vU2FWz8Pp5q9xhVwXH642TDPJkchLH72 v9DIxSFOJ9xWPJY+MWNOKjJ1kzDAgZl8DEhZKgjg+31EQNkstStDF/cYZA88wkS8gpYJ 5z3g== X-Gm-Message-State: AOJu0YwyOHLuAFKn91cg6azMCkbXRntRqKcxBS5aDFDqwN+YB3nNjUMl KyHohWyJh90+SVf0xDPY21An3yiyfVYTAw== X-Google-Smtp-Source: AGHT+IG01BGKnhBW9S+2NohKjQR3/ei7HDGE4c61uQYX2ljUDTvkKaCHRtvLF3+AgqYkpBIzgAhprQ== X-Received: by 2002:a25:d8c6:0:b0:db7:dad0:60f5 with SMTP id p189-20020a25d8c6000000b00db7dad060f5mr2063446ybg.130.1701638964612; Sun, 03 Dec 2023 13:29:24 -0800 (PST) Received: from localhost.localdomain ([201.206.180.22]) by smtp.gmail.com with ESMTPSA id c17-20020a25a291000000b00d9cc606c78csm1807318ybi.41.2023.12.03.13.29.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 03 Dec 2023 13:29:24 -0800 (PST) From: Sergey Kambalin X-Google-Original-From: Sergey Kambalin To: qemu-arm@nongnu.org Cc: qemu-devel@nongnu.org, Sergey Kambalin Subject: [PATCH 15/45] Add BCM2838 PCIE host Date: Sun, 3 Dec 2023 15:28:35 -0600 Message-Id: <20231203212905.1364036-16-sergey.kambalin@auriga.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231203212905.1364036-15-sergey.kambalin@auriga.com> References: <20230726132512.149618-1-sergey.kambalin@auriga.com> <20231203212905.1364036-1-sergey.kambalin@auriga.com> <20231203212905.1364036-2-sergey.kambalin@auriga.com> <20231203212905.1364036-3-sergey.kambalin@auriga.com> <20231203212905.1364036-4-sergey.kambalin@auriga.com> <20231203212905.1364036-5-sergey.kambalin@auriga.com> <20231203212905.1364036-6-sergey.kambalin@auriga.com> <20231203212905.1364036-7-sergey.kambalin@auriga.com> <20231203212905.1364036-8-sergey.kambalin@auriga.com> <20231203212905.1364036-9-sergey.kambalin@auriga.com> <20231203212905.1364036-10-sergey.kambalin@auriga.com> <20231203212905.1364036-11-sergey.kambalin@auriga.com> <20231203212905.1364036-12-sergey.kambalin@auriga.com> <20231203212905.1364036-13-sergey.kambalin@auriga.com> <20231203212905.1364036-14-sergey.kambalin@auriga.com> <20231203212905.1364036-15-sergey.kambalin@auriga.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::b29; envelope-from=serg.oker@gmail.com; helo=mail-yb1-xb29.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Signed-off-by: Sergey Kambalin --- hw/arm/bcm2838_pcie.c | 216 +++++++++++++++++++++++++++++++++- include/hw/arm/bcm2838_pcie.h | 22 ++++ 2 files changed, 236 insertions(+), 2 deletions(-) diff --git a/hw/arm/bcm2838_pcie.c b/hw/arm/bcm2838_pcie.c index 3b4373c6a6..75146d6c2e 100644 --- a/hw/arm/bcm2838_pcie.c +++ b/hw/arm/bcm2838_pcie.c @@ -12,11 +12,222 @@ #include "hw/irq.h" #include "hw/pci-host/gpex.h" #include "hw/qdev-properties.h" -#include "migration/vmstate.h" -#include "qemu/module.h" #include "hw/arm/bcm2838_pcie.h" #include "trace.h" +/* + * RC host part + */ + +static uint64_t bcm2838_pcie_host_read(void *opaque, hwaddr offset, + unsigned size) { + hwaddr mmcfg_addr; + uint64_t value = ~0; + BCM2838PcieHostState *s = opaque; + PCIExpressHost *pcie_hb = PCIE_HOST_BRIDGE(s); + PCIDevice *root_pci_dev = PCI_DEVICE(&s->root_port); + uint8_t *root_regs = s->root_port.regs; + uint32_t *cfg_idx = (uint32_t *)(root_regs + BCM2838_PCIE_EXT_CFG_INDEX + - PCIE_CONFIG_SPACE_SIZE); + + if (offset < PCIE_CONFIG_SPACE_SIZE) { + value = pci_host_config_read_common(root_pci_dev, offset, + PCIE_CONFIG_SPACE_SIZE, size); + } else if (offset - PCIE_CONFIG_SPACE_SIZE + size + <= sizeof(s->root_port.regs)) { + switch (offset) { + case BCM2838_PCIE_EXT_CFG_DATA + ... BCM2838_PCIE_EXT_CFG_DATA + PCIE_CONFIG_SPACE_SIZE - 1: + mmcfg_addr = *cfg_idx + | PCIE_MMCFG_CONFOFFSET(offset - BCM2838_PCIE_EXT_CFG_DATA); + value = pcie_hb->mmio.ops->read(opaque, mmcfg_addr, size); + break; + default: + memcpy(&value, root_regs + offset - PCIE_CONFIG_SPACE_SIZE, size); + } + } else { + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: out-of-range access, %u bytes @ offset 0x%04" PRIx64 "\n", + __func__, size, offset); + } + + trace_bcm2838_pcie_host_read(size, offset, value); + return value; +} + +static void bcm2838_pcie_host_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) { + hwaddr mmcfg_addr; + BCM2838PcieHostState *s = opaque; + PCIExpressHost *pcie_hb = PCIE_HOST_BRIDGE(s); + PCIDevice *root_pci_dev = PCI_DEVICE(&s->root_port); + uint8_t *root_regs = s->root_port.regs; + uint32_t *cfg_idx = (uint32_t *)(root_regs + BCM2838_PCIE_EXT_CFG_INDEX + - PCIE_CONFIG_SPACE_SIZE); + + trace_bcm2838_pcie_host_write(size, offset, value); + + if (offset < PCIE_CONFIG_SPACE_SIZE) { + pci_host_config_write_common(root_pci_dev, offset, + PCIE_CONFIG_SPACE_SIZE, value, size); + } else if (offset - PCIE_CONFIG_SPACE_SIZE + size + <= sizeof(s->root_port.regs)) { + switch (offset) { + case BCM2838_PCIE_EXT_CFG_DATA + ... BCM2838_PCIE_EXT_CFG_DATA + PCIE_CONFIG_SPACE_SIZE - 1: + mmcfg_addr = *cfg_idx + | PCIE_MMCFG_CONFOFFSET(offset - BCM2838_PCIE_EXT_CFG_DATA); + pcie_hb->mmio.ops->write(opaque, mmcfg_addr, value, size); + break; + default: + memcpy(root_regs + offset - PCIE_CONFIG_SPACE_SIZE, &value, size); + } + } else { + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: out-of-range access, %u bytes @ offset 0x%04" PRIx64 "\n", + __func__, size, offset); + } +} + +static const MemoryRegionOps bcm2838_pcie_host_ops = { + .read = bcm2838_pcie_host_read, + .write = bcm2838_pcie_host_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = {.max_access_size = sizeof(uint64_t)}, +}; + +int bcm2838_pcie_host_set_irq_num(BCM2838PcieHostState *s, int index, int spi) +{ + if (index >= BCM2838_PCIE_NUM_IRQS) { + return -EINVAL; + } + + s->irq_num[index] = spi; + return 0; +} + +static void bcm2838_pcie_host_set_irq(void *opaque, int irq_num, int level) +{ + BCM2838PcieHostState *s = opaque; + + qemu_set_irq(s->irq[irq_num], level); +} + +static PCIINTxRoute bcm2838_pcie_host_route_intx_pin_to_irq(void *opaque, + int pin) +{ + PCIINTxRoute route; + BCM2838PcieHostState *s = opaque; + + route.irq = s->irq_num[pin]; + route.mode = route.irq < 0 ? PCI_INTX_DISABLED : PCI_INTX_ENABLED; + + return route; +} + +static int bcm2838_pcie_host_map_irq(PCIDevice *pci_dev, int pin) +{ + return pin; +} + +static void bcm2838_pcie_host_realize(DeviceState *dev, Error **errp) +{ + PCIHostState *pci = PCI_HOST_BRIDGE(dev); + BCM2838PcieHostState *s = BCM2838_PCIE_HOST(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + int i; + + memory_region_init_io(&s->cfg_regs, OBJECT(s), &bcm2838_pcie_host_ops, s, + "bcm2838_pcie_cfg_regs", BCM2838_PCIE_REGS_SIZE); + sysbus_init_mmio(sbd, &s->cfg_regs); + + /* + * The MemoryRegions io_mmio and io_ioport that we pass to + * pci_register_root_bus() are not the same as the MemoryRegions + * io_mmio_window and io_ioport_window that we expose as SysBus MRs. + * The difference is in the behavior of accesses to addresses where no PCI + * device has been mapped. + * + * io_mmio and io_ioport are the underlying PCI view of the PCI address + * space, and when a PCI device does a bus master access to a bad address + * this is reported back to it as a transaction failure. + * + * io_mmio_window and io_ioport_window implement "unmapped addresses read as + * -1 and ignore writes"; this is a traditional x86 PC behavior, which is + * not mandated properly by the PCI spec but expected by the majority of + * PCI-using guest software, including Linux. + * + * We implement it in the PCIe host controller, by providing the *_window + * MRs, which are containers with io ops that implement the 'background' + * behavior and which hold the real PCI MRs as sub-regions. + */ + memory_region_init(&s->io_mmio, OBJECT(s), "bcm2838_pcie_mmio", UINT64_MAX); + memory_region_init(&s->io_ioport, OBJECT(s), "bcm2838_pcie_ioport", + 64 * 1024); + + memory_region_init_io(&s->io_mmio_window, OBJECT(s), + &unassigned_io_ops, OBJECT(s), + "bcm2838_pcie_mmio_window", UINT64_MAX); + memory_region_init_io(&s->io_ioport_window, OBJECT(s), + &unassigned_io_ops, OBJECT(s), + "bcm2838_pcie_ioport_window", 64 * 1024); + + memory_region_add_subregion(&s->io_mmio_window, 0, &s->io_mmio); + memory_region_add_subregion(&s->io_ioport_window, 0, &s->io_ioport); + sysbus_init_mmio(sbd, &s->io_mmio_window); + sysbus_init_mmio(sbd, &s->io_ioport_window); + + for (i = 0; i < BCM2838_PCIE_NUM_IRQS; i++) { + sysbus_init_irq(sbd, &s->irq[i]); + s->irq_num[i] = -1; + } + + pci->bus = pci_register_root_bus(dev, "pcie.0", bcm2838_pcie_host_set_irq, + bcm2838_pcie_host_map_irq, s, &s->io_mmio, + &s->io_ioport, 0, BCM2838_PCIE_NUM_IRQS, + TYPE_PCIE_BUS); + pci_bus_set_route_irq_fn(pci->bus, bcm2838_pcie_host_route_intx_pin_to_irq); + qdev_realize(DEVICE(&s->root_port), BUS(pci->bus), &error_fatal); +} + +static const char *bcm2838_pcie_host_root_bus_path(PCIHostState *host_bridge, + PCIBus *rootbus) +{ + return "0000:00"; +} + +static void bcm2838_pcie_host_class_init(ObjectClass *class, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(class); + PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class); + + hc->root_bus_path = bcm2838_pcie_host_root_bus_path; + dc->realize = bcm2838_pcie_host_realize; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + dc->fw_name = "pci"; +} + +static void bcm2838_pcie_host_initfn(Object *obj) +{ + BCM2838PcieHostState *s = BCM2838_PCIE_HOST(obj); + BCM2838PcieRootState *root = &s->root_port; + + object_initialize_child(obj, "root_port", root, TYPE_BCM2838_PCIE_ROOT); + qdev_prop_set_int32(DEVICE(root), "addr", PCI_DEVFN(0, 0)); + qdev_prop_set_bit(DEVICE(root), "multifunction", false); +} + +static const TypeInfo bcm2838_pcie_host_info = { + .name = TYPE_BCM2838_PCIE_HOST, + .parent = TYPE_PCIE_HOST_BRIDGE, + .instance_size = sizeof(BCM2838PcieHostState), + .instance_init = bcm2838_pcie_host_initfn, + .class_init = bcm2838_pcie_host_class_init, +}; + /* * RC root part (D0:F0) */ @@ -69,6 +280,7 @@ static const TypeInfo bcm2838_pcie_root_info = { static void bcm2838_pcie_register(void) { type_register_static(&bcm2838_pcie_root_info); + type_register_static(&bcm2838_pcie_host_info); } type_init(bcm2838_pcie_register) diff --git a/include/hw/arm/bcm2838_pcie.h b/include/hw/arm/bcm2838_pcie.h index 39828f817f..58c3a0efe7 100644 --- a/include/hw/arm/bcm2838_pcie.h +++ b/include/hw/arm/bcm2838_pcie.h @@ -16,6 +16,9 @@ #include "hw/pci/pcie_port.h" #include "qom/object.h" +#define TYPE_BCM2838_PCIE_HOST "bcm2838-pcie-host" +OBJECT_DECLARE_SIMPLE_TYPE(BCM2838PcieHostState, BCM2838_PCIE_HOST) + #define TYPE_BCM2838_PCIE_ROOT "bcm2838-pcie-root" OBJECT_DECLARE_TYPE(BCM2838PcieRootState, BCM2838PcieRootClass, BCM2838_PCIE_ROOT) @@ -50,4 +53,23 @@ struct BCM2838PcieRootClass { }; +struct BCM2838PcieHostState { + /*< private >*/ + PCIExpressHost parent_obj; + + /*< public >*/ + BCM2838PcieRootState root_port; + + MemoryRegion cfg_regs; + MemoryRegion io_ioport; + MemoryRegion io_mmio; + MemoryRegion io_ioport_window; + MemoryRegion io_mmio_window; + + qemu_irq irq[BCM2838_PCIE_NUM_IRQS]; + int irq_num[BCM2838_PCIE_NUM_IRQS]; +}; + +int bcm2838_pcie_host_set_irq_num(BCM2838PcieHostState *s, int index, int spi); + #endif /* BCM2838_PCIE_H */