From 0e07810c35d4aa44af20423327e7ac50965f05cd Mon Sep 17 00:00:00 2001 From: caojinhuahw Date: Tue, 11 Nov 2025 16:33:16 +0800 Subject: [PATCH 1/5] ub config: introduce ub config base framework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、add ub config space realize required struct 2、add some ub config space item define according to ub spce 3、add memmap table for ub config addr convert Signed-off-by: caojinhuahw --- hw/arm/virt.c | 6 + hw/ub/meson.build | 1 + hw/ub/ub_config.c | 133 +++++++++ include/hw/ub/hisi/ubc.h | 215 ++++++++++++++ include/hw/ub/ub_common.h | 98 +++++++ include/hw/ub/ub_config.h | 579 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 1032 insertions(+) create mode 100644 hw/ub/ub_config.c create mode 100644 include/hw/ub/ub_config.h diff --git a/hw/arm/virt.c b/hw/arm/virt.c index a27d3b5fc3..470a320bc6 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -98,6 +98,7 @@ #include "hw/ub/hisi/ub_fm.h" #include "hw/ub/ub_ummu.h" #include "hw/ub/ub_common.h" +#include "hw/ub/ub_config.h" #endif // CONFIG_UB #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ @@ -1757,6 +1758,11 @@ static void create_ub(VirtMachineState *vms) MemoryRegion *mmio_reg; MemoryRegion *mmio_alias; + if (ub_cfg_addr_map_table_init() < 0) { + qemu_log("failed to init ub cfg addr map table\n"); + exit(1); + } + ubc = qdev_new(TYPE_BUS_CONTROLLER); qdev_prop_set_uint32(ubc, "ub-bus-controller-msgq-reg-size", UBC_MSGQ_REG_SIZE); qdev_prop_set_uint32(ubc, "ub-bus-controller-fm-msgq-reg-size", FM_MSGQ_REG_SIZE); diff --git a/hw/ub/meson.build b/hw/ub/meson.build index e1146704e6..ffa135dacf 100644 --- a/hw/ub/meson.build +++ b/hw/ub/meson.build @@ -2,6 +2,7 @@ ub_ss = ss.source_set() ub_ss.add(files( 'ub.c', 'ub_ubc.c', + 'ub_config.c', 'ub_acpi.c', )) system_ss.add_all(when: 'CONFIG_HW_UB', if_true: ub_ss) diff --git a/hw/ub/ub_config.c b/hw/ub/ub_config.c new file mode 100644 index 0000000000..32ae6b91e4 --- /dev/null +++ b/hw/ub/ub_config.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that 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/module.h" +#include "hw/arm/virt.h" +#include "hw/qdev-properties.h" +#include "hw/ub/ub.h" +#include "hw/ub/ub_bus.h" +#include "hw/ub/ub_ubc.h" +#include "hw/ub/ub_config.h" +#include "qemu/log.h" +#include "migration/vmstate.h" +#include "qapi/error.h" + +UbCfgAddrMapEntry *g_ub_cfg_addr_map_table = NULL; +uint32_t g_emulated_ub_cfg_size; + +uint64_t ub_cfg_slice_start_offset[UB_CFG_EMULATED_SLICES_NUM] = { + [CFG0_BASIC] = 0x0, + [CAP1_RSV] = 0x100, + [CAP2_SHP] = 0x200, + [CAP3_ERR_RECORD] = 0x300, + [CAP4_ERR_INFO] = 0x400, + [CAP5_EMQ] = 0x500, + [CFG1_BASIC] = 0x10000, + [CAP1_DECODER] = 0x10100, + [CAP2_JETTY] = 0x10200, + [CAP3_INT_TYPE1] = 0x10300, + [CAP4_INT_TYPE2] = 0x10400, + [CAP5_RSV] = 0x10500, + [CAP6_UB_MEM] = 0x10600, + [CFG0_PORT_BASIC] = 0x20000, + [CFG0_ROUTE_TABLE] = 0xF0000000, +}; + +static void ub_cfg_display_addr_map_table(void) +{ + int i; + + for (i = 0; i < UB_CFG_SLICE_NUMS; i++) { + qemu_log("map_table[%d]---start_addr: 0x%lx, mapped_offset: 0x%lx\n", i, + g_ub_cfg_addr_map_table[i].start_addr, g_ub_cfg_addr_map_table[i].mapped_offset); + } +} + +int ub_cfg_addr_map_table_init(void) +{ + int i, idx; + + /* used in all qemu lifecycle, be freed when qemu exit */ + g_ub_cfg_addr_map_table = malloc(UB_CFG_SLICE_NUMS * sizeof(UbCfgAddrMapEntry)); + if (!g_ub_cfg_addr_map_table) { + qemu_log("failed to malloc for g_ub_cfg_addr_map_table\n"); + return -1; + } + + /* fill general slice map table */ + for (i = 0; i < UB_CFG_GENERAL_SLICES_NUM; i++) { + g_ub_cfg_addr_map_table[i].start_addr = ub_cfg_slice_start_offset[i]; + g_ub_cfg_addr_map_table[i].start_addr *= UB_CFG_START_OFFSET_GRANU; + g_ub_cfg_addr_map_table[i].mapped_offset = i * UB_CFG_SLICE_SIZE; + } + + /* fill port info slice map table */ + for (i = 0; i < UB_DEV_MAX_NUM_OF_PORT; i++) { + idx = UB_CFG_GENERAL_SLICES_NUM + i; + g_ub_cfg_addr_map_table[idx].start_addr = ub_cfg_slice_start_offset[CFG0_PORT_BASIC]; + g_ub_cfg_addr_map_table[idx].start_addr *= UB_CFG_START_OFFSET_GRANU; + g_ub_cfg_addr_map_table[idx].start_addr += i * UB_PORT_SZ; + g_ub_cfg_addr_map_table[idx].mapped_offset = idx * UB_CFG_SLICE_SIZE; + } + + /* fill route table slice map table */ + idx = UB_CFG_GENERAL_SLICES_NUM + UB_DEV_MAX_NUM_OF_PORT; + g_ub_cfg_addr_map_table[idx].start_addr = ub_cfg_slice_start_offset[CFG0_ROUTE_TABLE]; + g_ub_cfg_addr_map_table[idx].start_addr *= UB_CFG_START_OFFSET_GRANU; + g_ub_cfg_addr_map_table[idx].mapped_offset = idx * UB_CFG_SLICE_SIZE; + + g_emulated_ub_cfg_size = UB_CFG_SLICE_NUMS * UB_CFG_SLICE_SIZE; + qemu_log("each ub-dev emulated ub cfg size is 0x%x bytes\n", g_emulated_ub_cfg_size); + + return 0; +} + +uint32_t ub_emulated_config_size(void) +{ + return g_emulated_ub_cfg_size; +} + +uint64_t ub_cfg_offset_to_emulated_offset(uint64_t offset, bool check_success) +{ + uint64_t emulate_offset = UINT64_MAX; + int i; + uint64_t diff; + + for (i = 0; i < UB_CFG_SLICE_NUMS; i++) { + if (offset < g_ub_cfg_addr_map_table[i].start_addr) { + break; + } + + diff = offset - g_ub_cfg_addr_map_table[i].start_addr; + if (diff >= UB_CFG_SLICE_SIZE) { + continue; + } + + emulate_offset = g_ub_cfg_addr_map_table[i].mapped_offset + diff; + break; + } + + if (check_success) { + if (emulate_offset == UINT64_MAX) { + ub_cfg_display_addr_map_table(); + qemu_log("failed to convert offset 0x%lx to emulated offset\n", offset); + } + assert(emulate_offset != UINT64_MAX); + } + + return emulate_offset; +} \ No newline at end of file diff --git a/include/hw/ub/hisi/ubc.h b/include/hw/ub/hisi/ubc.h index c34693accb..f9201741a9 100644 --- a/include/hw/ub/hisi/ubc.h +++ b/include/hw/ub/hisi/ubc.h @@ -184,4 +184,219 @@ #define HI_MSGQ_MAX_DEPTH 1024 #define HI_MSGQ_MIN_DEPTH 4 +/* + * msgq sq memory layout + * +----------------------------+ + * | sqe 1 | + * |----------------------------| 12Byte + * +----| payload addr(offset) | + * | +----------------------------+ + * | | sqe 2 | + * | |----------------------------| 12Byte + * +-------| payload addr(offset) | + * | | +----------------------------+ + * | | | ..... | + * | | | | + * | | +----------------------------+ + * | | | sqe (depth) | + * | | |----------------------------| 12Byte + * +---------| payload addr(offset) | + * | | | +----------------------------+ + * | | +--> | payload 1 | 1K + * | | +----------------------------+ + * | +-----> | payload 2 | 1K + * | +----------------------------+ + * | | ....... | 1K + * | +----------------------------+ + * +-------> | payload (depth) | 1K + * +----------------------------+ + * + * SQE layout + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| + * +-----------------------------------------------+-----------------------+-----------+-----------+ + * | payload length | msg id |submsg code| msg code | + * +-----------------------------------------------+-----+--+--+-----------+-----------+-----------+ + * | rsvd |e1|e2| vl | rsvd | e1:icrc e2:local + * +-----------------------------------------------------+--+--+-----------+-----------------------+ + * | payload addr | + * +-----------------------------------------------------------------------------------------------+ + */ +typedef struct HiMsgSqe { + /* DW0 */ + uint32_t task_type : 2; + uint32_t rsvd0 : 2; + uint32_t local : 1; + uint32_t dev_type : 2; + uint32_t icrc : 1; + union { + struct { + uint8_t type : 1; + uint8_t msg_code : 3; + uint8_t sub_msg_code : 4; + }; + uint8_t opcode; + }; + uint32_t p_len : 12; + uint32_t rsvd1 : 4; + + /* DW1 */ + uint32_t msn : 16; + uint32_t rsvd3 : 16; + + /* DW2 */ + uint32_t p_addr; + + /* DW3 */ + uint32_t rsvd2; +} HiMsgSqe; +#define HI_MSG_SQE_SIZE sizeof(HiMsgSqe) + +typedef struct HiMsgCqe { + /* DW0 */ + uint32_t task_type : 2; + uint32_t rsvd0 : 6; + union { + struct { + uint8_t type : 1; + uint8_t msg_code : 3; + uint8_t sub_msg_code : 4; + }; + uint8_t opcode; + }; + uint32_t p_len : 12; + uint32_t rsvd1 : 4; + + /* DW1 */ + uint32_t msn : 16; + uint32_t rsvd5 : 16; + + /* DW2 */ + uint32_t rq_pi : 10; + uint32_t rsvd2 : 6; + uint32_t status : 8; + uint32_t rsvd3 : 8; + + /* DW3 */ + uint32_t rsvd4; +} HiMsgCqe; +#define HI_MSG_CQE_SIZE sizeof(HiMsgCqe) + +typedef struct HiMsgSqePld { + char packet[HI_MSG_SQE_PLD_SIZE]; +} HiMsgSqePld; + +typedef struct HiMsgqInfo { + uint64_t sq_base_addr_gpa; + uint64_t sq_base_addr_hva; + uint64_t sq_sz; + uint64_t cq_base_addr_gpa; + uint64_t cq_base_addr_hva; + uint64_t cq_sz; + uint64_t rq_base_addr_gpa; + uint64_t rq_base_addr_hva; + uint64_t rq_sz; +} HiMsgqInfo; + +typedef enum HiMsgqIdx { + MSG_SQ = 0, + MSG_RQ = 1, + MSG_CQ = 2, + MSGQ_NUM +} HiMsgqIdx_t; + +enum HiCqeStatus { + CQE_SUCCESS, + CQE_FAIL +}; + +enum HiCqSwState { + CQ_SW_INIT, + CQ_SW_HANDLED +}; + +struct HiMsgQueue { + HiMsgqIdx_t idx; + + union { + struct HiMsgSqe *sqe; + void *rqe; + struct HiMsgCqe *cqe; + void *entry; + }; + + uint16_t entry_size; + uint8_t depth; + uint8_t ci; + uint8_t pi; + + pthread_spinlock_t lock; +}; + +#define UB_MSG_CODE_ENUM 0x8 /* hisi private */ +enum HiEnumSubMsgCode { + ENUM_QUERY_REQ = 0, + ENUM_QUERY_RSP, + CNA_CFG_REQ, + CNA_CFG_RSP +}; + +enum UB_MSG_RSP_STATUS_CODE { + UB_MSG_RSP_SUCCESS, + UB_MSG_RSP_INVALID_MESSAGE, + UB_MSG_RSP_UPI_BEYOND_AUTH, + UB_MSG_RSP_INVALID_TOKEN, + UB_MSG_RSP_REG_ATTR_MISMATCH, + UB_MSG_RSP_INVALID_ADDR, + UB_MSG_RSP_HW_EXEC_FAILED, + UB_MSG_RSP_LACK_OF_EID, +}; + +enum HiTaskType { + PROTOCOL_MSG = 0, + PROTOCOL_ENUM = 1, + HISI_PRIVATE = 2 +}; + +typedef enum HiMsgqPrivateOpcode { + CC_CTX_CFG_CMD = 0, + QUERY_UB_MEM_ROUTE_CMD = 1, + EU_TABLE_CFG_CMD = 2, + CC_CTX_QUERY_CMD = 3 +} HiMsgqPrivateOpcode; + +typedef enum HiEuCfgStatus { + EU_CFG_FAIL, + EU_CFG_SUCCESS +} HiEuCfgStatus; + +typedef struct HiEuCfgReq { + uint32_t eu_msg_code : 4; + uint32_t cfg_entry_num : 10; + uint32_t tbl_cfg_mode : 1; + uint32_t tbl_cfg_status : 1; + uint32_t entry_start_id : 16; + uint32_t eid : 20; + uint32_t rsv0 : 12; + uint32_t upi : 16; + uint32_t rsv1 : 16; +} HiEuCfgReq; +#define HI_EU_CFG_REQ_SIZE 12 + +typedef struct HiEuCfgRsp { + uint32_t eu_msg_code : 4; + uint32_t cfg_entry_num : 10; + uint32_t tbl_cfg_mode : 1; + uint32_t tbl_cfg_status : 1; + uint32_t entry_start_id : 16; +} HiEuCfgRsp; +#define HI_EU_CFG_RSP_SIZE 4 + +typedef struct HiEuCfgPld { + union { + HiEuCfgReq req; + HiEuCfgRsp rsp; + }; +} HiEuCfgPld; + #endif diff --git a/include/hw/ub/ub_common.h b/include/hw/ub/ub_common.h index 1336ea3ed3..b8a0287e56 100644 --- a/include/hw/ub/ub_common.h +++ b/include/hw/ub/ub_common.h @@ -314,5 +314,103 @@ (((~0ULL) - (1ULL << (l)) + 1) & \ (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) #define DASH_SZ 3 +/* The caller is responsible for free memory. */ +char *line_generator(uint8_t len); +enum UbMsgType { + MSG_REQ = 0, + MSG_RSP = 1 +}; + +enum UbMsgCode { + UB_MSG_CODE_RAS = 0, + UB_MSG_CODE_LINK = 1, + UB_MSG_CODE_CFG = 2, + UB_MSG_CODE_VDM = 3, + UB_MSG_CODE_EXCH = 4, + UB_MSG_CODE_SEC = 5, + UB_MSG_CODE_POOL = 6, + UB_MSG_CODE_MAX = 7 +}; + +struct UbLinkHeader { + uint32_t plen : 14; + uint32_t rm : 2; + uint32_t cfg : 4; + uint32_t rsvd1 : 1; + uint32_t vl : 4; + uint32_t rsvd0 : 1; + uint32_t crd_vl : 4; + uint32_t ack : 1; + uint32_t crd : 1; +}; +#define UB_CLAN_LINK_CFG 6 + +struct ClanNetworkHeader { + /* DW0 */ + uint32_t dcna : 16; + uint32_t scna : 16; + /* DW1 */ +#define NTH_NLP_WITH_TPH 0 +#define NTH_NLP_WITHOUT_TPH 1 + uint32_t nth_nlp : 3; + uint32_t mgmt : 1; + uint32_t sl : 4; + uint32_t lb : 8; + uint32_t cc : 16; +}; + +typedef struct MsgExtendedHeader { + uint32_t plen : 12; + uint32_t rsvd : 4; + uint32_t rsp_status : 8; + union { + struct { + uint8_t type : 1; + uint8_t msg_code : 3; + uint8_t sub_msg_code : 4; + }; + uint8_t code; + }; +} MsgExtendedHeader; + +typedef struct MsgPktHeader { /* TODO, check byte order */ + /* DW0 */ + struct UbLinkHeader ulh; + /* DW1-DW2 */ + struct ClanNetworkHeader nth; + /* DW3 */ + uint32_t seid_h : 8; + uint32_t upi : 16; +#define CTPH_NLP_UPI_40BITS_UEID 2 + uint32_t ctph_nlp : 4; /* tp header */ + uint32_t pad : 2; +#define CTPH_OPCODE_NOT_CNP 0 + uint32_t tp_opcode : 2; + /* DW4 */ + uint32_t deid : 20; + uint32_t seid_l : 12; + /* DW5 */ + uint32_t src_tassn : 16; + uint32_t taver : 3; + uint32_t tk_vld : 1; + uint32_t udf : 4; +#define TAH_OPCODE_MSG 0x14 + uint32_t ta_opcode : 8; + /* DW6 */ + uint32_t sjetty : 20; + uint32_t sjt_type : 2; + uint32_t rsv0 : 3; + uint32_t retry : 1; + uint32_t se : 1; + uint32_t jetty_en : 1; + uint32_t rsv1 : 1; + uint32_t odr : 3; + /* DW7 */ + struct MsgExtendedHeader msgetah; + + /* DW8~DW11 */ + char payload[0]; /* payload */ +} MsgPktHeader; +#define MSG_PKT_HEADER_SIZE 32 #endif diff --git a/include/hw/ub/ub_config.h b/include/hw/ub/ub_config.h new file mode 100644 index 0000000000..05b2c19c57 --- /dev/null +++ b/include/hw/ub/ub_config.h @@ -0,0 +1,579 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that 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 UB_CONFIG_H +#define UB_CONFIG_H + +#include "hw/ub/hisi/ubc.h" +#include "hw/ub/ub_common.h" +#include "hw/ub/ub.h" +#include "qemu/units.h" + +enum UbCfgEmulatedSlice { + CFG0_BASIC = 0, + /* CFG0_CAP START */ + CAP1_RSV, + CAP2_SHP, + CAP3_ERR_RECORD, + CAP4_ERR_INFO, + CAP5_EMQ, + /* CFG0_CAP END */ + CFG1_BASIC, + /* CFG1_CAP START */ + CAP1_DECODER, + CAP2_JETTY, + CAP3_INT_TYPE1, + CAP4_INT_TYPE2, + CAP5_RSV, + CAP6_UB_MEM, + /* CFG1_CAP END */ + UB_CFG_GENERAL_SLICES_NUM, + + /* dont add new here */ + CFG0_PORT_BASIC, + CFG0_ROUTE_TABLE, + UB_CFG_EMULATED_SLICES_NUM, + /* dont add new here */ +}; + +/* In UB spec, route table slice is 1GB, in virtualization, + * route table is not used. To redece mem overhead, the route + * table also emulated with 1k slice, so add 1 extra */ +#define UB_CFG_SLICE_NUMS (UB_CFG_GENERAL_SLICES_NUM + UB_DEV_MAX_NUM_OF_PORT + 1) +#define UB_CFG_START_OFFSET_GRANU 4 +#define UB_CFG_SLICE_SIZE (1 * KiB) + +typedef struct UbCfgAddrMapEntry { + uint64_t start_addr; + uint64_t mapped_offset; +} UbCfgAddrMapEntry; + +int ub_cfg_addr_map_table_init(void); + +enum UbCfgSubMsgCode { + UB_CFG0_READ = 0, + UB_CFG0_WRITE = 1, + UB_CFG1_READ = 2, + UB_CFG1_WRITE = 3, + UB_CFG_MAX_SUB_MSG_CODE, +}; + +typedef struct CfgMsgPldReq { + /* DW0 */ + uint32_t rsvd0 : 4; + uint32_t byte_enable : 4; + uint32_t rsvd1 : 8; + uint32_t entity_idx : 16; + + /* DW1 */ + uint32_t req_addr; + + /* DW2 */ + uint32_t rsvd2; + /* DW3 */ + uint32_t write_data; +} CfgMsgPldReq; + +typedef struct CfgMsgPldRsp { + /* DW0 */ + uint32_t read_data; + /* DW1 */ + uint32_t rsvd1; + /* DW2 */ + uint32_t rsvd2; + /* DW3 */ + uint32_t rsvd3; +} CfgMsgPldRsp; + +typedef struct CfgMsgPld { + union { + CfgMsgPldReq req; + CfgMsgPldRsp rsp; + }; +} CfgMsgPld; +#define CFG_MSG_PLD_SIZE 16 +#define MSG_CFG_PKT_SIZE (MSG_PKT_HEADER_SIZE + CFG_MSG_PLD_SIZE) /* header 32bytes, pld 16bytes */ + +void handle_msg_cfg(void *opaque, HiMsgSqe *sqe, void *payload); +enum UbCfgBlockType { + UB_CFG0_BASIC_BLOCK_TYPE = 0, + UB_CFG_ROUTING_BLOCK_TYPE = 1, + UB_CFG_CAP_BLOCK_TYPE = 2, + UB_CFG_PORT_BLOCK_TYPE = 3, + UB_CFG_VD_BLOCK_TYPE = 4, + UB_CFG1_BASIC_BLOCK_TYPE = 5, + UB_CFG_BLOCK_NUMS +}; + +typedef struct CfgMsgPkt { + MsgPktHeader header; + CfgMsgPld pld; +} CfgMsgPkt; + +typedef struct __attribute__ ((__packed__)) ConfigNetAddrInfo { + uint32_t primary_cna : 24; /* 0x1A */ + uint32_t rsv : 8; + uint32_t rsv1; /* 0x1B */ + uint32_t rsv2; /* 0x1C */ + uint32_t rsv3; /* 0x1D */ + uint32_t rsv4; /* 0x1E */ +} ConfigNetAddrInfo; + +typedef struct SliceHeader { + uint32_t slice_version : 4; + uint32_t slice_used_size : 28; +} SliceHeader; + +typedef struct __attribute__ ((__packed__)) Cfg0SupportFeature { + union { + uint32_t rsv[4]; + struct { + uint8_t entity_available : 1; + uint8_t mtu_supported : 3; + uint8_t route_table_supported : 1; + uint8_t upi_supported : 1; + uint8_t broker_supported : 1; + uint8_t switch_supported : 1; + uint8_t rsv : 1; + uint8_t cc_supported : 1; + } bits; + }; +} Cfg0SupportFeature; + +typedef struct __attribute__ ((__packed__)) UbEid { + uint32_t dw0; + uint32_t dw1; + uint32_t dw2; + uint32_t dw3; +} UbEid; + +#define CAP_BITMAP_LEN 32 +#define RSV_LEN 4 +typedef struct __attribute__ ((__packed__)) UbCfg0Basic { + /* dw0 */ + SliceHeader header; // RO + /* dw1 */ + uint16_t total_num_of_port; // RO + uint16_t total_num_of_ue; // RO + /* dw2~dw9 */ + uint8_t cap_bitmap[CAP_BITMAP_LEN]; // RO + /* dw10~dw14 */ + Cfg0SupportFeature support_feature; // RO + /* dw14~dw17 */ + UbGuid guid; // RO + /* dw18~dw21 */ + UbEid eid; // RW + /* dw22~dw25 */ + UbEid fm_eid; + /* dw26~dw30 */ + ConfigNetAddrInfo net_addr_info; // RW + /* dw31~dw44 */ + uint32_t upi : 16; // RW + uint32_t rsv1 : 16; + uint32_t module_id : 16; // HwInit + uint32_t vendor_id : 16; + uint32_t dev_rst : 1; // RW + uint32_t rsv3 : 31; + uint32_t rsv4; + uint32_t mtu_cfg : 3; // RW + uint32_t rsv5 : 29; + uint32_t cc_en : 1; // RW + uint32_t rsv6 : 31; + uint32_t th_en : 1; // RW + uint32_t rsv7 : 31; + uint32_t fm_cna : 24; // RW + uint32_t rsv8 : 8; + uint64_t ueid_low; // RW + uint64_t ueid_high; // RW + uint32_t ucna : 24; // RW + uint32_t rsv9 : 8; + uint32_t rsv10; +} UbCfg0Basic; + +typedef struct __attribute__ ((__packed__)) UbSlotInfo { + /* dw2 */ + uint8_t pps : 1; + uint8_t wlps : 1; + uint8_t plps : 1; + uint8_t pdss : 1; + uint8_t pwcs : 1; + uint32_t rsv1 : 27; + /* dw3 */ + uint16_t start_port_idx; + uint16_t end_port_idx; + /* dw4~dw10 */ + uint8_t pp_ctrl : 1; + uint32_t rsv2 : 31; + uint8_t wl_ctrl : 2; + uint32_t rsv3 : 30; + uint8_t pl_ctrl : 2; + uint32_t rsv4 : 30; + uint8_t ms_ctrl : 1; + uint32_t rsv5 : 31; + uint8_t pd_ctrl : 1; + uint32_t rsv6 : 31; + uint8_t pds_ctrl : 1; + uint32_t rsv7 : 31; + uint8_t pw_ctrl : 1; + uint32_t rsv8 : 31; + /* dw11~dw13 */ + uint8_t pp_st : 1; + uint32_t rsv9 : 31; + uint8_t pd_st : 1; + uint32_t rsv10 : 31; + uint8_t pdsc_st : 1; + uint32_t rsv11 : 31; + /* dw14~dw17 */ + uint32_t rsv[2]; +} UbSlotInfo; + +typedef struct __attribute__ ((__packed__)) UbCfg0ShpCap { + /* dw0 */ + SliceHeader header; // RO + /* dw1 */ + uint16_t slot_num; // RO + uint16_t rsv1; + /* dw2 ~ */ + UbSlotInfo slot_info[0]; // RO +} UbCfg0ShpCap; + +typedef struct __attribute__ ((__packed__)) ErrorMsgQueCtrl { + uint64_t correctable_err_report_enable : 1; + uint64_t uncorrectable_nonfatal_err_report_enable : 1; + uint64_t uncorrectable_fatal_err_report_enable : 1; + uint64_t rsv_1 : 5; + uint64_t interrupt_generation_enable : 1 ; + uint64_t rsv_2 : 55; +} ErrorMsgQueCtrl; + +typedef struct __attribute__ ((__packed__)) UbCfg0EmqCap { + /* dw0 */ + uint64_t segment_header; + ErrorMsgQueCtrl error_msg_que_ctrlr; +} UbCfg0EmqCap; + +typedef struct __attribute__ ((__packed__)) Cfg1SupportFeature { + union { + uint32_t rsv[4]; + struct { + uint8_t rsv1 : 2; + uint8_t mgs : 1; + uint8_t rsv2 : 2; + uint8_t ubbas : 1; + uint8_t ers0s : 1; + uint8_t ers1s : 1; + uint8_t ers2s : 1; + uint8_t cdmas : 1; + uint8_t matt_juris : 1; + } bits; + }; +} Cfg1SupportFeature; + +typedef struct __attribute__ ((__packed__)) UbCfg1DecoderCap { + /* dw0 */ + SliceHeader header; +#define DECODER_CAP_EVENT_SIZE 5 +#define DECODER_CAP_CMD_SIZE 5 +#define DECODER_CAP_MMIO_SIZE 7 + /* dw1 */ + struct { + uint16_t rsv1 : 4; + uint16_t event_size_sup : 4; + uint16_t rsv2 : 4; + uint16_t cmd_size_sup : 4; + uint16_t mmio_size_sup : 3; + uint16_t rsv3 : 13; + } decoder; + /* dw2 */ + struct { + uint32_t decoder_en : 1; + uint32_t rsv : 31; + } decoder_ctrl; + /* dw3-4 */ + uint64_t dec_matt_ba; + /* dw5-6 */ + uint64_t dec_mmio_ba; + /* dw7 */ + uint32_t dev_usi_idx; + /* dw 8-0xf */ +#define DECODER_CAP_RESERVED1_BYTES 8 + uint32_t rsv1[DECODER_CAP_RESERVED1_BYTES]; + /* dw 0x10 */ + struct { + uint32_t cmdq_en : 1; + uint32_t rsv1 : 7; + uint32_t cmdq_size_use : 4; + uint32_t rsv2 : 20; + } decoder_cmdq_cfg; + /* dw 0x11 */ + struct { + uint32_t cmdq_wr_idx : 11; + uint32_t rsv1 : 5; + uint32_t cmdq_err_resp : 1; + uint32_t rsv2 : 15; + } decoder_cmdq_prod; + /* dw 0x12 */ + struct { + uint32_t cmdq_rd_idx : 11; + uint32_t rsv1 : 5; + uint32_t cmdq_err : 1; + uint32_t cmdq_err_res : 3; + uint32_t rsv2 : 12; + } decoder_cmdq_cons; + /* dw 0x13-0x14 */ + struct { + uint64_t rsv1 : 6; + uint64_t cmdq_ba : 42; + uint64_t rsv2 : 16; + } decoder_cmdq_ba; + /* dw 0x15-0x1f */ +#define DECODER_CAP_RESERVED2_BYTES 11 + uint32_t rsv2[DECODER_CAP_RESERVED2_BYTES]; + /* dw 0x20 */ + struct { + uint32_t evtq_en : 1; + uint32_t rsv1 : 7; + uint32_t evtq_size_use : 4; + uint32_t rsv2 : 20; + } decoder_evtq_cfg; + /* dw 0x21 */ + struct { + uint32_t evtq_wr_idx : 11; + uint32_t rsv : 20; + uint32_t evtq_ovrl_err : 1; + } decoder_evtq_prod; + /* dw 0x22 */ + struct { + uint32_t evtq_rd_idx : 11; + uint32_t rsv : 20; + uint32_t evtq_ovrl_err_resp : 1; + } decoder_evtq_cons; + /* dw 0x23 */ + struct { + uint64_t rsv1 : 6; + uint64_t evtq_ba : 42; + uint64_t rsv2 : 16; + } decoder_evtq_ba; +} UbCfg1DecoderCap; + +typedef struct __attribute__ ((__packed__)) UbCfg1IntType1Cap { + /* dw0 */ + SliceHeader header; + /* dw1 */ + uint32_t interrupt_enable : 1; + uint32_t rsv1 : 31; + /* dw2 */ + uint32_t support_int_num : 3; + uint32_t rsv2 : 29; + /* dw3 */ + uint32_t interrupt_enable_num : 3; + uint32_t rsv3 : 29; + /* dw4 */ + uint32_t interrupt_data; + /* dw5-dw6 */ + uint64_t interrupt_address; + /* dw7 */ + uint32_t interrupt_id; + /* dw8 */ + uint32_t interrupt_mask; + /* dw9 */ + uint32_t interrupt_pending; +} UbCfg1IntType1Cap; + +typedef struct __attribute__ ((__packed__)) UbCfg1IntType2Cap { + /* dw0 */ + SliceHeader header; + /* dw1 */ + uint16_t vec_table_num; + uint16_t add_table_num; + /* dw2 ~ dw8 */ + uint64_t vec_table_start_addr; + uint64_t add_table_start_addr; + uint64_t pend_table_start_addr; + uint32_t interrupt_id; + uint32_t interrupt_mask : 1; + uint32_t rsv1 : 31; + uint32_t interrupt_enable : 1; + uint32_t rsv2 : 31; +} UbCfg1IntType2Cap; + +typedef struct __attribute__ ((__packed__)) UbCfg1Basic { + /* dw0 */ + SliceHeader header; // RO + /* dw1~dw8 */ + uint8_t cap_bitmap[CAP_BITMAP_LEN]; // RO + /* dw9~dw12 */ + Cfg1SupportFeature support_feature; // RO + /* dw13~dw42 */ + uint32_t ers_space_size[UB_NUM_REGIONS]; + uint64_t ers_start_addr[UB_NUM_REGIONS]; + uint64_t ers_ubba[UB_NUM_REGIONS]; + uint32_t elr : 1; + uint32_t rsv1 : 31; + uint32_t elr_done : 1; + uint32_t rsv2 : 31; + uint32_t mig_ctrl : 8; + uint32_t rsv3 : 24; + uint32_t mig_status : 8; + uint32_t rsv4 : 24; + uint32_t ers_att : 3; + uint32_t rsv5 : 29; + uint32_t sys_pgs : 1; + uint32_t rsv6 : 31; + uint64_t eid_upi_tab; + uint32_t eid_upi_ten; + uint64_t rsv7; + uint64_t rsv8; + uint32_t class_code : 16; + uint32_t rsv9 : 16; + uint32_t tpid_num : 16; + uint32_t rsv10 : 16; + uint32_t ctp_tb_bypass : 1; + uint32_t rsv11 : 31; + uint32_t crystal_dma_en : 1; + uint32_t rsv12 : 31; + uint32_t dev_token_id : 20; + uint32_t rsv13 : 12; + uint32_t bus_access_en : 1; + uint32_t rsv14 : 31; + uint32_t dev_rs_access_en : 1; + uint32_t rsv15 : 31; +} UbCfg1Basic; + +typedef struct __attribute__ ((__packed__)) ConfigPortInfo { + uint16_t port_idx : 16; + uint8_t port_type : 1; + uint8_t enum_boundary : 1; + uint16_t rsv : 14; +} ConfigPortInfo; + +typedef struct __attribute__ ((__packed__)) ConfigNeighborPortInfo { + uint16_t neighbor_port_idx : 16; + uint16_t rsv : 16; + UbGuid neighbot_port_guid; +} ConfigNeighborPortInfo; + +#define PORT_CAP_BITMAP_LEN 32 +typedef struct __attribute__ ((__packed__)) ConfigPortBasic { + SliceHeader header; + uint8_t port_cap_bitmap[PORT_CAP_BITMAP_LEN]; + ConfigPortInfo port_info; + ConfigNeighborPortInfo neighbor_port_info; + uint32_t port_cna : 24; + uint32_t rsv1 : 8; + uint8_t port_reset : 1; + uint32_t rsv2 : 31; +} ConfigPortBasic; + +typedef struct __attribute__ ((__packed__)) UbRouteTable { + SliceHeader header; + uint32_t entry_num : 16; + uint32_t ers : 1; + uint32_t rsv1 : 15; + uint32_t er_en : 1; + uint32_t rsv2 : 31; + uint32_t entry[0]; +} UbRouteTable; + +#define SUPPORTED 1 +#define NOT_SUPPORTED 0 + +#define UBFM 1 +#define UB_DRIVE 0 + +/* slice header default value, unit (4 bytes) */ +#define UB_SLICE_VERSION 0x0 +#define UB_CFG0_BASIC_SLICE_USED_SIZE 0x24 +#define UB_CFG1_BASIC_SLICE_USED_SIZE 0x20 +#define UB_PORT_BASIC_SLICE_USED_SIZE 0x11 + +/* ub dev cap */ +#define BITS_PER_CAP_BIT_MAP 128 +#define CFG0_RSV_INDEX 1 +#define CFG0_CAP2_SHP_INDEX 2 +#define CFG1_DECODER_CAP_INDEX 1 +#define CFG1_JETTY_CAP_INDEX 2 +#define CFG1_INT_CAP_INDEX 3 + +/* ub dev config space CFG0 addr offset, unit (bytes) */ +#define UB_SLICE_SZ (0x00000100 * DWORD_SIZE) +#define UB_CFG0_BASIC_START 0x00000000 +#define UB_CFG0_BASIC_CAP_BITMAP (UB_CFG0_BASIC_START + 0x02 * DWORD_SIZE) +#define UB_CFG0_BASIC_GUID_START (UB_CFG0_BASIC_START + 0x0E * DWORD_SIZE) +#define UB_CFG0_BASIC_NA_INFO_START (UB_CFG0_BASIC_START + 0x1A * DWORD_SIZE) +#define UB_CFG0_DEV_UEID_OFFSET (UB_CFG0_BASIC_START + 0x27 * DWORD_SIZE) +#define UB_CFG0_CAP1_RSV_START (UB_CFG0_BASIC_START + UB_SLICE_SZ) +#define UB_CFG0_CAP2_SHP_START (UB_CFG0_CAP1_RSV_START + UB_SLICE_SZ) +#define UB_CFG0_CAP3_ERR_RECORD_START (UB_CFG0_CAP2_SHP_START + UB_SLICE_SZ) +#define UB_CFG0_CAP4_ERR_INFO_START (UB_CFG0_CAP3_ERR_RECORD_START + UB_SLICE_SZ) +#define UB_CFG0_EMQ_CAP_START (UB_CFG0_CAP4_ERR_INFO_START + UB_SLICE_SZ) +/* ub dev config space CFG1 addr offset, unit (bytes) */ +#define UB_CFG1_BASIC_START (0x00010000 * DWORD_SIZE) +#define UB_CFG1_CAP1_DECODER (UB_CFG1_BASIC_START + UB_SLICE_SZ) +#define UB_CFG1_CAP2_JETTY (UB_CFG1_CAP1_DECODER + UB_SLICE_SZ) +#define UB_CFG1_CAP3_INT_TYPE1 (UB_CFG1_CAP2_JETTY + UB_SLICE_SZ) +#define UB_CFG1_CAP4_INT_TYPE2 (UB_CFG1_CAP3_INT_TYPE1 + UB_SLICE_SZ) +#define UB_CFG1_CAP5_RSV (UB_CFG1_CAP4_INT_TYPE2 + UB_SLICE_SZ) +#define UB_CFG1_CAP6_UB_MEM (UB_CFG1_CAP5_RSV + UB_SLICE_SZ) +/* ub dev config space PORT addr offset, unit (bytes) */ +#define UB_PORT_SLICE_START (0x00020000 * DWORD_SIZE) +#define UB_PORT_SZ (0x00010000 * DWORD_SIZE) +/* ub dev config space ROUT TABLE addr offset, unit (bytes) */ +#define UB_ROUTE_TABLE_START (0xF0000000ULL * DWORD_SIZE) +#define UB_ROUTE_TABLE_SIZE (0x10000000 * DWORD_SIZE) +/* ub dev config space CFG1 system page granule size define */ +#define UB_CFG1_BASIC_SYSTEM_GRANULE_SIZE_4K (4 * 1024) +#define UB_CFG1_BASIC_SYSTEM_GRANULE_SIZE_64K (64 * 1024) +/* ub dev config space CFG1 dev_toke id offset 0xB4 */ +#define UB_CFG1_DEV_TOKEN_ID_OFFSET (UB_CFG1_BASIC_START + 0x2D * DWORD_SIZE) +#define UB_TOKEN_ID_MASK 0xfffff +/* ub dev config space CFG1 dev_rs_access_en offset 0xBC */ +#define UB_CFG1_DEV_RS_ACCESS_EN_OFFSET (UB_CFG1_BASIC_START + 0x2F * DWORD_SIZE) +#define UB_DEV_RS_ACCESS_EN_MASK 0x1 +/* ub dev config space CFG1 bus_access_en offset 0xB8 */ +#define UB_CFG1_BUS_ACCESS_EN_OFFSET (UB_CFG1_BASIC_START + 0x2E * DWORD_SIZE) +#define UB_BUS_ACCESS_EN_MASK 0x1 +/* ub dev config space INT TYPE2 CAP addr offset, unit (bytes) */ +#define UB_CFG1_CAP4_INT_TYPE2_NUMOF_INT_VEC_OFFSET (UB_CFG1_CAP4_INT_TYPE2 + 1 * DWORD_SIZE) +#define UB_CFG1_CAP4_INT_TYPE2_NUMOF_INT_ADDR_OFFSET (UB_CFG1_CAP4_INT_TYPE2 + 1 * DWORD_SIZE + WORD_SIZE) +#define UB_CFG1_CAP4_INT_TYPE2_INT_VEC_TAB_OFFSET (UB_CFG1_CAP4_INT_TYPE2 + 2 * DWORD_SIZE) +#define UB_CFG1_CAP4_INT_TYPE2_INT_ADDR_TAB_OFFSET (UB_CFG1_CAP4_INT_TYPE2 + 4 * DWORD_SIZE) +#define UB_CFG1_CAP4_INT_TYPE2_INT_PENDING_TAB_OFFSET (UB_CFG1_CAP4_INT_TYPE2 + 6 * DWORD_SIZE) +#define UB_CFG1_CAP4_INT_TYPE2_INT_ID_OFFSET (UB_CFG1_CAP4_INT_TYPE2 + 8 * DWORD_SIZE) +#define UB_CFG1_CAP4_INT_TYPE2_INT_MASK_OFFSET (UB_CFG1_CAP4_INT_TYPE2 + 9 * DWORD_SIZE) +/* ub dev usi vec&addr&pend table entrys size uint (bytes) */ +#define USI_VEC_TABLE_ENTRY_SIZE 0x8 +#define USI_ADDR_TABLE_ENTRY_SIZE 0x20 +#define USI_PEND_TABLE_ENTRY_SIZE 0x4 +#define USI_PEND_TABLE_ENTRY_BIT_NUM 32 +/* ub dev usi addr table valid bit offset */ +#define USI_ADDR_TABLE_VALID_BIT_OFFSET 10 +#define USI_ADDR_TABLE_VALID_BIT_MASK 0x10 +/* usi config space */ +#define UB_CFG1_CAP4_INT_TYPE2_MASK_OFFSET (UB_CFG1_CAP4_INT_TYPE2 + 0x24) +#define UB_CFG1_CAP4_INT_TYPE2_MASKBIT 0x1 +#define UB_CFG1_CAP4_INT_TYPE2_ENABLE_OFFSET (UB_CFG1_CAP4_INT_TYPE2 + 0x28) +#define UB_CFG1_CAP4_INT_TYPE2_ENABLEBIT 0x1 +/* usi vec table source */ +#define USI_VEC_TABLE_MASK_OFFSET 0x6 +#define USI_VEC_TABLE_MASKBIT 0x1 +#define USI_VEC_TABLE_ADDR_INDEX_OFFSET 0x4 + +uint32_t ub_emulated_config_size(void); +uint64_t ub_cfg_offset_to_emulated_offset(uint64_t offset, bool check_success); + +#endif \ No newline at end of file -- Gitee From 4fe54a9d146bfb4cf2085ffac980accdbb8328a4 Mon Sep 17 00:00:00 2001 From: caojinhuahw Date: Tue, 11 Nov 2025 17:18:49 +0800 Subject: [PATCH 2/5] ub: do more realize for ub device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、realize default config space read/write 2、support ub register 3、init default wmask for ub device Signed-off-by: caojinhuahw --- hw/ub/ub.c | 273 ++++++++++++++++++++++++++++++++++++++++++++- include/hw/ub/ub.h | 6 + 2 files changed, 277 insertions(+), 2 deletions(-) diff --git a/hw/ub/ub.c b/hw/ub/ub.c index 974df5d0f7..b6503c62e2 100644 --- a/hw/ub/ub.c +++ b/hw/ub/ub.c @@ -24,6 +24,7 @@ #include "hw/qdev-properties-system.h" #include "hw/ub/ub_common.h" #include "hw/ub/ub.h" +#include "hw/ub/ub_config.h" #include "hw/ub/ub_bus.h" #include "hw/ub/ub_ubc.h" #include "qemu/log.h" @@ -117,13 +118,250 @@ static const TypeInfo ub_bus_info = { .class_init = ub_bus_class_init, }; +static void ub_config_alloc(UBDevice *ub_dev) +{ + size_t config_size = ub_emulated_config_size(); + ub_dev->config = g_malloc0(config_size); + ub_dev->wmask = g_malloc0(config_size); + ub_dev->w1cmask = g_malloc0(config_size); +} + +static void ub_port_info_alloc(UBDevice *ub_dev) +{ + ub_dev->port.neighbors = g_malloc0(sizeof(NeighborInfo) * + ub_dev->port.port_num); + ub_dev->port.port_info_exist = false; +} + +static void ub_config_free(UBDevice *ub_dev) +{ + g_free(ub_dev->config); + g_free(ub_dev->wmask); + g_free(ub_dev->w1cmask); +} + +static void ub_port_info_free(UBDevice *ub_dev) +{ + if (ub_dev->port.neighbors_cmd) { + g_free(ub_dev->port.neighbors_cmd); + } + if (ub_dev->port.neighbors) { + g_free(ub_dev->port.neighbors); + } +} + +static void ub_config_set_guid(UBDevice *ub_dev) +{ + uint64_t offset = ub_cfg_offset_to_emulated_offset(UB_CFG0_BASIC_GUID_START, true); + uint8_t *ub_config_guid_ptr = ub_dev->config + offset; + char guid_str[UB_DEV_GUID_STRING_LENGTH + 1] = {0}; + + ub_device_get_str_from_guid(&ub_dev->guid, guid_str, + UB_DEV_GUID_STRING_LENGTH + 1); + memcpy(ub_config_guid_ptr, &ub_dev->guid, sizeof(UbGuid)); +} + +static void ub_init_wmask(UBDevice *ub_dev) +{ + UbCfg0Basic *cfg0_basic_wmask; + UbCfg0EmqCap *cfg0_emq_cap_wmask; + UbCfg1Basic *cfg1_basic_wmask; + UbCfg1IntType1Cap *cfg1_int_type1_wmask; + UbCfg1IntType2Cap *cfg1_int_type2_wmask; + UbRouteTable *route_table_wmask; + uint64_t emulated_offset; + + /* cfg0 basic */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG0_BASIC_START, true); + cfg0_basic_wmask = (UbCfg0Basic *)(ub_dev->wmask + emulated_offset); + memset(cfg0_basic_wmask, 0, sizeof(UbCfg0Basic)); + memset(&cfg0_basic_wmask->eid, 0xff, sizeof(UbEid)); + memset(&cfg0_basic_wmask->fm_eid, 0xff, sizeof(UbEid)); + cfg0_basic_wmask->net_addr_info.primary_cna = 0xffffff; + cfg0_basic_wmask->upi = ~0; + cfg0_basic_wmask->dev_rst = ~0; + cfg0_basic_wmask->mtu_cfg = ~0; + cfg0_basic_wmask->cc_en = ~0; + cfg0_basic_wmask->th_en = ~0; + cfg0_basic_wmask->fm_cna = ~0; + cfg0_basic_wmask->ueid_low = ~0UL; + cfg0_basic_wmask->ueid_high = ~0UL; + cfg0_basic_wmask->ucna = ~0; + + /* cfg0 emq cap */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG0_EMQ_CAP_START, true); + cfg0_emq_cap_wmask = (UbCfg0EmqCap *)(ub_dev->wmask + emulated_offset); + memset(cfg0_emq_cap_wmask, 0, sizeof(UbCfg0EmqCap)); + cfg0_emq_cap_wmask->error_msg_que_ctrlr.correctable_err_report_enable = ~0; + cfg0_emq_cap_wmask->error_msg_que_ctrlr.uncorrectable_nonfatal_err_report_enable = ~0; + cfg0_emq_cap_wmask->error_msg_que_ctrlr.uncorrectable_fatal_err_report_enable = ~0; + cfg0_emq_cap_wmask->error_msg_que_ctrlr.interrupt_generation_enable = ~0; + + /* cfg1 basic */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG1_BASIC_START, true); + cfg1_basic_wmask = (UbCfg1Basic *)(ub_dev->wmask + emulated_offset); + memset(cfg1_basic_wmask, 0, sizeof(UbCfg1Basic)); + cfg1_basic_wmask->elr = ~0; + cfg1_basic_wmask->mig_ctrl = ~0; + cfg1_basic_wmask->sys_pgs = ~0; + cfg1_basic_wmask->eid_upi_tab = ~0UL; + cfg1_basic_wmask->ctp_tb_bypass = ~0; + cfg1_basic_wmask->crystal_dma_en = ~0; + cfg1_basic_wmask->dev_token_id = ~0; + cfg1_basic_wmask->bus_access_en = ~0; + cfg1_basic_wmask->dev_rs_access_en = ~0; + + /* cfg1 int type1 cap */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG1_CAP3_INT_TYPE1, true); + cfg1_int_type1_wmask = (UbCfg1IntType1Cap *)(ub_dev->wmask + emulated_offset); + memset(cfg1_int_type1_wmask, 0, sizeof(UbCfg1IntType1Cap)); + cfg1_int_type1_wmask->interrupt_enable = ~0; + cfg1_int_type1_wmask->interrupt_enable_num = ~0; + cfg1_int_type1_wmask->interrupt_data = ~0U; + cfg1_int_type1_wmask->interrupt_address = ~0UL; + cfg1_int_type1_wmask->interrupt_id = ~0U; + cfg1_int_type1_wmask->interrupt_mask = ~0U; + + /* cfg1 int type2 cap */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG1_CAP4_INT_TYPE2, true); + cfg1_int_type2_wmask = (UbCfg1IntType2Cap *)(ub_dev->wmask + emulated_offset); + memset(cfg1_int_type2_wmask, 0, sizeof(UbCfg1IntType2Cap)); + cfg1_int_type2_wmask->interrupt_id = ~0U; + cfg1_int_type2_wmask->interrupt_mask = ~0; + cfg1_int_type2_wmask->interrupt_enable = ~0; + + /* port basic */ + // set after port_info is initialized + + /* port cap */ + // not support yet + + /* route table */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_ROUTE_TABLE_START, true); + route_table_wmask = (UbRouteTable *)(ub_dev->wmask + emulated_offset); + memset(route_table_wmask, 0xff, UB_CFG_SLICE_SIZE); + route_table_wmask->entry_num = 0; + route_table_wmask->ers = 0; + + /* route table entry */ + // not support yet +} + +static void ub_init_w1cmask(UBDevice *ub_dev) +{ + UbCfg0Basic *cfg0_basic_w1cmask; + UbCfg1Basic *cfg1_basic_w1cmask; + uint64_t emulated_offset; + + /* cfg0 basic */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG0_BASIC_START, true); + cfg0_basic_w1cmask = (UbCfg0Basic *)(ub_dev->w1cmask + emulated_offset); + memset(cfg0_basic_w1cmask, 0, sizeof(UbCfg0Basic)); + cfg0_basic_w1cmask->dev_rst = ~0; + + /* cfg1 basic */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG1_BASIC_START, true); + cfg1_basic_w1cmask = (UbCfg1Basic *)(ub_dev->w1cmask + emulated_offset); + memset(cfg1_basic_w1cmask, 0, sizeof(UbCfg1Basic)); + cfg1_basic_w1cmask->elr = ~0; + + /* port cap */ + // not support yet +} + +static void ub_config_space_init(UBDevice *ub_dev) +{ + ub_config_set_guid(ub_dev); + ub_init_wmask(ub_dev); + ub_init_w1cmask(ub_dev); +} + +void ub_default_read_config(UBDevice *dev, uint64_t offset, + uint32_t *val, uint32_t dw_mask) +{ + uint32_t read_data; + uint64_t emulated_offset = ub_cfg_offset_to_emulated_offset(offset, false); + + if (emulated_offset == UINT64_MAX) { + *val = 0; + qemu_log("ub default read config out of emulated range, offset " + "is 0x%lx\n", offset); + return; + } + + memcpy(&read_data, dev->config + emulated_offset, DWORD_SIZE); + *val = read_data & dw_mask; +} + +void ub_default_write_config(UBDevice *dev, uint64_t offset, + uint32_t *val, uint32_t dw_mask) +{ + uint32_t write_data = *val; + uint32_t dw_wmask, dw_w1cmask; + uint64_t emulated_offset; + uint32_t *dst_data = NULL; + + emulated_offset = ub_cfg_offset_to_emulated_offset(offset, false); + if (emulated_offset == UINT64_MAX) { + qemu_log("ub default write config out of emulated range, offset " + "is 0x%lx\n", offset); + return; + } + + dst_data = (uint32_t *)(dev->config + emulated_offset); + dw_wmask = *(uint32_t *)(dev->wmask + emulated_offset) & dw_mask; + dw_w1cmask = *(uint32_t *)(dev->w1cmask + emulated_offset) & dw_mask; + *dst_data = (*dst_data & ~dw_wmask) | (write_data & dw_wmask); + *dst_data &= ~(write_data & dw_w1cmask); +} + static UBDevice *do_ub_register_device(UBDevice *ub_dev, const char *name, Error **errp) { - return NULL; + UBBus *bus = ub_get_bus(ub_dev); + UBDeviceClass *uc = UB_DEVICE_GET_CLASS(ub_dev); + UBConfigReadFunc *config_read = uc->config_read; + UBConfigWriteFunc *config_write = uc->config_write; + + if (ub_dev->eid < UB_SUPPORT_MIN_EID || ub_dev->eid > UB_SUPPORT_MAX_EID) { + qemu_log("expect eid val is [0x%x, 0x%x], but current eid val is 0x%x\n", + UB_SUPPORT_MIN_EID, UB_SUPPORT_MAX_EID, ub_dev->eid); + error_setg(errp, "expect eid val is [0x%x, 0x%x], but current eid val is 0x%x\n", + UB_SUPPORT_MIN_EID, UB_SUPPORT_MAX_EID, ub_dev->eid); + return NULL; + } + if (ub_find_device_by_guid(&ub_dev->guid)) { + qemu_log("%s guid already exists.\n", ub_dev->qdev.id); + error_setg(errp, "%s guid already exists.\n", ub_dev->qdev.id); + return NULL; + } + if (ub_find_device_by_eid(bus, ub_dev->eid)) { + qemu_log("%s eid already exists.\n", ub_dev->qdev.id); + error_setg(errp, "%s eid already exists.\n", ub_dev->qdev.id); + return NULL; + } + pstrcpy(ub_dev->name, sizeof(ub_dev->name), name); + QLIST_INSERT_HEAD(&bus->devices, ub_dev, node); + + /* allocate memory for ub device config space */ + ub_config_alloc(ub_dev); + ub_config_space_init(ub_dev); + /* allocate memory for ub device port info */ + ub_port_info_alloc(ub_dev); + + if (!config_read) + config_read = ub_default_read_config; + if (!config_write) + config_write = ub_default_write_config; + ub_dev->config_read = config_read; + ub_dev->config_write = config_write; + + return ub_dev; } static void do_ub_unregister_device(UBDevice *ub_dev) { + ub_config_free(ub_dev); + ub_port_info_free(ub_dev); } static void ub_qdev_realize(DeviceState *qdev, Error **errp) @@ -168,6 +406,19 @@ static Property ub_props[] = { DEFINE_PROP_END_OF_LIST() }; +UBDevice *ub_find_device_by_eid(UBBus *bus, uint32_t eid) +{ + UBDevice *dev; + + QLIST_FOREACH(dev, &bus->devices, node) { + if (dev->eid == eid) { + return dev; + } + } + + return NULL; +} + static void ub_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); @@ -262,4 +513,22 @@ BusControllerState *container_of_ubbus(UBBus *bus) } return NULL; -} \ No newline at end of file +} + +UBDevice *ub_find_device_by_guid(UbGuid *guid) +{ + BusControllerState *ubc = NULL; + UBDevice *dev = NULL; + + QLIST_FOREACH(ubc, &ub_bus_controllers, node) { + if (!ubc->bus->qbus.num_children) { + continue; + } + QLIST_FOREACH(dev, &ubc->bus->devices, node) { + if (dev && !memcmp(guid, &dev->guid, sizeof(UbGuid))) { + return dev; + } + } + } + return NULL; +} diff --git a/include/hw/ub/ub.h b/include/hw/ub/ub.h index 5cb6b2b207..2f408d874d 100644 --- a/include/hw/ub/ub.h +++ b/include/hw/ub/ub.h @@ -221,4 +221,10 @@ static inline uint64_t ub_get_quad(const uint8_t *config) return ldq_le_p(config); } +void ub_default_read_config(UBDevice *dev, uint64_t offset, + uint32_t *val, uint32_t dw_mask); +void ub_default_write_config(UBDevice *dev, uint64_t offset, + uint32_t *val, uint32_t dw_mask); +UBDevice *ub_find_device_by_guid(UbGuid *guid); + #endif -- Gitee From 9b685111a67661e5bf5fb2866d7d8b376cd072ea Mon Sep 17 00:00:00 2001 From: caojinhuahw Date: Tue, 11 Nov 2025 17:36:55 +0800 Subject: [PATCH 3/5] ub port: setup ub port info config ub device port info after machine create done Signed-off-by: caojinhuahw --- hw/arm/virt.c | 6 +- hw/ub/ub.c | 276 ++++++++++++++++++++++++++++++++++++++++ include/hw/arm/virt.h | 1 - include/hw/ub/ub.h | 4 +- include/qemu/typedefs.h | 1 + 5 files changed, 285 insertions(+), 3 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 470a320bc6..de914a9136 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2070,7 +2070,11 @@ void virt_machine_done(Notifier *notifier, void *data) } fw_cfg_add_extra_pci_roots(vms->bus, vms->fw_cfg); - +#ifdef CONFIG_UB + if (ub_dev_finally_setup(vms, &error_fatal) < 0) { + exit(1); + } +#endif // CONFIG_UB virt_acpi_setup(vms); virt_build_smbios(vms); } diff --git a/hw/ub/ub.c b/hw/ub/ub.c index b6503c62e2..2b797dcf60 100644 --- a/hw/ub/ub.c +++ b/hw/ub/ub.c @@ -27,6 +27,7 @@ #include "hw/ub/ub_config.h" #include "hw/ub/ub_bus.h" #include "hw/ub/ub_ubc.h" +#include "hw/ub/ub_acpi.h" #include "qemu/log.h" #include "qapi/error.h" #include "hw/ub/ub_bus.h" @@ -515,6 +516,24 @@ BusControllerState *container_of_ubbus(UBBus *bus) return NULL; } +UBDevice *ub_find_device_by_id(const char *id) +{ + BusControllerState *ubc = NULL; + UBDevice *dev = NULL; + + QLIST_FOREACH(ubc, &ub_bus_controllers, node) { + if (!ubc->bus->qbus.num_children) { + continue; + } + QLIST_FOREACH(dev, &ubc->bus->devices, node) { + if (dev && !strcmp(id, dev->qdev.id)) { + return dev; + } + } + } + return NULL; +} + UBDevice *ub_find_device_by_guid(UbGuid *guid) { BusControllerState *ubc = NULL; @@ -532,3 +551,260 @@ UBDevice *ub_find_device_by_guid(UbGuid *guid) } return NULL; } + +// #pragma GCC push_options +// #pragma GCC optimize ("O0") +static void ub_config_set_port_basic(NeighborInfo *info, UBDevice *dev) +{ + uint32_t port_idx = info->local_port_idx; + uint64_t emulated_offset; + ConfigPortBasic *port_basic = NULL; + ConfigPortBasic *port_basic_wmask = NULL; + ConfigPortBasic *port_basic_w1cmask = NULL; + + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_PORT_SLICE_START + port_idx * UB_PORT_SZ, true); + port_basic = (ConfigPortBasic *)(dev->config + emulated_offset); + port_basic_wmask = (ConfigPortBasic *)(dev->wmask + emulated_offset); + port_basic_w1cmask = (ConfigPortBasic *)(dev->w1cmask + emulated_offset); + memset(port_basic, 0, sizeof(ConfigPortBasic)); + memset(port_basic_wmask, 0, sizeof(ConfigPortBasic)); + memset(port_basic_w1cmask, 0, sizeof(ConfigPortBasic)); + /* slice header */ + port_basic->header.slice_version = UB_SLICE_VERSION; + port_basic->header.slice_used_size = UB_PORT_BASIC_SLICE_USED_SIZE; + /* port info */ + port_basic->port_info.port_type = 0; // physical port + port_basic->port_info.port_idx = port_idx & UINT16_MASK; + /* neighbor port info */ + port_basic->neighbor_port_info.neighbor_port_idx = info->neighbor_port_idx & UINT16_MASK; + port_basic->neighbor_port_info.neighbot_port_guid = info->neighbor_dev->guid; + port_basic->port_reset = 0; + + /* set wmask */ + port_basic_wmask->port_cna = ~0; + port_basic_wmask->port_reset = ~0; +} +// #pragma GCC pop_options + +static int ub_dev_set_neighbor_dev_neighbor_info(uint32_t local_port_idx, + uint32_t neighbor_port_idx, UBDevice *local_dev, + UBDevice *neighbor_dev, Error **errp) +{ + UbPortInfo *neighbor_port = &neighbor_dev->port; + + if (neighbor_port->port_num <= neighbor_port_idx) { + qemu_log("invalid neighbor port idx %u %u\n", + neighbor_port->port_num, neighbor_port_idx); + + error_setg(errp, "invalid neighbor port idx %u %u\n", + neighbor_port->port_num, neighbor_port_idx); + return -1; + } + + if (neighbor_port->neighbors[neighbor_port_idx].neighbor_dev) { + if (neighbor_port->neighbors[neighbor_port_idx].neighbor_dev != local_dev || + neighbor_port->neighbors[neighbor_port_idx].local_port_idx != neighbor_port_idx || + neighbor_port->neighbors[neighbor_port_idx].neighbor_port_idx != local_port_idx) { + qemu_log("The neighbor information of the two devices does not match " + "each other. \nPlease check your command line parameter port info:\n" + "%s set (%s:%u = %s:%u) BUT neighbor %s already set (%s:%u = %s:%u)\n", + local_dev->qdev.id, local_dev->qdev.id, local_port_idx, + neighbor_dev->qdev.id, neighbor_port_idx, + neighbor_dev->qdev.id, neighbor_dev->qdev.id, neighbor_port_idx, + neighbor_port->neighbors[neighbor_port_idx].neighbor_dev->qdev.id, + neighbor_port->neighbors[neighbor_port_idx].neighbor_port_idx); + + error_setg(errp, "The neighbor information of the two devices does not match " + "each other. \nPlease check your command line parameter port info:\n" + "%s set (%s:%u = %s:%u) BUT neighbor %s already set (%s:%u = %s:%u)\n", + local_dev->qdev.id, local_dev->qdev.id, local_port_idx, + neighbor_dev->qdev.id, neighbor_port_idx, + neighbor_dev->qdev.id, neighbor_dev->qdev.id, neighbor_port_idx, + neighbor_port->neighbors[neighbor_port_idx].neighbor_dev->qdev.id, + neighbor_port->neighbors[neighbor_port_idx].neighbor_port_idx); + return -1; + } + } + neighbor_port->neighbors[neighbor_port_idx].local_port_idx = neighbor_port_idx; + neighbor_port->neighbors[neighbor_port_idx].neighbor_port_idx = local_port_idx; + neighbor_port->neighbors[neighbor_port_idx].neighbor_dev = local_dev; + neighbor_port->port_info_exist = true; + ub_config_set_port_basic(&neighbor_port->neighbors[neighbor_port_idx], neighbor_dev); + return 0; +} + +static int ub_dev_set_neighbor_info(UBDevice *dev, Error **errp) +{ + char *neighbor_info_str; + char neighbor_id[UB_DEV_ID_LEN] = {0}; + uint32_t local_port_idx; + uint32_t neighbor_port_idx; + UBDevice *neighbor_dev; + + neighbor_info_str = strtok(dev->port.neighbors_cmd, "+"); + while (neighbor_info_str != NULL) { + int ret = sscanf(neighbor_info_str, "%u:%[^:]:%u", + &local_port_idx, neighbor_id, &neighbor_port_idx); + neighbor_info_str = strtok(NULL, "+"); + if (ret < 3) { + qemu_log("port info format is incorrect %s\n", neighbor_info_str); + error_setg(errp, "port info format is incorrect %s\n", neighbor_info_str); + g_free(dev->port.neighbors_cmd); + dev->port.neighbors_cmd = NULL; + return -1; + } + if (local_port_idx >= dev->port.port_num) { + qemu_log("%s local port info is illegal, port idx:%u port num %u\n", + dev->qdev.id, local_port_idx, dev->port.port_num); + error_setg(errp, "%s local port info is illegal, port idx:%u port num %u\n", + dev->qdev.id, local_port_idx, dev->port.port_num); + g_free(dev->port.neighbors_cmd); + dev->port.neighbors_cmd = NULL; + return -1; + } + + neighbor_dev = ub_find_device_by_id(neighbor_id); + if (neighbor_dev == NULL) { + qemu_log("%s:%u neighbor_dev not exist %s\n", + dev->qdev.id, local_port_idx, neighbor_id); + error_setg(errp, "%s:%u neighbor_dev not exist %s\n", + dev->qdev.id, local_port_idx, neighbor_id); + g_free(dev->port.neighbors_cmd); + dev->port.neighbors_cmd = NULL; + return -1; + } + if (neighbor_dev == dev) { + qemu_log("%s can not connect to itself\n", dev->qdev.id); + error_setg(errp, "%s can not connect to itself\n", dev->qdev.id); + g_free(dev->port.neighbors_cmd); + dev->port.neighbors_cmd = NULL; + return -1; + } + if (neighbor_port_idx >= neighbor_dev->port.port_num) { + qemu_log("%s neighbor port info is illegal, port idx:%u port num %u\n", + dev->qdev.id, neighbor_port_idx, neighbor_dev->port.port_num); + error_setg(errp, "%s neighbor port info is illegal, port idx:%u port num %u\n", + dev->qdev.id, neighbor_port_idx, neighbor_dev->port.port_num); + g_free(dev->port.neighbors_cmd); + dev->port.neighbors_cmd = NULL; + return -1; + } + /* ub device can only connect with ub controller or ub switch */ + if ((dev->dev_type & UB_TYPE_DEVICE) && + !(neighbor_dev->dev_type & (UB_TYPE_SWITCH | UB_TYPE_ISWITCH | UB_TYPE_IBUS_CONTROLLER))) { + qemu_log("%s can not connect with %s, ub device can only connect with " + "ub controller or ub switch\n", dev->qdev.id, neighbor_dev->qdev.id); + error_setg(errp,"%s can not connect with %s ub device can only connect with " + "ub controller or ub switch\n", dev->qdev.id, neighbor_dev->qdev.id); + g_free(dev->port.neighbors_cmd); + dev->port.neighbors_cmd = NULL; + return -1; + } + /* Check whether the neighbor information of the two ends matches. */ + if (dev->port.neighbors[local_port_idx].neighbor_dev) { + if (dev->port.neighbors[local_port_idx].neighbor_dev != neighbor_dev || + dev->port.neighbors[local_port_idx].local_port_idx != local_port_idx || + dev->port.neighbors[local_port_idx].neighbor_port_idx != neighbor_port_idx) { + qemu_log("The neighbor information of the two devices does not match " + "each other. \nPlease check your command line parameter port info:\n" + "%s set (%s:%u = %s:%u) BUT %s set (%s:%u = %s:%u)\n", + dev->qdev.id, dev->qdev.id, local_port_idx, + neighbor_dev->qdev.id, neighbor_port_idx, + dev->port.neighbors[local_port_idx].neighbor_dev->qdev.id, + dev->port.neighbors[local_port_idx].neighbor_dev->qdev.id, + dev->port.neighbors[local_port_idx].neighbor_port_idx, + dev->qdev.id, + dev->port.neighbors[local_port_idx].local_port_idx); + + error_setg(errp, "The neighbor information of the two devices does not match " + "each other. \nPlease check your command line parameter port info:\n" + "%s set (%s:%u = %s:%u) BUT %s set (%s:%u = %s:%u)\n", + dev->qdev.id, dev->qdev.id, local_port_idx, + neighbor_dev->qdev.id, neighbor_port_idx, + dev->port.neighbors[local_port_idx].neighbor_dev->qdev.id, + dev->port.neighbors[local_port_idx].neighbor_dev->qdev.id, + dev->port.neighbors[local_port_idx].neighbor_port_idx, + dev->qdev.id, + dev->port.neighbors[local_port_idx].local_port_idx); + + g_free(dev->port.neighbors_cmd); + dev->port.neighbors_cmd = NULL; + return -1; + } + } + dev->port.neighbors[local_port_idx].local_port_idx = local_port_idx; + dev->port.neighbors[local_port_idx].neighbor_port_idx = neighbor_port_idx; + dev->port.neighbors[local_port_idx].neighbor_dev = neighbor_dev; + dev->port.port_info_exist = true; + /* set remote neighbor_dev */ + if (ub_dev_set_neighbor_dev_neighbor_info(local_port_idx, neighbor_port_idx, dev, + neighbor_dev, errp) < 0) { + g_free(dev->port.neighbors_cmd); + dev->port.neighbors_cmd = NULL; + return -1; + } + ub_config_set_port_basic(&dev->port.neighbors[local_port_idx], dev); + } + g_free(dev->port.neighbors_cmd); + dev->port.neighbors_cmd = NULL; + return 0; +} + +static int ub_dev_init_port_info_by_cmd(Error **errp) +{ + BusControllerState *ubc = NULL; + UBDevice *dev = NULL; + + QLIST_FOREACH(ubc, &ub_bus_controllers, node) { + if (!ubc->bus->qbus.num_children) { + continue; + } + + QLIST_FOREACH(dev, &ubc->bus->devices, node) { + if (dev && dev->port.neighbors_cmd) { + if (ub_dev_set_neighbor_info(dev, errp) < 0) { + return -1; + } + qemu_log("finish set_neighbor_info, eid:%u\n", dev->eid); + } + } + } + /* Check whether any device port info does not exist */ + QLIST_FOREACH(ubc, &ub_bus_controllers, node) { + if (!ubc->bus->qbus.num_children) { + continue; + } + QLIST_FOREACH(dev, &ubc->bus->devices, node) { + if (dev->dev_type != UB_TYPE_DEVICE && dev->dev_type != UB_TYPE_IDEVICE) { + continue; + } + + if (dev && !dev->port.port_info_exist) { + qemu_log("%s port info does not exist.\n", dev->qdev.id); + error_setg(errp, "%s port info does not exist.\n", dev->qdev.id); + return -1; + } + } + } + return 0; +} + +/* + * now all ub device add, finally setup for all ub device. + * 1. check ub device bus instance type + * 2. init the port info + * */ +int ub_dev_finally_setup(VirtMachineState *vms, Error **errp) +{ + /* + * Initialize the port information of all UB devices according + * to the input information after all UB devices are constructed. + */ + if (ub_dev_init_port_info_by_cmd(errp) < 0) { + return -1; + } + + ub_set_ubinfo_in_ubc_table(vms); + + return 0; +} \ No newline at end of file diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 7f0d3ed39d..29cc5fa0c4 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -39,7 +39,6 @@ #include "sysemu/kvm.h" #include "hw/intc/arm_gicv3_common.h" #include "qom/object.h" -#include "hw/ub/ub_bus.h" #define NUM_GICV2M_SPIS 64 #define NUM_VIRTIO_TRANSPORTS 32 diff --git a/include/hw/ub/ub.h b/include/hw/ub/ub.h index 2f408d874d..858824220c 100644 --- a/include/hw/ub/ub.h +++ b/include/hw/ub/ub.h @@ -20,6 +20,7 @@ #include #include "qemu/typedefs.h" #include "exec/memory.h" +#include "hw/arm/virt.h" #define BYTE_SIZE 1 #define WORD_SIZE 2 @@ -226,5 +227,6 @@ void ub_default_read_config(UBDevice *dev, uint64_t offset, void ub_default_write_config(UBDevice *dev, uint64_t offset, uint32_t *val, uint32_t dw_mask); UBDevice *ub_find_device_by_guid(UbGuid *guid); - +int ub_dev_finally_setup(VirtMachineState *vms, Error **errp); +UBDevice *ub_find_device_by_id(const char *id); #endif diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 18d0f21ee2..a1b15dd219 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -140,6 +140,7 @@ typedef struct VMStateDescription VMStateDescription; /* UB typedef */ typedef struct UBDevice UBDevice; +typedef struct UBBus UBBus; /* * Pointer types -- Gitee From 7f97fabe53c964a9f522e0708d518dafcc6a0747 Mon Sep 17 00:00:00 2001 From: caojinhuahw Date: Tue, 11 Nov 2025 18:43:51 +0800 Subject: [PATCH 4/5] ub: init ub bus controller dev config space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、init default config value for bus controller dev config space 2、init default wmask value for bus controller dev config space Signed-off-by: caojinhuahw --- hw/ub/ub_ubc.c | 169 +++++++++++++++++++++++++++++++++++++++++ include/hw/ub/ub_ubc.h | 9 +++ 2 files changed, 178 insertions(+) diff --git a/hw/ub/ub_ubc.c b/hw/ub/ub_ubc.c index e371f4f35a..1023ec9deb 100644 --- a/hw/ub/ub_ubc.c +++ b/hw/ub/ub_ubc.c @@ -24,7 +24,11 @@ #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" #include "hw/ub/ub.h" +#include "hw/ub/ub_bus.h" #include "hw/ub/ub_ubc.h" +#include "hw/ub/ub_config.h" +#include "hw/ub/hisi/ubc.h" +#include "hw/ub/hisi/ub_mem.h" #include "migration/vmstate.h" static uint64_t ub_msgq_reg_read(void *opaque, hwaddr addr, unsigned len) @@ -205,6 +209,170 @@ static const TypeInfo ub_bus_controller_type_info = { .class_init = ub_bus_controller_class_init, }; +static void ub_bus_controller_cfg0_route_table_init(UBDevice *ub_dev) +{ + uint64_t emulated_offset = ub_cfg_offset_to_emulated_offset(UB_ROUTE_TABLE_START, true); + UbRouteTable *route_table = (UbRouteTable *)(ub_dev->config + emulated_offset); + + /* The prerequisite is that each device uses only one port. + * The Ub controller own a CNA, each port own a CNA, and each device own a CNA. */ + route_table->entry_num = UB_DEV_MAX_NUM_OF_PORT * 2 + 1; + route_table->ers = 1; /* support exact route */ +} + +static void ub_bus_controller_space_cfg0_init(UBDevice *ub_dev) +{ + UbCfg0Basic *cfg0_basic; + Cfg0SupportFeature *support_feature; + UbCfg0ShpCap *shp_cap; + UbSlotInfo *slot_info; + uint64_t emulated_offset; + + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG0_BASIC_START, true); + cfg0_basic = (UbCfg0Basic *)(ub_dev->config + emulated_offset); + cfg0_basic->header.slice_version = UB_SLICE_VERSION; + cfg0_basic->header.slice_used_size = UB_CFG0_BASIC_SLICE_USED_SIZE; + cfg0_basic->total_num_of_port = ub_dev->port.port_num & UINT16_MASK; + cfg0_basic->total_num_of_ue = 1; + cfg0_basic->cap_bitmap[CFG0_CAP2_SHP_INDEX / BITS_PER_BYTE] = + 1 << (CFG0_CAP2_SHP_INDEX % BITS_PER_BYTE); + support_feature = &cfg0_basic->support_feature; + support_feature->bits.entity_available = 1; + support_feature->bits.mtu_supported = 1; + support_feature->bits.route_table_supported = SUPPORTED; + support_feature->bits.upi_supported = SUPPORTED; + support_feature->bits.broker_supported = NOT_SUPPORTED; + support_feature->bits.switch_supported = SUPPORTED; + support_feature->bits.cc_supported = NOT_SUPPORTED; + /* SHP CAP */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG0_CAP2_SHP_START, true); + shp_cap = (UbCfg0ShpCap *)(ub_dev->config + emulated_offset); + shp_cap->slot_num = 1; + shp_cap->header.slice_version = UB_SLICE_VERSION; + shp_cap->header.slice_used_size = (shp_cap->slot_num * sizeof(UbSlotInfo) + sizeof(UbCfg0ShpCap)) / DWORD_SIZE; + for (int i = 0; i < shp_cap->slot_num; ++i) { + slot_info = (UbSlotInfo *)((uint8_t *)shp_cap->slot_info + i * sizeof(UbSlotInfo)); + slot_info->start_port_idx = 0; + slot_info->end_port_idx = cfg0_basic->total_num_of_port - 1; + slot_info->pp_ctrl = 1; + slot_info->ms_ctrl = 1; + slot_info->pd_ctrl = 1; + slot_info->pds_ctrl = 1; + } + ub_bus_controller_cfg0_route_table_init(ub_dev); +} + +static void ub_bus_controller_space_cfg1_init(UBDevice *ub_dev) +{ + UbCfg1Basic *cfg1_basic; + Cfg1SupportFeature *support_feature; + UbCfg1DecoderCap *dec_cap; + uint64_t emulated_offset; + + /* basic */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG1_BASIC_START, true); + cfg1_basic = (UbCfg1Basic *)(ub_dev->config + emulated_offset); + cfg1_basic->header.slice_version = UB_SLICE_VERSION; + cfg1_basic->header.slice_used_size = UB_CFG1_BASIC_SLICE_USED_SIZE; + + cfg1_basic->cap_bitmap[CFG1_DECODER_CAP_INDEX / BITS_PER_BYTE] |= + 1 << (CFG1_DECODER_CAP_INDEX % BITS_PER_BYTE); + + support_feature = &cfg1_basic->support_feature; + support_feature->bits.mgs = SUPPORTED; + support_feature->bits.ubbas = NOT_SUPPORTED; + support_feature->bits.ers0s = SUPPORTED; + support_feature->bits.ers1s = NOT_SUPPORTED; + support_feature->bits.ers2s = SUPPORTED; + support_feature->bits.cdmas = SUPPORTED; + support_feature->bits.matt_juris = UB_DRIVE; + cfg1_basic->ers_space_size[0] = UBC_ERS0_SPACE_SIZE; + cfg1_basic->ers_space_size[1] = UBC_ERS1_SPACE_SIZE; + cfg1_basic->ers_space_size[2] = UBC_ERS2_SPACE_SIZE; + cfg1_basic->ers_start_addr[0] = UBC_ERS0_SPACE_ADDR; + cfg1_basic->ers_start_addr[1] = UBC_ERS1_SPACE_ADDR; + cfg1_basic->ers_start_addr[2] = UBC_ERS2_SPACE_ADDR; + cfg1_basic->eid_upi_ten = UBC_EID_UPI_TEN_DEFAULT_VAL; + cfg1_basic->class_code = UBC_CLASS_CODE; + /* decoder cap */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG1_CAP1_DECODER, true); + dec_cap = (UbCfg1DecoderCap *)(ub_dev->config + emulated_offset); + dec_cap->header.slice_version = UB_SLICE_VERSION; + dec_cap->header.slice_used_size = sizeof(UbCfg1DecoderCap) / DWORD_SIZE; + dec_cap->decoder.event_size_sup = DECODER_CAP_EVENT_SIZE; + dec_cap->decoder.cmd_size_sup = DECODER_CAP_CMD_SIZE; + dec_cap->decoder.mmio_size_sup = DECODER_CAP_MMIO_SIZE; +} + +static void ub_bus_controller_wmask_init(UBDevice *ub_dev) +{ + UbCfg1DecoderCap *dec_cap_mask; + UbCfg0ShpCap *cfg0_shp_wmask, *cfg0_shp; + uint64_t emulated_offset; + + /* cfg0 cap */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG0_CAP2_SHP_START, true); + cfg0_shp_wmask = (UbCfg0ShpCap *)(ub_dev->wmask + emulated_offset); + cfg0_shp = (UbCfg0ShpCap *)(ub_dev->config + emulated_offset); + memset(cfg0_shp_wmask, 0, UB_SLICE_SZ); + for (int i = 0; i < cfg0_shp->slot_num; ++i) { + cfg0_shp_wmask->slot_info[i].pp_ctrl = ~0; + cfg0_shp_wmask->slot_info[i].wl_ctrl = ~0; + cfg0_shp_wmask->slot_info[i].pl_ctrl = ~0; + cfg0_shp_wmask->slot_info[i].ms_ctrl = ~0; + cfg0_shp_wmask->slot_info[i].pd_ctrl = ~0; + cfg0_shp_wmask->slot_info[i].pds_ctrl = ~0; + cfg0_shp_wmask->slot_info[i].pw_ctrl = ~0; + } + + /* cfg1 cap */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG1_CAP1_DECODER, true); + dec_cap_mask = (UbCfg1DecoderCap *)(ub_dev->wmask + emulated_offset); + memset(dec_cap_mask, 0, sizeof(UbCfg1DecoderCap)); + dec_cap_mask->decoder_ctrl.decoder_en = ~0; + memset(&dec_cap_mask->dec_matt_ba, 0xff, sizeof(dec_cap_mask->dec_matt_ba)); + memset(&dec_cap_mask->dec_mmio_ba, 0xff, sizeof(dec_cap_mask->dec_mmio_ba)); + memset(&dec_cap_mask->dev_usi_idx, 0xff, sizeof(dec_cap_mask->dev_usi_idx)); + dec_cap_mask->decoder_cmdq_cfg.cmdq_en = ~0; + dec_cap_mask->decoder_cmdq_cfg.cmdq_size_use = ~0; + dec_cap_mask->decoder_cmdq_prod.cmdq_wr_idx = ~0; + dec_cap_mask->decoder_cmdq_prod.cmdq_err_resp = ~0; + dec_cap_mask->decoder_cmdq_cons.cmdq_rd_idx = ~0; + dec_cap_mask->decoder_cmdq_cons.cmdq_err = ~0; + dec_cap_mask->decoder_cmdq_cons.cmdq_err_res = ~0; + dec_cap_mask->decoder_cmdq_ba.cmdq_ba = ~0; + dec_cap_mask->decoder_evtq_cfg.evtq_en = ~0; + dec_cap_mask->decoder_evtq_cfg.evtq_size_use = ~0; + dec_cap_mask->decoder_evtq_prod.evtq_wr_idx = ~0; + dec_cap_mask->decoder_evtq_cons.evtq_rd_idx = ~0; + dec_cap_mask->decoder_evtq_ba.evtq_ba = ~0; +} + +static void ub_bus_controller_w1cmask_init(UBDevice *ub_dev) +{ + UbCfg0ShpCap *cfg0_shp_w1cmask, *cfg0_shp; + uint64_t emulated_offset; + + /* cfg0 cap */ + emulated_offset = ub_cfg_offset_to_emulated_offset(UB_CFG0_CAP2_SHP_START, true); + cfg0_shp_w1cmask = (UbCfg0ShpCap *)(ub_dev->w1cmask + emulated_offset); + cfg0_shp = (UbCfg0ShpCap *)(ub_dev->config + emulated_offset); + memset(cfg0_shp_w1cmask, 0, UB_SLICE_SZ); + for (int i = 0; i < cfg0_shp->slot_num; ++i) { + cfg0_shp_w1cmask->slot_info[i].pp_st = ~0; + cfg0_shp_w1cmask->slot_info[i].pd_st = ~0; + cfg0_shp_w1cmask->slot_info[i].pdsc_st = ~0; + } +} + +static void ub_bus_controller_dev_config_space_init(UBDevice *dev) +{ + ub_bus_controller_space_cfg0_init(dev); + ub_bus_controller_space_cfg1_init(dev); + ub_bus_controller_wmask_init(dev); + ub_bus_controller_w1cmask_init(dev); +} + static bool ub_ubc_is_empty(UBBus *bus) { UBDevice *dev; @@ -240,6 +408,7 @@ static void ub_bus_controller_dev_realize(UBDevice *dev, Error **errp) } dev->dev_type = UB_TYPE_IBUS_CONTROLLER; + ub_bus_controller_dev_config_space_init(dev); } static Property ub_bus_controller_dev_properties[] = { diff --git a/include/hw/ub/ub_ubc.h b/include/hw/ub/ub_ubc.h index af0f4b1a7f..fe86a1e34f 100644 --- a/include/hw/ub/ub_ubc.h +++ b/include/hw/ub/ub_ubc.h @@ -61,6 +61,15 @@ struct BusControllerClass { SysBusDeviceClass parent_class; }; +#define UBC_ERS0_SPACE_SIZE 0x2 +#define UBC_ERS1_SPACE_SIZE 0x10001 +#define UBC_ERS2_SPACE_SIZE 0x20 +#define UBC_ERS0_SPACE_ADDR 0x2c00000000 +#define UBC_ERS1_SPACE_ADDR 0x2d00000000 +#define UBC_ERS2_SPACE_ADDR 0x2e00000000 +#define UBC_EID_UPI_TEN_DEFAULT_VAL 1024 +#define UBC_CLASS_CODE 0x0 + void ub_save_ubc_list(BusControllerState *s); BusControllerState *container_of_ubbus(UBBus *bus); #endif -- Gitee From 3e92cc3ff46785e1b9233f5f9d922757a655ceb1 Mon Sep 17 00:00:00 2001 From: caojinhuahw Date: Tue, 11 Nov 2025 19:01:56 +0800 Subject: [PATCH 5/5] ub: realize ub fm memory region ops add ub fm memory region ops for read/write process Signed-off-by: caojinhuahw --- hw/ub/hisi/meson.build | 5 +++ hw/ub/hisi/ub_fm.c | 70 ++++++++++++++++++++++++++++++++++++++ hw/ub/ub_ubc.c | 5 ++- include/hw/ub/hisi/ub_fm.h | 6 +++- 4 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 hw/ub/hisi/ub_fm.c diff --git a/hw/ub/hisi/meson.build b/hw/ub/hisi/meson.build index e69de29bb2..df07aae9e1 100644 --- a/hw/ub/hisi/meson.build +++ b/hw/ub/hisi/meson.build @@ -0,0 +1,5 @@ +ub_ss = ss.source_set() +ub_ss.add(files( + 'ub_fm.c', +)) +system_ss.add_all(when: 'CONFIG_HW_UB', if_true: ub_ss) \ No newline at end of file diff --git a/hw/ub/hisi/ub_fm.c b/hw/ub/hisi/ub_fm.c new file mode 100644 index 0000000000..7b7625621a --- /dev/null +++ b/hw/ub/hisi/ub_fm.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 "hw/ub/hisi/ub_fm.h" +#include "qemu/log.h" + +uint64_t ub_fm_msgq_reg_read(void *opaque, hwaddr addr, unsigned len) +{ + BusControllerState *s = opaque; + uint64_t val; + + switch (len) { + case BYTE_SIZE: + val = ub_get_byte(s->fm_msgq_reg + addr); + break; + case WORD_SIZE: + val = ub_get_word(s->fm_msgq_reg + addr); + break; + case DWORD_SIZE: + val = ub_get_long(s->fm_msgq_reg + addr); + break; + default: + qemu_log("invalid argument len 0x%x\n", len); + val = ~0x0; + break; + } + + qemu_log("ub_fm_msgq_reg_read addr 0x%lx len 0x%x val 0x%lx\n", + addr, len, val); + return val; +} + +void ub_fm_msgq_reg_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) +{ + BusControllerState *s = opaque; + + switch (len) { + case BYTE_SIZE: + ub_set_byte(s->fm_msgq_reg + addr, val); + break; + case WORD_SIZE: + ub_set_word(s->fm_msgq_reg + addr, val); + break; + case DWORD_SIZE: + ub_set_long(s->fm_msgq_reg + addr, val); + break; + default: + /* As length is under guest control, handle illegal values. */ + qemu_log("invalid argument len 0x%x addr 0x%lx val 0x%lx\n", + len, addr, val); + return; + } + qemu_log("ub_fm_msgq_reg_write addr 0x%lx len 0x%x val 0x%lx\n", + addr, len, val); +} \ No newline at end of file diff --git a/hw/ub/ub_ubc.c b/hw/ub/ub_ubc.c index 1023ec9deb..d28ba2024f 100644 --- a/hw/ub/ub_ubc.c +++ b/hw/ub/ub_ubc.c @@ -29,6 +29,7 @@ #include "hw/ub/ub_config.h" #include "hw/ub/hisi/ubc.h" #include "hw/ub/hisi/ub_mem.h" +#include "hw/ub/hisi/ub_fm.h" #include "migration/vmstate.h" static uint64_t ub_msgq_reg_read(void *opaque, hwaddr addr, unsigned len) @@ -83,7 +84,9 @@ static const MemoryRegionOps ub_msgq_reg_ops = { }; static const MemoryRegionOps ub_fm_msgq_reg_ops = { - + .read = ub_fm_msgq_reg_read, + .write = ub_fm_msgq_reg_write, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void ub_reg_alloc(DeviceState *dev) diff --git a/include/hw/ub/hisi/ub_fm.h b/include/hw/ub/hisi/ub_fm.h index bd606227a6..93255e47d8 100644 --- a/include/hw/ub/hisi/ub_fm.h +++ b/include/hw/ub/hisi/ub_fm.h @@ -18,8 +18,12 @@ #ifndef UB_HISI_FM_H #define UB_HISI_FM_H #include "hw/ub/hisi/ubc.h" +#include "hw/qdev-core.h" +#include "hw/ub/ub_common.h" #define FM_MSGQ_REG_OFFSET (UBC_MSGQ_REG_OFFSET + UBC_MSGQ_REG_SIZE) #define FM_MSGQ_REG_SIZE 0x100000 /* 1MiB */ -#endif +uint64_t ub_fm_msgq_reg_read(void *opaque, hwaddr addr, unsigned len); +void ub_fm_msgq_reg_write(void *opaque, hwaddr addr, uint64_t val, unsigned len); +#endif \ No newline at end of file -- Gitee