From patchwork Thu Jan 9 02:44:40 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ethan Chen X-Patchwork-Id: 13931900 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5A8CDE7719A for ; Thu, 9 Jan 2025 03:14:32 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tVizD-0000v3-68; Wed, 08 Jan 2025 22:13:31 -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 1tViyy-0000jR-5c; Wed, 08 Jan 2025 22:13:16 -0500 Received: from 60-248-80-70.hinet-ip.hinet.net ([60.248.80.70] helo=Atcsqr.andestech.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tViyv-0001NX-N3; Wed, 08 Jan 2025 22:13:15 -0500 Received: from Atcsqr.andestech.com (localhost [127.0.0.2] (may be forged)) by Atcsqr.andestech.com with ESMTP id 5092jpqw029104; Thu, 9 Jan 2025 10:45:51 +0800 (+08) (envelope-from ethan84@andestech.com) Received: from mail.andestech.com (ATCPCS31.andestech.com [10.0.1.89]) by Atcsqr.andestech.com with ESMTPS id 5092j2Y8027864 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 9 Jan 2025 10:45:02 +0800 (+08) (envelope-from ethan84@andestech.com) Received: from atcpcw16.andestech.com (10.0.1.106) by ATCPCS31.andestech.com (10.0.1.89) with Microsoft SMTP Server (TLS) id 14.3.498.0; Thu, 9 Jan 2025 10:45:02 +0800 To: CC: , , , , , , , , , , , , Ethan Chen Subject: [PATCH v9 7/8] hw/misc/riscv_iopmp_dispatcher: Device for redirect IOPMP transaction infomation Date: Thu, 9 Jan 2025 10:44:40 +0800 Message-ID: <20250109024441.3283671-8-ethan84@andestech.com> X-Mailer: git-send-email 2.42.0.345.gaab89be2eb.dirty In-Reply-To: <20250109024441.3283671-1-ethan84@andestech.com> References: <20250109024441.3283671-1-ethan84@andestech.com> MIME-Version: 1.0 X-Originating-IP: [10.0.1.106] X-DKIM-Results: atcpcs31.andestech.com; dkim=none; X-DNSRBL: X-MAIL: Atcsqr.andestech.com 5092jpqw029104 Received-SPF: pass client-ip=60.248.80.70; envelope-from=ethan84@andestech.com; helo=Atcsqr.andestech.com X-Spam_score_int: -8 X-Spam_score: -0.9 X-Spam_bar: / X-Spam_report: (-0.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, RDNS_DYNAMIC=0.982, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, TVD_RCVD_IP=0.001 autolearn=no 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: , Reply-to: Ethan Chen X-Patchwork-Original-From: Ethan Chen via From: Ethan Chen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This device determines the target IOPMP device for forwarding information based on: * Address: For parallel IOPMP devices * Stage: For cascading IOPMP devices Signed-off-by: Ethan Chen --- hw/misc/meson.build | 1 + hw/misc/riscv_iopmp_dispatcher.c | 136 +++++++++++++++++++++++ include/hw/misc/riscv_iopmp_dispatcher.h | 61 ++++++++++ 3 files changed, 198 insertions(+) create mode 100644 hw/misc/riscv_iopmp_dispatcher.c create mode 100644 include/hw/misc/riscv_iopmp_dispatcher.h diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 88f2bb6b88..497f83637f 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -35,6 +35,7 @@ system_ss.add(when: 'CONFIG_SIFIVE_E_AON', if_true: files('sifive_e_aon.c')) system_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c')) system_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.c')) specific_ss.add(when: 'CONFIG_RISCV_IOPMP', if_true: files('riscv_iopmp.c')) +specific_ss.add(when: 'CONFIG_RISCV_IOPMP', if_true: files('riscv_iopmp_dispatcher.c')) subdir('macio') diff --git a/hw/misc/riscv_iopmp_dispatcher.c b/hw/misc/riscv_iopmp_dispatcher.c new file mode 100644 index 0000000000..ba6eaeb396 --- /dev/null +++ b/hw/misc/riscv_iopmp_dispatcher.c @@ -0,0 +1,136 @@ +/* + * QEMU RISC-V IOPMP dispatcher + * + * Receives transaction information from the requestor and forwards it to the + * corresponding IOPMP device. + * + * Copyright (c) 2023-2025 Andes Tech. Corp. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "trace.h" +#include "exec/exec-all.h" +#include "exec/address-spaces.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "hw/misc/riscv_iopmp_dispatcher.h" +#include "memory.h" +#include "hw/irq.h" +#include "hw/misc/riscv_iopmp_txn_info.h" + +static void riscv_iopmp_dispatcher_realize(DeviceState *dev, Error **errp) +{ + int i; + RISCVIOPMPDispState *s = RISCV_IOPMP_DISP(dev); + + s->SinkMemMap = g_new(SinkMemMapEntry *, s->stage_num); + for (i = 0; i < s->stage_num; i++) { + s->SinkMemMap[i] = g_new(SinkMemMapEntry, s->target_num); + } + + object_initialize_child(OBJECT(s), "iopmp_dispatcher_txn_info", + &s->txn_info_sink, + TYPE_RISCV_IOPMP_DISP_SS); +} + +static Property iopmp_dispatcher_properties[] = { + DEFINE_PROP_UINT32("stage-num", RISCVIOPMPDispState, stage_num, 2), + DEFINE_PROP_UINT32("target-num", RISCVIOPMPDispState, target_num, 10), +}; + +static void riscv_iopmp_dispatcher_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + device_class_set_props(dc, iopmp_dispatcher_properties); + dc->realize = riscv_iopmp_dispatcher_realize; +} + +static const TypeInfo riscv_iopmp_dispatcher_info = { + .name = TYPE_RISCV_IOPMP_DISP, + .parent = TYPE_DEVICE, + .instance_size = sizeof(RISCVIOPMPDispState), + .class_init = riscv_iopmp_dispatcher_class_init, +}; + +static size_t dispatcher_txn_info_push(StreamSink *txn_info_sink, + unsigned char *buf, + size_t len, bool eop) +{ + uint64_t addr; + uint32_t stage; + int i, j; + riscv_iopmp_disp_ss *ss = + RISCV_IOPMP_DISP_SS(txn_info_sink); + RISCVIOPMPDispState *s = RISCV_IOPMP_DISP(container_of(ss, + RISCVIOPMPDispState, txn_info_sink)); + riscv_iopmp_txn_info signal; + memcpy(&signal, buf, len); + addr = signal.start_addr; + stage = signal.stage; + for (i = stage; i < s->stage_num; i++) { + for (j = 0; j < s->target_num; j++) { + if (s->SinkMemMap[i][j].map.base <= addr && + addr < s->SinkMemMap[i][j].map.base + + s->SinkMemMap[i][j].map.size) { + return stream_push(s->SinkMemMap[i][j].sink, buf, len, eop); + } + } + } + /* Always pass if target is not protected by IOPMP*/ + return 1; +} + +static void riscv_iopmp_disp_ss_class_init( + ObjectClass *klass, void *data) +{ + StreamSinkClass *ssc = STREAM_SINK_CLASS(klass); + ssc->push = dispatcher_txn_info_push; +} + +static const TypeInfo riscv_iopmp_disp_ss_info = { + .name = TYPE_RISCV_IOPMP_DISP_SS, + .parent = TYPE_OBJECT, + .instance_size = sizeof(riscv_iopmp_disp_ss), + .class_init = riscv_iopmp_disp_ss_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_STREAM_SINK }, + { } + }, +}; + +void iopmp_dispatcher_add_target(DeviceState *dev, StreamSink *sink, + uint64_t base, uint64_t size, uint32_t stage, uint32_t id) +{ + RISCVIOPMPDispState *s = RISCV_IOPMP_DISP(dev); + if (stage < s->stage_num && id < s->target_num) { + s->SinkMemMap[stage][id].map.base = base; + s->SinkMemMap[stage][id].map.size = size; + s->SinkMemMap[stage][id].sink = sink; + } +} + +static void +iopmp_dispatcher_register_types(void) +{ + type_register_static(&riscv_iopmp_dispatcher_info); + type_register_static(&riscv_iopmp_disp_ss_info); +} + +type_init(iopmp_dispatcher_register_types); + diff --git a/include/hw/misc/riscv_iopmp_dispatcher.h b/include/hw/misc/riscv_iopmp_dispatcher.h new file mode 100644 index 0000000000..bbaa76507b --- /dev/null +++ b/include/hw/misc/riscv_iopmp_dispatcher.h @@ -0,0 +1,61 @@ +/* + * QEMU RISC-V IOPMP dispatcher + * + * Receives transaction information from the requestor and forwards it to the + * corresponding IOPMP device. + * + * Copyright (c) 2023-2024 Andes Tech. Corp. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef RISCV_IOPMP_DISPATCHER_H +#define RISCV_IOPMP_DISPATCHER_H + +#include "hw/sysbus.h" +#include "qemu/typedefs.h" +#include "memory.h" +#include "hw/stream.h" +#include "hw/misc/riscv_iopmp_txn_info.h" +#include "exec/hwaddr.h" + +#define TYPE_RISCV_IOPMP_DISP "riscv-iopmp-dispatcher" +OBJECT_DECLARE_SIMPLE_TYPE(RISCVIOPMPDispState, RISCV_IOPMP_DISP) + +#define TYPE_RISCV_IOPMP_DISP_SS "riscv-iopmp-dispatcher-streamsink" +OBJECT_DECLARE_SIMPLE_TYPE(riscv_iopmp_disp_ss, RISCV_IOPMP_DISP_SS) + +typedef struct riscv_iopmp_disp_ss { + Object parent; +} riscv_iopmp_disp_ss; + +typedef struct SinkMemMapEntry { + StreamSink *sink; + MemMapEntry map; +} SinkMemMapEntry; + +typedef struct RISCVIOPMPDispState { + SysBusDevice parent_obj; + riscv_iopmp_disp_ss txn_info_sink; + SinkMemMapEntry **SinkMemMap; + /* The maximum number of cascading stages of IOPMP */ + uint32_t stage_num; + /* The maximum number of parallel IOPMP devices within a single stage. */ + uint32_t target_num; +} RISCVIOPMPDispState; + +void iopmp_dispatcher_add_target(DeviceState *dev, StreamSink *sink, + uint64_t base, uint64_t size, uint32_t stage, uint32_t id); +#endif