From 48636ea7e0147e61031ba8cba9c4840d55512f7f Mon Sep 17 00:00:00 2001 From: klmengkd Date: Sat, 20 Dec 2025 15:45:03 +0800 Subject: [PATCH] uvb: support uvb over ub message drivers inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ID9GC7?from=project-issue CVE: NA -------------------------------- This patch add cis ub message handler. Signed-off-by: klmengkd --- drivers/firmware/uvb/Makefile | 4 +- drivers/firmware/uvb/cis/cis_core.c | 46 ++++-- drivers/firmware/uvb/cis/cis_info_process.h | 1 - drivers/firmware/uvb/cis/cis_ub.c | 171 ++++++++++++++++++++ drivers/firmware/uvb/cis/cis_ub.h | 125 ++++++++++++++ drivers/firmware/uvb/cis/uvb_info_process.h | 2 + drivers/firmware/uvb/odf/odf_get_fdt.c | 34 ---- drivers/firmware/uvb/odf/odf_trans.c | 18 ++- 8 files changed, 350 insertions(+), 51 deletions(-) create mode 100644 drivers/firmware/uvb/cis/cis_ub.c create mode 100644 drivers/firmware/uvb/cis/cis_ub.h delete mode 100644 drivers/firmware/uvb/odf/odf_get_fdt.c diff --git a/drivers/firmware/uvb/Makefile b/drivers/firmware/uvb/Makefile index d5a261794d9e..27175fb0e3a0 100644 --- a/drivers/firmware/uvb/Makefile +++ b/drivers/firmware/uvb/Makefile @@ -4,7 +4,6 @@ ccflags-y += -I$(srctree)/drivers/firmware/uvb/include -obj-$(CONFIG_UDFI) = odf/odf_get_fdt.o obj-$(CONFIG_UDFI_ODF) += odf.o odf-objs := odf/odf_trans.o \ odf/odf_data.o \ @@ -13,4 +12,5 @@ odf-objs := odf/odf_trans.o \ obj-$(CONFIG_UDFI_CIS) += cis.o cis-objs := cis/cis_info_process.o \ cis/uvb_info_process.o \ - cis/cis_core.o + cis/cis_core.o \ + cis/cis_ub.o diff --git a/drivers/firmware/uvb/cis/cis_core.c b/drivers/firmware/uvb/cis/cis_core.c index d1e5938b306c..c46ef0e736b4 100644 --- a/drivers/firmware/uvb/cis/cis_core.c +++ b/drivers/firmware/uvb/cis/cis_core.c @@ -13,8 +13,11 @@ #include #include #include +#include +#include #include "cis_info_process.h" #include "uvb_info_process.h" +#include "cis_ub.h" MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Call ID Service Framework"); @@ -140,6 +143,22 @@ void uninit_uvb(void) free_uvb_window_lock(); } +static const struct auxiliary_device_id uvb_id_table[] = { + { + .name = UBASE_ADEV_NAME ".uvb", + }, + {}, +}; + +MODULE_DEVICE_TABLE(auxiliary, uvb_id_table); + +static struct auxiliary_driver uvb_drv = { + .probe = uvb_probe, + .remove = uvb_remove, + .name = "uvb", + .id_table = uvb_id_table, +}; + static int __init cis_init(void) { int err = 0; @@ -147,23 +166,29 @@ static int __init cis_init(void) err = init_cis_table(); if (err) { pr_err("cis info init failed, err=%d\n", err); - return err; - } + } else { + err = init_global_vars(); + if (err) { + pr_err("global vars malloc failed, err=%d\n", err); + return err; + } - err = init_global_vars(); - if (err) { - pr_err("global vars malloc failed, err=%d\n", err); - return err; + err = init_uvb(); + if (err) { + pr_err("uvb init failed, err=%d\n", err); + free_global_vars(); + return err; + } + pr_info("cis uvb init success\n"); } - err = init_uvb(); + err = auxiliary_driver_register(&uvb_drv); if (err) { - pr_err("uvb init failed, err=%d\n", err); - free_global_vars(); + pr_err("failed to register uvb drv\n"); return err; } - pr_info("cis init success\n"); + pr_info("register uvb over ub drv success\n"); return 0; } @@ -172,6 +197,7 @@ static void __exit cis_exit(void) { uninit_uvb(); free_global_vars(); + auxiliary_driver_unregister(&uvb_drv); pr_info("cis exit success\n"); } diff --git a/drivers/firmware/uvb/cis/cis_info_process.h b/drivers/firmware/uvb/cis/cis_info_process.h index ad2ed2467fda..4c23f413bb45 100644 --- a/drivers/firmware/uvb/cis/cis_info_process.h +++ b/drivers/firmware/uvb/cis/cis_info_process.h @@ -21,7 +21,6 @@ extern struct cis_message *io_param_sync; extern struct list_head g_local_cis_list; -extern DECLARE_HASHTABLE(uvb_lock_table, MAX_UVB_LOCK_IN_BITS); struct udfi_para { u32 message_id; diff --git a/drivers/firmware/uvb/cis/cis_ub.c b/drivers/firmware/uvb/cis/cis_ub.c new file mode 100644 index 000000000000..464e5bbe638d --- /dev/null +++ b/drivers/firmware/uvb/cis/cis_ub.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. + * Description: UVB over UB message processing module, handles CIS UB init, + * func register/lookup and UB message. + * Author: mengkanglai + * Create: 2025-12-18 + */ + +#define pr_fmt(fmt) "[UVB_UB]: " fmt + +#include +#include +#include +#include +#include +#include "cis_ub.h" +#include "cis_info_process.h" + +enum ubios_cis_opcode { + CIS_OPC_SEND = 0xFA00, + CIS_OPC_RECV = 0xFA01, +}; + +void ub_msg_header_init(struct msg_pkt_header *header) +{ + header->ulh.cfg = UB_COMPACT_LINK_CFG; + header->nth.nth_nlp = NTH_NLP_WITH_TPH; + header->nth.mm = NTH_NLP_WITH_MGMT; + header->ctph_nlp = CTPH_NLP_UPI_40BITS_UEID; + header->tp_opcode = CTPH_OPCODE_NOT_CNP; + header->btah.ta_opcode = TAH_OPCODE_MSG; + header->msgetah.msg_code = UB_MSG_CODE; + header->msgetah.sub_msg_code = UB_SUB_MSG_CODE; + header->ub_pload.type = UB_PAYLOAD_TYPE; + header->ub_pload.version = UB_PAYLOAD_VERION; +} + +void setup_resp_pkt(struct msg_pkt_header *resp, struct msg_pkt_header *rcv) +{ + struct compact_network_header *nth = &rcv->nth; + + memcpy(resp, rcv, sizeof(struct msg_pkt_header)); + ub_msg_header_init(resp); + resp->ub_pload.message_id = ~rcv->ub_pload.message_id; + resp->ub_pload.sender_id = UBIOS_USER_ID_BIOS; + resp->ub_pload.receiver_id = UBIOS_USER_ID_UB_DEVICE | nth->scna; + resp->nth.dcna = nth->scna; + resp->deid = eid_gen(rcv->seid_h, rcv->seid_l); + resp->nth.scna = nth->dcna; + resp->seid_l = seid_low(rcv->deid); + resp->seid_h = seid_high(rcv->deid); + resp->msgetah.rsp = 0x1; +} + +static bool check_ub_pload_valid(struct payload *ub_pload, u32 len) +{ + if (!ub_pload->sender_id || !ub_pload->receiver_id) { + pr_err("senderid or receiverid can't be null\n"); + return false; + } + + if (UBIOS_GET_MESSAGE_FLAG(ub_pload->message_id) != UBIOS_CALL_ID_FLAG) { + pr_err("uvb over ub not a cis call\n"); + return false; + } + + if (len > sizeof(struct msg_pkt_header) && !ub_pload->data_total_size) { + pr_err("ub pload have data but data size is null\n"); + return false; + } + + if (len == sizeof(struct msg_pkt_header) && ub_pload->data_total_size) { + pr_err("ub pload no data but data size is not null\n"); + return false; + } + + return true; +} + +int uvb_handle_cmdq_event(void *dev, void *data, u32 len) +{ + int err = 0; + msg_handler func; + struct cis_message msg = {}; + struct ubase_cmd_buf in; + struct msg_pkt_header *resp; + struct msg_pkt_header *ub_header = (struct msg_pkt_header *)data; + struct payload *ub_pload = &ub_header->ub_pload; + + u32 output_size = ub_pload->output_buffer_size; + + msg.input = ub_pload->data; + msg.input_size = ub_pload->data_total_size; + + if (ub_header->msgetah.plen < ub_pload->data_total_size) { + pr_err("it's a framed message, not supported\n"); + return -EINVAL; + } + + if (!check_ub_pload_valid(ub_pload, len)) { + pr_err("check payload param failed\n"); + return -EINVAL; + } + + if (output_size == UVB_OUTPUT_SIZE_NULL || !output_size) { + msg.p_output_size = NULL; + msg.output = NULL; + } else { + msg.p_output_size = &output_size; + msg.output = kzalloc(output_size, GFP_KERNEL); + } + + func = search_local_cis_func(ub_pload->message_id, ub_pload->receiver_id); + if (!func) { + pr_err("not found cis registered func\n"); + kfree(msg.output); + return -EOPNOTSUPP; + } + + err = func(&msg); + if (err) + pr_err("uvb over ub execute cis func failed, err=%d\n", err); + + if (msg.output && msg.p_output_size && *msg.p_output_size) { + resp = kzalloc(sizeof(struct msg_pkt_header) + *msg.p_output_size, GFP_KERNEL); + memcpy(resp->ub_pload.data, msg.output, *msg.p_output_size); + resp->ub_pload.data_total_size = resp->msgetah.plen = *msg.p_output_size; + } else { + resp = kzalloc(sizeof(struct msg_pkt_header), GFP_KERNEL); + resp->ub_pload.data_total_size = resp->msgetah.plen = 0; + } + + setup_resp_pkt(resp, ub_header); + resp->ub_pload.returned_status = (u32)err; + + ubase_fill_inout_buf(&in, CIS_OPC_SEND, false, + sizeof(struct msg_pkt_header) + resp->msgetah.plen, &resp); + err = ubase_cmd_send_in(dev, &in); + if (err) + pr_err("send ubase info err, err=%d\n", err); + + kfree(resp); + kfree(msg.output); + + return err; +} + +int uvb_probe(struct auxiliary_device *aux_dev, const struct auxiliary_device_id *id) +{ + int ret = 0; + struct ubase_crq_event_nb uvb_crq_events; + + uvb_crq_events.opcode = CIS_OPC_RECV; + uvb_crq_events.back = aux_dev; + uvb_crq_events.crq_handler = uvb_handle_cmdq_event; + ret = ubase_register_crq_event(aux_dev, &uvb_crq_events); + if (ret) { + pr_err("register uvb crq events failed, err=%d\n", ret); + return -1; + } + + pr_info("register uvb crq events success\n"); + + return 0; +} + +void uvb_remove(struct auxiliary_device *aux_dev) +{ + ubase_unregister_crq_event(aux_dev, CIS_OPC_RECV); +} diff --git a/drivers/firmware/uvb/cis/cis_ub.h b/drivers/firmware/uvb/cis/cis_ub.h new file mode 100644 index 000000000000..1b72c633e5bc --- /dev/null +++ b/drivers/firmware/uvb/cis/cis_ub.h @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. + * Description: cis ub header + * Create: 2025-12-18 + */ + +#ifndef CIS_UB_H +#define CIS_UB_H + +#define seid_high(eid) (((eid) >> 12) & 0xff) +#define seid_low(eid) ((eid) & 0xfff) +#define eid_gen(eid_h, eid_l) ((eid_h) << 12 | (eid_l)) + +struct payload { +#define UB_PAYLOAD_TYPE 0x1 + u32 type : 4; +#define UB_PAYLOAD_VERION 0x1 + u32 version : 4; + u32 rsvd : 10; + u32 index : 16; + u32 message_id; + u32 sender_id; + u32 receiver_id; + union { + u32 output_buffer_size; + u32 returned_status; + }; + u32 data_total_size; + DECLARE_FLEX_ARRAY(char, data); +}; + +struct base_header { + /* DW0 */ + u32 ini_tassn : 16; + u32 udf_flag : 1; + u32 rsvd2 : 1; + u32 poison : 1; + u32 tk_en : 1; + u32 ee : 2; + u32 taver : 2; +#define TAH_OPCODE_MSG 0x10 + u32 ta_opcode : 8; + /* DW1 */ + u32 ini_rc_id : 20; + u32 ini_rc_type : 2; + u32 excl : 1; + u32 rsvd3 : 1; + u32 atloc : 1; + u32 retry : 1; + u32 se : 1; + u32 tc_en : 1; + u32 tak_en : 1; + u32 odr : 3; +}; + +struct msg_extended_header { + u32 plen : 12; + u32 rsvd : 4; + u32 rsp_status : 8; + u32 rsp : 1; +#define UB_MSG_CODE 0x3 + u32 msg_code : 3; +#define UB_SUB_MSG_CODE 0x1 + u32 sub_msg_code : 4; +}; + +struct compact_network_header { + /* DW0 */ + u32 dcna : 16; + u32 scna : 16; + /* DW1 */ +#define NTH_NLP_WITH_TPH 0 +#define NTH_NLP_WITHOUT_TPH 1 + u32 nth_nlp : 3; +#define NTH_NLP_WITH_MGMT 0 + u32 mm : 1; + u32 sl : 4; + u32 lb : 8; + u32 cci : 16; +}; + +struct ub_link_header { + u32 plen : 14; + u32 rt : 2; + u32 cfg : 4; + u32 rsvd0 : 1; + u32 vl : 4; + u32 rsvd1 : 1; + u32 crd_vl : 4; + u32 ack : 1; + u32 crd : 1; +}; + +#define UB_COMPACT_LINK_CFG 6 + +struct msg_pkt_header { + /* DW0 */ + struct ub_link_header ulh; + /* DW1~DW2 */ +struct compact_network_header nth; + /* DW3 */ + u32 seid_h : 8; + u32 upi : 16; +#define CTPH_NLP_UPI_40BITS_UEID 2 + u32 ctph_nlp : 4; + u32 pad : 2; +#define CTPH_OPCODE_NOT_CNP 0 + u32 tp_opcode : 2; + /* DW4 */ + u32 deid : 20; + u32 seid_l : 12; + /* DW5~DW6 */ + struct base_header btah; + /* DW7 */ + struct msg_extended_header msgetah; + + /* DW8~DW15 */ + struct payload ub_pload; +}; + +int uvb_probe(struct auxiliary_device *aux_dev, const struct auxiliary_device_id *id); +void uvb_remove(struct auxiliary_device *aux_dev); + +#endif diff --git a/drivers/firmware/uvb/cis/uvb_info_process.h b/drivers/firmware/uvb/cis/uvb_info_process.h index 7f7f0e7362db..1341ec85c132 100644 --- a/drivers/firmware/uvb/cis/uvb_info_process.h +++ b/drivers/firmware/uvb/cis/uvb_info_process.h @@ -9,6 +9,8 @@ #ifndef UVB_INFO_PROCESS_H #define UVB_INFO_PROCESS_H +extern DECLARE_HASHTABLE(uvb_lock_table, MAX_UVB_LOCK_IN_BITS); + int uvb_poll_window(void *data); u32 checksum32(const void *data, u32 size); #endif diff --git a/drivers/firmware/uvb/odf/odf_get_fdt.c b/drivers/firmware/uvb/odf/odf_get_fdt.c deleted file mode 100644 index b683955e657c..000000000000 --- a/drivers/firmware/uvb/odf/odf_get_fdt.c +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. - * Description: ODF get fdt info - * Author: mengkanglai - * Create: 2025-04-18 - */ -#include -#include -#include -#include -#include - -int odf_get_fdt_ubiostbl(u64 *phys_addr, char *tbl) -{ - int node, len; - const void *prop; - - node = fdt_path_offset(initial_boot_params, "/chosen"); - if (node < 0) { - pr_err("failed to get device tree chosen node\n"); - return -EINVAL; - } - prop = fdt_getprop(initial_boot_params, node, tbl, &len); - if (!prop) { - pr_err("failed to get property\n"); - return -EINVAL; - } - *phys_addr = (len == 4) ? (u64)be32_to_cpup((const u32 *)prop) : - get_unaligned_be64(prop); - - return 0; -} -EXPORT_SYMBOL(odf_get_fdt_ubiostbl); diff --git a/drivers/firmware/uvb/odf/odf_trans.c b/drivers/firmware/uvb/odf/odf_trans.c index ac68c736db20..e1447403681a 100644 --- a/drivers/firmware/uvb/odf/odf_trans.c +++ b/drivers/firmware/uvb/odf/odf_trans.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "cis_uvb_interface.h" #include "odf_interface.h" #include "odf_handle.h" @@ -390,18 +391,27 @@ static int create_odf_info(void) acpi_status status; int ret = 0; u16 count = 0; + struct device_node *chosen_node; status = acpi_get_table(ACPI_SIG_UBRT, 0, &ubrt_header); if (ACPI_SUCCESS(status)) { pr_info("Success fully get UBRT table\n"); return 0; } - ret = odf_get_fdt_ubiostbl(&od_root_phys, "linux,ubiostbl"); - if (ret) { - pr_err("from fdt get ubiostbl failed\n"); + + chosen_node = of_find_node_by_name(of_root, "chosen"); + if (!chosen_node) { + pr_err("failed to find chosen node\n"); return -1; } + ret = of_property_read_u64(chosen_node, "linux,ubiostbl", &od_root_phys); + if (ret) { + pr_err("failed to read ubiostbl property\n"); + of_node_put(chosen_node); + return ret; + } + od_root_origin = (struct ubios_od_root *) memremap(od_root_phys, sizeof(struct ubios_od_header), MEMREMAP_WB); if (!od_root_origin) { @@ -454,7 +464,7 @@ static int __init odf_init(void) status = create_odf_info(); if (status) { pr_err("odf table init failed\n"); - return -1; + return 0; } status = create_cis_info_from_odf(); -- Gitee