From 35d7e10580712aabc48ee4904e69d177cb38594c Mon Sep 17 00:00:00 2001 From: Xiongchuan Zhou Date: Wed, 29 Oct 2025 16:39:38 +0800 Subject: [PATCH 001/103] ub: ubase: support debugfs for active dev stats. commit 6b3b919054909ca3d7bdfb1c9c2fe48c098ff1cb openEuler This commit is used to support debugfs for active dev stats. Current commit uses debugfs to collect statistics on the number of times that the rx stream stop and resume interfaces are invoked. In addition, the latest 10 statistics can be queried. Signed-off-by: Xiaobo Zhang Signed-off-by: Xiongchuan Zhou Signed-off-by: huwentao --- drivers/ub/ubase/debugfs/ubase_debugfs.c | 57 ++++++++++++++++++++++++ drivers/ub/ubase/ubase_dev.c | 10 ++++- drivers/ub/ubase/ubase_stats.c | 22 +++++++++ drivers/ub/ubase/ubase_stats.h | 3 ++ 4 files changed, 90 insertions(+), 2 deletions(-) diff --git a/drivers/ub/ubase/debugfs/ubase_debugfs.c b/drivers/ub/ubase/debugfs/ubase_debugfs.c index d7495d8b4ef7..ef0b162e1188 100644 --- a/drivers/ub/ubase/debugfs/ubase_debugfs.c +++ b/drivers/ub/ubase/debugfs/ubase_debugfs.c @@ -30,6 +30,55 @@ static int ubase_dbg_dump_rst_info(struct seq_file *s, void *data) return 0; } +static int ubase_dbg_dump_activate_record(struct seq_file *s, void *data) +{ + struct ubase_dev *udev = dev_get_drvdata(s->private); + struct ubase_activate_dev_stats *record; + u8 cnt = 1, stats_cnt; + u64 total, idx; + + if (!test_bit(UBASE_STATE_INITED_B, &udev->state_bits) || + test_bit(UBASE_STATE_RST_HANDLING_B, &udev->state_bits)) + return -EBUSY; + + record = &udev->stats.activate_record; + + mutex_lock(&record->lock); + + seq_puts(s, "current time : "); + ubase_dbg_format_time(ktime_get_real_seconds(), s); + seq_puts(s, "\n"); + seq_printf(s, "activate dev count : %llu\n", record->act_cnt); + seq_printf(s, "deactivate dev count : %llu\n", record->deact_cnt); + + total = record->act_cnt + record->deact_cnt; + if (!total) { + seq_puts(s, "activate dev change records : NA\n"); + mutex_unlock(&record->lock); + return 0; + } + + seq_puts(s, "activate dev change records :\n"); + seq_puts(s, "\tNo.\tTIME\t\t\t\tSTATUS\t\tRESULT\n"); + + stats_cnt = min(total, UBASE_ACT_STAT_MAX_NUM); + while (cnt <= stats_cnt) { + total--; + idx = total % UBASE_ACT_STAT_MAX_NUM; + seq_printf(s, "\t%-2d\t", cnt); + ubase_dbg_format_time(record->stats[idx].time, s); + seq_printf(s, "\t%s", record->stats[idx].activate ? + "activate" : "deactivate"); + seq_printf(s, "\t%d", record->stats[idx].result); + seq_puts(s, "\n"); + cnt++; + } + + mutex_unlock(&record->lock); + + return 0; +} + static void ubase_dbg_fill_single_port(struct seq_file *s, struct ubase_perf_stats_result *stats) { @@ -193,6 +242,14 @@ static struct ubase_dbg_cmd_info ubase_dbg_cmd[] = { .init = __ubase_dbg_seq_file_init, .read_func = ubase_dbg_dump_rst_info, }, + { + .name = "activate_record", + .dentry_index = UBASE_DBG_DENTRY_ROOT, + .property = UBASE_SUP_URMA | UBASE_SUP_CDMA | UBASE_SUP_UBL_ETH, + .support = __ubase_dbg_dentry_support, + .init = __ubase_dbg_seq_file_init, + .read_func = ubase_dbg_dump_activate_record, + }, { .name = "sl_vl_map", .dentry_index = UBASE_DBG_DENTRY_QOS, diff --git a/drivers/ub/ubase/ubase_dev.c b/drivers/ub/ubase/ubase_dev.c index abdb3232edea..3921cd0ff824 100644 --- a/drivers/ub/ubase/ubase_dev.c +++ b/drivers/ub/ubase/ubase_dev.c @@ -16,6 +16,7 @@ #include "ubase_mailbox.h" #include "ubase_pmem.h" #include "ubase_reset.h" +#include "ubase_stats.h" #include "ubase_dev.h" #define UBASE_PERIOD_100MS 100 @@ -1317,12 +1318,15 @@ int ubase_activate_dev(struct auxiliary_device *adev) if (ret) { ubase_err(udev, "failed to activate ubase dev, ret = %d.\n", ret); - return ret; + goto activate_dev_err; } ubase_activate_notify(udev, adev, true); - return 0; +activate_dev_err: + ubase_update_activate_stats(udev, true, ret); + + return ret; } EXPORT_SYMBOL(ubase_activate_dev); @@ -1352,6 +1356,8 @@ int ubase_deactivate_dev(struct auxiliary_device *adev) ubase_activate_notify(udev, adev, true); } + ubase_update_activate_stats(udev, false, ret); + return ret; } EXPORT_SYMBOL(ubase_deactivate_dev); diff --git a/drivers/ub/ubase/ubase_stats.c b/drivers/ub/ubase/ubase_stats.c index b30e839ebb0b..7f536e0cd537 100644 --- a/drivers/ub/ubase/ubase_stats.c +++ b/drivers/ub/ubase/ubase_stats.c @@ -65,3 +65,25 @@ int ubase_get_ub_port_stats(struct auxiliary_device *adev, u16 port_id, sizeof(*data) / sizeof(u64), false); } EXPORT_SYMBOL(ubase_get_ub_port_stats); + +void ubase_update_activate_stats(struct ubase_dev *udev, bool activate, + int result) +{ + struct ubase_activate_dev_stats *record = &udev->stats.activate_record; + u64 idx, total; + + mutex_lock(&record->lock); + + if (activate) + record->act_cnt++; + else + record->deact_cnt++; + + total = record->act_cnt + record->deact_cnt; + idx = (total - 1) % UBASE_ACT_STAT_MAX_NUM; + record->stats[idx].activate = activate; + record->stats[idx].time = ktime_get_real_seconds(); + record->stats[idx].result = result; + + mutex_unlock(&record->lock); +} diff --git a/drivers/ub/ubase/ubase_stats.h b/drivers/ub/ubase/ubase_stats.h index b3f6e5d788cc..a6826dd461c7 100644 --- a/drivers/ub/ubase/ubase_stats.h +++ b/drivers/ub/ubase/ubase_stats.h @@ -15,4 +15,7 @@ struct ubase_query_mac_stats_cmd { __le64 stats_val[]; }; +void ubase_update_activate_stats(struct ubase_dev *udev, bool activate, + int result); + #endif /* _UBASE_STATS_H */ -- Gitee From 0445b641aca4d3e315fe287a617113c1e6c12697 Mon Sep 17 00:00:00 2001 From: Xiongchuan Zhou Date: Tue, 23 Sep 2025 15:18:35 +0800 Subject: [PATCH 002/103] ub: ubase: Added debug information query function for FST/FVT/RQMT entries commit 0bbe314ab1feb4918f0643fd752f319fb2cfe310 openEuler This patch enhances the debugfs of the ubase driver by adding support for querying information on FST (Flow Steering Table), FVT (Flow Virtualization Table), and RQMT (Requirement) entries, thereby improving QoS debugging capabilities. Main Features: 1. Entry Information Display: - FST Table: Displays configuration details such as the number of service level queue virtual channels and the starting queue ID. - FVT Table: Shows information on virtual channel size and requirement offsets. - FST_REVERT Table: Provides mapping relationships between FST index, UE index, queue index, and the number of virtual channels. - RQMT Table: Displays requirement information, including FST index, starting queue index, and queue number offset. 2. Multi-User Entity Support: - Supports querying entry information for the current UE and all registered UEs. - Uses a UE list lock to ensure thread-safe access. This feature provides network administrators with an in-depth visualization tool for traffic steering and virtualization configurations, aiding in the diagnosis and optimization of complex QoS policy configurations. Signed-off-by: Zihao Sheng Signed-off-by: Xiongchuan Zhou Signed-off-by: huwentao --- drivers/ub/ubase/debugfs/ubase_debugfs.c | 8 ++ drivers/ub/ubase/debugfs/ubase_qos_debugfs.c | 102 +++++++++++++++++++ drivers/ub/ubase/debugfs/ubase_qos_debugfs.h | 1 + 3 files changed, 111 insertions(+) diff --git a/drivers/ub/ubase/debugfs/ubase_debugfs.c b/drivers/ub/ubase/debugfs/ubase_debugfs.c index ef0b162e1188..56ce970411bd 100644 --- a/drivers/ub/ubase/debugfs/ubase_debugfs.c +++ b/drivers/ub/ubase/debugfs/ubase_debugfs.c @@ -314,6 +314,14 @@ static struct ubase_dbg_cmd_info ubase_dbg_cmd[] = { .init = __ubase_dbg_seq_file_init, .read_func = ubase_dbg_dump_adev_qos_info, }, + { + .name = "fst_fvt_rqmt_info", + .dentry_index = UBASE_DBG_DENTRY_QOS, + .property = UBASE_SUP_URMA | UBASE_SUP_CDMA | UBASE_SUP_UBL_ETH, + .support = __ubase_dbg_dentry_support, + .init = __ubase_dbg_seq_file_init, + .read_func = ubase_dbg_dump_fsv_fvt_rqmt, + }, { .name = "tm_queue", .dentry_index = UBASE_DBG_DENTRY_QOS, diff --git a/drivers/ub/ubase/debugfs/ubase_qos_debugfs.c b/drivers/ub/ubase/debugfs/ubase_qos_debugfs.c index 9b8221e422da..91e05df180bb 100644 --- a/drivers/ub/ubase/debugfs/ubase_qos_debugfs.c +++ b/drivers/ub/ubase/debugfs/ubase_qos_debugfs.c @@ -252,6 +252,108 @@ int ubase_dbg_dump_adev_qos_info(struct seq_file *s, void *data) return 0; } +static void ubase_dbg_fill_fst_fvt(struct seq_file *s, + struct ubase_query_fst_fvt_rqmt_cmd *resp) +{ + seq_puts(s, "\tFST:\n"); + seq_printf(s, "\t\tsl_queue_vl_num: %u\n", + le16_to_cpu(resp->sl_queue_vl_num)); + seq_printf(s, "\t\tsl_queue_start_qid: %u\n", + le16_to_cpu(resp->sl_queue_start_qid)); + seq_puts(s, "\tFVT:\n"); + seq_printf(s, "\t\tfvt_vl_size: %u\n", le16_to_cpu(resp->fvt_vl_size)); + seq_printf(s, "\t\tfvt_rqmt_offset: %u\n", + le16_to_cpu(resp->fvt_rqmt_offset)); +} + +static void ubase_dbg_fill_fst_revert(struct seq_file *s, + struct ubase_query_fst_fvt_rqmt_cmd *resp) +{ + u16 vl_num = min(UBASE_MAX_VL_NUM, le16_to_cpu(resp->sl_queue_vl_num)); + u16 j; + + seq_puts(s, "\tFST_REVERT:\n"); + seq_puts(s, "\t\tFST_IDX UE_IDX QUE_IDX VL_NUM\n"); + + for (j = 0; j < vl_num; j++) { + seq_puts(s, "\t\t"); + seq_printf(s, "%-9u", le16_to_cpu(resp->fstr_info[j].fst_idx)); + seq_printf(s, "%-10u", resp->fstr_info[j].queue_ue_num); + seq_printf(s, "%-10u", resp->fstr_info[j].queue_que_num); + seq_printf(s, "%-9u", le16_to_cpu(resp->fstr_info[j].queue_vl_num)); + seq_puts(s, "\n"); + } +} + +static void ubase_dbg_fill_rqmt(struct seq_file *s, + struct ubase_query_fst_fvt_rqmt_cmd *resp) +{ + u16 vl_size = min(UBASE_MAX_VL_NUM, le16_to_cpu(resp->fvt_vl_size)); + u16 j; + + seq_puts(s, "\tRQMT:\n"); + seq_puts(s, "\t\tFST_IDX QUE_IDX QUE_SHIFT\n"); + + for (j = 0; j < vl_size; j++) { + seq_puts(s, "\t\t"); + seq_printf(s, "%-9u", le16_to_cpu(resp->rqmt_info[j].fst_idx)); + seq_printf(s, "%-10u", + le16_to_cpu(resp->rqmt_info[j].start_queue_idx)); + seq_printf(s, "%-12u", + le16_to_cpu(resp->rqmt_info[j].queue_quantity_shift)); + seq_puts(s, "\n"); + } + + seq_puts(s, "\n"); +} + +static void ubase_dbg_fill_tbl_content(struct seq_file *s, + struct ubase_query_fst_fvt_rqmt_cmd *resp) +{ + ubase_dbg_fill_fst_fvt(s, resp); + + ubase_dbg_fill_fst_revert(s, resp); + + ubase_dbg_fill_rqmt(s, resp); +} + +int ubase_dbg_dump_fsv_fvt_rqmt(struct seq_file *s, void *data) +{ + struct ubase_dev *udev = dev_get_drvdata(s->private); + struct ubase_query_fst_fvt_rqmt_cmd resp = {0}; + struct ubase_ue_node *ue_node; + u16 ue_id; + int ret; + + if (!test_bit(UBASE_STATE_INITED_B, &udev->state_bits) || + test_bit(UBASE_STATE_RST_HANDLING_B, &udev->state_bits)) + return -EBUSY; + + seq_puts(s, "current ue:\n"); + ret = ubase_query_fst_fvt_rqmt(udev, &resp, 0); + if (ret) + return ret; + + ubase_dbg_fill_tbl_content(s, &resp); + + mutex_lock(&udev->ue_list_lock); + list_for_each_entry(ue_node, &udev->ue_list, list) { + ue_id = ue_node->bus_ue_id; + memset(&resp, 0, sizeof(resp)); + + seq_printf(s, "ue%u:\n", ue_id); + + ret = ubase_query_fst_fvt_rqmt(udev, &resp, ue_id); + if (ret) + goto out; + ubase_dbg_fill_tbl_content(s, &resp); + } + +out: + mutex_unlock(&udev->ue_list_lock); + return ret; +} + static void ubase_dbg_fill_tm_queue_seq(struct seq_file *s, struct ubase_query_tm_queue_cmd *resp) { diff --git a/drivers/ub/ubase/debugfs/ubase_qos_debugfs.h b/drivers/ub/ubase/debugfs/ubase_qos_debugfs.h index 48f45a2dbec0..e44b4cacd21e 100644 --- a/drivers/ub/ubase/debugfs/ubase_qos_debugfs.h +++ b/drivers/ub/ubase/debugfs/ubase_qos_debugfs.h @@ -16,6 +16,7 @@ int ubase_dbg_dump_ets_tcg_info(struct seq_file *s, void *data); int ubase_dbg_dump_ets_port_info(struct seq_file *s, void *data); int ubase_dbg_dump_rack_vl_bitmap(struct seq_file *s, void *data); int ubase_dbg_dump_adev_qos_info(struct seq_file *s, void *data); +int ubase_dbg_dump_fsv_fvt_rqmt(struct seq_file *s, void *data); int ubase_dbg_dump_tm_queue_info(struct seq_file *s, void *data); int ubase_dbg_dump_tm_qset_info(struct seq_file *s, void *data); int ubase_dbg_dump_tm_pri_info(struct seq_file *s, void *data); -- Gitee From 23a1a3e3dfbe905e7874803144b0e4be83dd95a1 Mon Sep 17 00:00:00 2001 From: Xiongchuan Zhou Date: Wed, 29 Oct 2025 16:50:32 +0800 Subject: [PATCH 003/103] ub: ubase: add function that query aeq/ceq/tp/tpg context commit f817c5c6db98ed97a926202808d90fa395048dc2 openEuler This patch adds hardware context debugging functionality to the ubase driver, providing visual query capabilities for key hardware contexts such as AEQ, CEQ, TPG, and TP through the debugfs interface. 1. Main Features: - Supports querying AEQ/CEQ event queue contexts (status, size, interrupt configuration, etc.) - Provides display of TPG (Transmission Port Group) and TP (Transmission Port) context information - Implements hardware register context dump functionality with desensitization of key fields - Adds a new context debugging directory, integrating various context query interfaces 2. Technical Features: - Uses a mailbox mechanism to query hardware context registers - Masks sensitive addresses and token information - Supports multi-context group and port bitmap filtering - Thread-safe lock mechanism protects data structure access This implementation provides developers with an in-depth hardware state diagnostic tool, facilitating the debugging of complex hardware interaction issues. Signed-off-by: Fengyan Mu Signed-off-by: Xiongchuan Zhou Signed-off-by: huwentao --- drivers/ub/ubase/debugfs/ubase_ctx_debugfs.c | 369 +++++++++++++++++++ drivers/ub/ubase/debugfs/ubase_ctx_debugfs.h | 20 + drivers/ub/ubase/debugfs/ubase_debugfs.c | 62 ++++ drivers/ub/ubase/ubase_tp.h | 26 ++ 4 files changed, 477 insertions(+) create mode 100644 drivers/ub/ubase/debugfs/ubase_ctx_debugfs.h diff --git a/drivers/ub/ubase/debugfs/ubase_ctx_debugfs.c b/drivers/ub/ubase/debugfs/ubase_ctx_debugfs.c index 1004033c1581..33221a90edd9 100644 --- a/drivers/ub/ubase/debugfs/ubase_ctx_debugfs.c +++ b/drivers/ub/ubase/debugfs/ubase_ctx_debugfs.c @@ -7,6 +7,237 @@ #include #include "ubase_debugfs.h" +#include "ubase_hw.h" +#include "ubase_mailbox.h" +#include "ubase_tp.h" +#include "ubase_ctx_debugfs.h" + +#define UBASE_DEFAULT_CTXGN 0 + +static void ubase_dump_eq_ctx(struct seq_file *s, struct ubase_eq *eq) +{ + seq_printf(s, "%-5u", eq->eqn); + seq_printf(s, "%-13u", eq->entries_num); + seq_printf(s, "%-7u", eq->state); + seq_printf(s, "%-8u", eq->arm_st); + seq_printf(s, "%-10u", eq->eqe_size); + seq_printf(s, "%-11u", eq->eq_period); + seq_printf(s, "%-14u", eq->coalesce_cnt); + seq_printf(s, "%-6u", eq->irqn); + seq_printf(s, "%-10u", eq->eqc_irqn); + seq_printf(s, "%-12u", eq->cons_index); + seq_puts(s, "\n"); +} + +static void ubase_eq_ctx_titles_print(struct seq_file *s) +{ + seq_puts(s, "EQN ENTRIES_NUM STATE ARM_ST EQE_SIZE EQ_PERIOD "); + seq_puts(s, "COALESCE_CNT IRQN EQC_IRQN CONS_INDEX\n"); +} + +static void ubase_dump_aeq_ctx(struct seq_file *s, struct ubase_dev *udev, u32 idx) +{ + struct ubase_aeq *aeq = &udev->irq_table.aeq; + struct ubase_eq *eq = &aeq->eq; + + ubase_dump_eq_ctx(s, eq); +} + +static void ubase_dump_ceq_ctx(struct seq_file *s, struct ubase_dev *udev, u32 idx) +{ + struct ubase_ceq *ceq = &udev->irq_table.ceqs.ceq[idx]; + struct ubase_eq *eq = &ceq->eq; + + ubase_dump_eq_ctx(s, eq); +} + +static void ubase_tpg_ctx_titles_print(struct seq_file *s) +{ + seq_puts(s, "CHANNEL_ID TPGN TP_SHIFT VALID_TP "); + seq_puts(s, "START_TPN TPG_STATE TP_CNT\n"); +} + +static void ubase_dump_tpg_ctx(struct seq_file *s, struct ubase_dev *udev, u32 idx) +{ + struct ubase_tpg *tpg = &udev->tp_ctx.tpg[idx]; + + seq_printf(s, "%-12u", idx); + seq_printf(s, "%-9u", tpg->mb_tpgn); + seq_printf(s, "%-10u", tpg->tp_shift); + seq_printf(s, "%-10lu", tpg->valid_tp); + seq_printf(s, "%-11u", tpg->start_tpn); + seq_printf(s, "%-11u", tpg->tpg_state); + seq_printf(s, "%-8u", tpg->tp_cnt); + seq_puts(s, "\n"); +} + +enum ubase_dbg_ctx_type { + UBASE_DBG_AEQ_CTX = 0, + UBASE_DBG_CEQ_CTX, + UBASE_DBG_TPG_CTX, + UBASE_DBG_TP_CTX, +}; + +static u32 ubase_get_ctx_num(struct ubase_dev *udev, + enum ubase_dbg_ctx_type ctx_type, u32 ctxgn) +{ + struct ubase_adev_caps *unic_caps = &udev->caps.unic_caps; + u32 ctx_num = 0; + + switch (ctx_type) { + case UBASE_DBG_AEQ_CTX: + ctx_num = udev->caps.dev_caps.num_aeq_vectors; + break; + case UBASE_DBG_CEQ_CTX: + ctx_num = udev->irq_table.ceqs.num; + break; + case UBASE_DBG_TPG_CTX: + ctx_num = unic_caps->tpg.max_cnt; + break; + case UBASE_DBG_TP_CTX: + spin_lock(&udev->tp_ctx.tpg_lock); + if (udev->tp_ctx.tpg) + ctx_num = udev->tp_ctx.tpg[ctxgn].tp_cnt; + spin_unlock(&udev->tp_ctx.tpg_lock); + break; + default: + ubase_err(udev, "failed to get ctx num, ctx_type = %u.\n", + ctx_type); + break; + } + + return ctx_num; +} + +static int ubase_dbg_dump_context(struct seq_file *s, + enum ubase_dbg_ctx_type ctx_type) +{ + struct ubase_dbg_ctx { + void (*print_ctx_titles)(struct seq_file *s); + void (*get_ctx)(struct seq_file *s, struct ubase_dev *udev, u32 idx); + } dbg_ctx[] = { + {ubase_eq_ctx_titles_print, ubase_dump_aeq_ctx}, + {ubase_eq_ctx_titles_print, ubase_dump_ceq_ctx}, + {ubase_tpg_ctx_titles_print, ubase_dump_tpg_ctx}, + }; + struct ubase_dev *udev = dev_get_drvdata(s->private); + struct ubase_adev_caps *unic_caps = &udev->caps.unic_caps; + unsigned long port_bitmap; + u32 tp_pos, i; + + dbg_ctx[ctx_type].print_ctx_titles(s); + + port_bitmap = unic_caps->utp_port_bitmap; + for (i = 0; i < ubase_get_ctx_num(udev, ctx_type, UBASE_DEFAULT_CTXGN); i++) { + if (ctx_type != UBASE_DBG_TP_CTX) { + dbg_ctx[ctx_type].get_ctx(s, udev, i); + continue; + } + + tp_pos = (i % unic_caps->tpg.depth) * UBASE_TP_PORT_BITMAP_STEP; + if (test_bit(tp_pos, &port_bitmap)) + dbg_ctx[ctx_type].get_ctx(s, udev, i); + } + + return 0; +} + +struct ubase_ctx_info { + u32 start_idx; + u32 ctx_size; + u8 op; + const char *ctx_name; +}; + +static inline u32 ubase_get_ctx_group_num(struct ubase_dev *udev, + enum ubase_dbg_ctx_type ctx_type) +{ + if (ctx_type == UBASE_DBG_TP_CTX) + return udev->caps.unic_caps.tpg.max_cnt; + + return 1; +} + +static void ubase_get_ctx_info(struct ubase_dev *udev, + enum ubase_dbg_ctx_type ctx_type, + struct ubase_ctx_info *ctx_info, u32 ctxgn) +{ + switch (ctx_type) { + case UBASE_DBG_AEQ_CTX: + ctx_info->start_idx = 0; + ctx_info->ctx_size = UBASE_AEQ_CTX_SIZE; + ctx_info->op = UBASE_MB_QUERY_AEQ_CONTEXT; + ctx_info->ctx_name = "aeq"; + break; + case UBASE_DBG_CEQ_CTX: + ctx_info->start_idx = 0; + ctx_info->ctx_size = UBASE_CEQ_CTX_SIZE; + ctx_info->op = UBASE_MB_QUERY_CEQ_CONTEXT; + ctx_info->ctx_name = "ceq"; + break; + case UBASE_DBG_TPG_CTX: + ctx_info->start_idx = udev->caps.unic_caps.tpg.start_idx; + ctx_info->ctx_size = udev->ctx_buf.tpg.entry_size; + ctx_info->op = UBASE_MB_QUERY_TPG_CONTEXT; + ctx_info->ctx_name = "tpg"; + break; + case UBASE_DBG_TP_CTX: + spin_lock(&udev->tp_ctx.tpg_lock); + ctx_info->start_idx = udev->tp_ctx.tpg ? + udev->tp_ctx.tpg[ctxgn].start_tpn : 0; + spin_unlock(&udev->tp_ctx.tpg_lock); + + ctx_info->ctx_size = udev->ctx_buf.tp.entry_size; + ctx_info->op = UBASE_MB_QUERY_TP_CONTEXT; + ctx_info->ctx_name = "tp"; + break; + default: + ubase_err(udev, "failed to get ctx info, ctx_type = %u.\n", + ctx_type); + break; + } +} + +static void ubase_mask_eq_ctx_key_words(void *buf) +{ + struct ubase_eq_ctx *eq = (struct ubase_eq_ctx *)buf; + + eq->eqe_base_addr_l = 0; + eq->eqe_base_addr_h = 0; + eq->eqe_token_id = 0; + eq->eqe_token_value = 0; +} + +static void ubase_mask_tp_ctx_key_words(void *buf) +{ + struct ubase_tp_ctx *tp = (struct ubase_tp_ctx *)buf; + + tp->wqe_ba_l = 0; + tp->wqe_ba_h = 0; + tp->tp_wqe_token_id = 0; + tp->reorder_q_addr_l = 0; + tp->reorder_q_addr_h = 0; + tp->scc_token = 0; + tp->scc_token_1 = 0; +} + +static void ubase_mask_ctx_key_words(void *buf, + enum ubase_dbg_ctx_type ctx_type) +{ + switch (ctx_type) { + case UBASE_DBG_AEQ_CTX: + case UBASE_DBG_CEQ_CTX: + ubase_mask_eq_ctx_key_words(buf); + break; + case UBASE_DBG_TPG_CTX: + break; + case UBASE_DBG_TP_CTX: + ubase_mask_tp_ctx_key_words(buf); + break; + default: + break; + } +} static void __ubase_print_context_hw(struct seq_file *s, void *ctx_addr, u32 ctx_len) @@ -29,3 +260,141 @@ void ubase_print_context_hw(struct seq_file *s, void *ctx_addr, u32 ctx_len) __ubase_print_context_hw(s, ctx_addr, ctx_len); } EXPORT_SYMBOL(ubase_print_context_hw); + +static int ubase_dbg_dump_ctx_hw(struct seq_file *s, void *data, + enum ubase_dbg_ctx_type ctx_type) +{ + struct ubase_dev *udev = dev_get_drvdata(s->private); + struct ubase_ctx_info ctx_info = {0}; + struct ubase_cmd_mailbox *mailbox; + u32 max_ctxgn, ctxn, ctxgn; + struct ubase_mbx_attr attr; + int ret = 0; + + if (!test_bit(UBASE_STATE_INITED_B, &udev->state_bits) || + test_bit(UBASE_STATE_RST_HANDLING_B, &udev->state_bits)) + return -EBUSY; + + mailbox = __ubase_alloc_cmd_mailbox(udev); + if (IS_ERR_OR_NULL(mailbox)) { + ubase_err(udev, + "failed to alloc mailbox for dump hw context.\n"); + return -ENOMEM; + } + + max_ctxgn = ubase_get_ctx_group_num(udev, ctx_type); + for (ctxgn = 0; ctxgn < max_ctxgn; ctxgn++) { + ubase_get_ctx_info(udev, ctx_type, &ctx_info, ctxgn); + + for (ctxn = 0; ctxn < ubase_get_ctx_num(udev, ctx_type, ctxgn); ctxn++) { + ubase_fill_mbx_attr(&attr, ctxn + ctx_info.start_idx, + ctx_info.op, 0); + ret = __ubase_hw_upgrade_ctx_ex(udev, &attr, mailbox); + if (ret) { + ubase_err(udev, + "failed to post query %s ctx mbx, ret = %d.\n", + ctx_info.ctx_name, ret); + goto upgrade_ctx_err; + } + + seq_printf(s, "offset\t%s%u\n", ctx_info.ctx_name, + ctxn + ctx_info.start_idx); + ubase_mask_ctx_key_words(mailbox->buf, ctx_type); + __ubase_print_context_hw(s, mailbox->buf, ctx_info.ctx_size); + seq_puts(s, "\n"); + } + } + +upgrade_ctx_err: + __ubase_free_cmd_mailbox(udev, mailbox); + + return ret; +} + +int ubase_dbg_dump_aeq_context(struct seq_file *s, void *data) +{ + return ubase_dbg_dump_context(s, UBASE_DBG_AEQ_CTX); +} + +int ubase_dbg_dump_ceq_context(struct seq_file *s, void *data) +{ + struct ubase_dev *udev = dev_get_drvdata(s->private); + int ret; + + if (!mutex_trylock(&udev->irq_table.ceq_lock)) + return -EBUSY; + + if (!udev->irq_table.ceqs.ceq) { + mutex_unlock(&udev->irq_table.ceq_lock); + return -EBUSY; + } + + ret = ubase_dbg_dump_context(s, UBASE_DBG_CEQ_CTX); + mutex_unlock(&udev->irq_table.ceq_lock); + + return ret; +} + +int ubase_dbg_dump_tpg_ctx(struct seq_file *s, void *data) +{ + struct ubase_dev *udev = dev_get_drvdata(s->private); + int ret; + + if (!test_bit(UBASE_STATE_INITED_B, &udev->state_bits)) + return -EBUSY; + + if (!ubase_get_ctx_num(udev, UBASE_DBG_TPG_CTX, UBASE_DEFAULT_CTXGN)) + return -EOPNOTSUPP; + + if (!spin_trylock(&udev->tp_ctx.tpg_lock)) + return -EBUSY; + + if (!udev->tp_ctx.tpg) { + spin_unlock(&udev->tp_ctx.tpg_lock); + return -EBUSY; + } + + ret = ubase_dbg_dump_context(s, UBASE_DBG_TPG_CTX); + spin_unlock(&udev->tp_ctx.tpg_lock); + + return ret; +} + +int ubase_dbg_dump_tpg_ctx_hw(struct seq_file *s, void *data) +{ + struct ubase_dev *udev = dev_get_drvdata(s->private); + + if (!test_bit(UBASE_STATE_INITED_B, &udev->state_bits)) + return -EBUSY; + + if (!ubase_get_ctx_num(udev, UBASE_DBG_TPG_CTX, UBASE_DEFAULT_CTXGN)) + return -EOPNOTSUPP; + + return ubase_dbg_dump_ctx_hw(s, data, UBASE_DBG_TPG_CTX); +} + +int ubase_dbg_dump_tp_ctx_hw(struct seq_file *s, void *data) +{ + struct ubase_dev *udev = dev_get_drvdata(s->private); + + if (!test_bit(UBASE_STATE_INITED_B, &udev->state_bits)) + return -EBUSY; + + if (!ubase_get_ctx_num(udev, UBASE_DBG_TP_CTX, UBASE_DEFAULT_CTXGN)) + return -EOPNOTSUPP; + + if (!ubase_get_ctx_group_num(udev, UBASE_DBG_TP_CTX)) + return -EOPNOTSUPP; + + return ubase_dbg_dump_ctx_hw(s, data, UBASE_DBG_TP_CTX); +} + +int ubase_dbg_dump_aeq_ctx_hw(struct seq_file *s, void *data) +{ + return ubase_dbg_dump_ctx_hw(s, data, UBASE_DBG_AEQ_CTX); +} + +int ubase_dbg_dump_ceq_ctx_hw(struct seq_file *s, void *data) +{ + return ubase_dbg_dump_ctx_hw(s, data, UBASE_DBG_CEQ_CTX); +} diff --git a/drivers/ub/ubase/debugfs/ubase_ctx_debugfs.h b/drivers/ub/ubase/debugfs/ubase_ctx_debugfs.h new file mode 100644 index 000000000000..532665141fc8 --- /dev/null +++ b/drivers/ub/ubase/debugfs/ubase_ctx_debugfs.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. + * + */ + +#ifndef __UBASE_CTX_DEBUGFS_H__ +#define __UBASE_CTX_DEBUGFS_H__ + +struct device; + +int ubase_dbg_dump_aeq_context(struct seq_file *s, void *data); +int ubase_dbg_dump_ceq_context(struct seq_file *s, void *data); +int ubase_dbg_dump_tpg_ctx(struct seq_file *s, void *data); +int ubase_dbg_dump_tp_ctx_hw(struct seq_file *s, void *data); +int ubase_dbg_dump_tpg_ctx_hw(struct seq_file *s, void *data); +int ubase_dbg_dump_aeq_ctx_hw(struct seq_file *s, void *data); +int ubase_dbg_dump_ceq_ctx_hw(struct seq_file *s, void *data); + +#endif diff --git a/drivers/ub/ubase/debugfs/ubase_debugfs.c b/drivers/ub/ubase/debugfs/ubase_debugfs.c index 56ce970411bd..ab3e1a88ced8 100644 --- a/drivers/ub/ubase/debugfs/ubase_debugfs.c +++ b/drivers/ub/ubase/debugfs/ubase_debugfs.c @@ -8,6 +8,7 @@ #include #include +#include "ubase_ctx_debugfs.h" #include "ubase_dev.h" #include "ubase_hw.h" #include "ubase_qos_debugfs.h" @@ -216,6 +217,11 @@ int ubase_dbg_seq_file_init(struct device *dev, EXPORT_SYMBOL(ubase_dbg_seq_file_init); static struct ubase_dbg_dentry_info ubase_dbg_dentry[] = { + { + .name = "context", + .property = UBASE_SUP_URMA | UBASE_SUP_CDMA | UBASE_SUP_UBL_ETH, + .support = __ubase_dbg_dentry_support, + }, { .name = "qos", .property = UBASE_SUP_URMA | UBASE_SUP_CDMA | UBASE_SUP_UBL_ETH, @@ -242,6 +248,22 @@ static struct ubase_dbg_cmd_info ubase_dbg_cmd[] = { .init = __ubase_dbg_seq_file_init, .read_func = ubase_dbg_dump_rst_info, }, + { + .name = "aeq_context", + .dentry_index = UBASE_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_URMA | UBASE_SUP_CDMA | UBASE_SUP_UBL_ETH, + .support = __ubase_dbg_dentry_support, + .init = __ubase_dbg_seq_file_init, + .read_func = ubase_dbg_dump_aeq_context, + }, + { + .name = "ceq_context", + .dentry_index = UBASE_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_URMA | UBASE_SUP_CDMA | UBASE_SUP_UBL_ETH, + .support = __ubase_dbg_dentry_support, + .init = __ubase_dbg_seq_file_init, + .read_func = ubase_dbg_dump_ceq_context, + }, { .name = "activate_record", .dentry_index = UBASE_DBG_DENTRY_ROOT, @@ -250,6 +272,46 @@ static struct ubase_dbg_cmd_info ubase_dbg_cmd[] = { .init = __ubase_dbg_seq_file_init, .read_func = ubase_dbg_dump_activate_record, }, + { + .name = "tpg_context", + .dentry_index = UBASE_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_URMA | UBASE_SUP_UBL_ETH, + .support = __ubase_dbg_dentry_support, + .init = __ubase_dbg_seq_file_init, + .read_func = ubase_dbg_dump_tpg_ctx, + }, + { + .name = "tp_context_hw", + .dentry_index = UBASE_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_URMA | UBASE_SUP_UBL_ETH, + .support = __ubase_dbg_dentry_support, + .init = __ubase_dbg_seq_file_init, + .read_func = ubase_dbg_dump_tp_ctx_hw, + }, + { + .name = "tpg_context_hw", + .dentry_index = UBASE_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_URMA | UBASE_SUP_UBL_ETH, + .support = __ubase_dbg_dentry_support, + .init = __ubase_dbg_seq_file_init, + .read_func = ubase_dbg_dump_tpg_ctx_hw, + }, + { + .name = "aeq_context_hw", + .dentry_index = UBASE_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_URMA | UBASE_SUP_CDMA | UBASE_SUP_UBL_ETH, + .support = __ubase_dbg_dentry_support, + .init = __ubase_dbg_seq_file_init, + .read_func = ubase_dbg_dump_aeq_ctx_hw, + }, + { + .name = "ceq_context_hw", + .dentry_index = UBASE_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_URMA | UBASE_SUP_CDMA | UBASE_SUP_UBL_ETH, + .support = __ubase_dbg_dentry_support, + .init = __ubase_dbg_seq_file_init, + .read_func = ubase_dbg_dump_ceq_ctx_hw, + }, { .name = "sl_vl_map", .dentry_index = UBASE_DBG_DENTRY_QOS, diff --git a/drivers/ub/ubase/ubase_tp.h b/drivers/ub/ubase/ubase_tp.h index 965535a18f1a..0506e77c98f0 100644 --- a/drivers/ub/ubase/ubase_tp.h +++ b/drivers/ub/ubase/ubase_tp.h @@ -11,8 +11,34 @@ #include "ubase_dev.h" +#define UBASE_TP_PORT_BITMAP_STEP 2 + #define UBASE_WAIT_TP_FLUSH_TOTAL_STEPS 12 +struct ubase_tp_ctx { + u32 rsvd0; + u32 wqe_ba_l; + u32 wqe_ba_h : 20; + u32 rsvd1 : 12; + u32 rsvd2[5]; + u32 rsvd3_0 : 4; + u32 tp_wqe_token_id : 20; + u32 rsvd3_1 : 8; + u32 rsvd4[5]; + u32 rsvd5 : 4; + u32 reorder_q_addr_l : 28; + u32 reorder_q_addr_h : 24; + u32 rsvd6 : 8; + u32 rsvd7[5]; + u32 scc_token : 19; + u32 rsvd8 : 13; + u32 rsvd9[4]; + u32 rsvd10_0 : 24; + u32 scc_token_1 : 4; + u32 rsvd10_1 : 4; + u32 rsvd11[37]; +}; + struct ubase_tpg { u32 mb_tpgn; u8 tpg_state; -- Gitee From a82a88a5180ab2f30333b11a636081c06112c05f Mon Sep 17 00:00:00 2001 From: Xiongchuan Zhou Date: Wed, 29 Oct 2025 16:53:51 +0800 Subject: [PATCH 004/103] ub: ubase: Supports the query of UBCL config. commit 8a2d8b74eb75df90052e3baad58e645aa0706b7f openEuler UBCL config file is a binary file. The file content determines the configuration of the UB system and deeply affects the running of it. If the file can be read conveniently and effectively, the maintenance capability of the system will be greatly improved. This patch allows the UBASE driver to read the content of UBCL config through debugfs. Users can use debugfs to read the file. Signed-off-by: Yixi Shen Signed-off-by: Haibin Lu Signed-off-by: Xiongchuan Zhou Signed-off-by: huwentao --- drivers/ub/ubase/debugfs/ubase_debugfs.c | 88 ++++++++++++++++++++++++ drivers/ub/ubase/ubase_cmd.h | 10 +++ include/ub/ubase/ubase_comm_cmd.h | 1 + 3 files changed, 99 insertions(+) diff --git a/drivers/ub/ubase/debugfs/ubase_debugfs.c b/drivers/ub/ubase/debugfs/ubase_debugfs.c index ab3e1a88ced8..76175d604366 100644 --- a/drivers/ub/ubase/debugfs/ubase_debugfs.c +++ b/drivers/ub/ubase/debugfs/ubase_debugfs.c @@ -8,6 +8,7 @@ #include #include +#include "ubase_cmd.h" #include "ubase_ctx_debugfs.h" #include "ubase_dev.h" #include "ubase_hw.h" @@ -31,6 +32,85 @@ static int ubase_dbg_dump_rst_info(struct seq_file *s, void *data) return 0; } +static int ubase_query_ubcl_config(struct ubase_dev *udev, u16 offset, + u16 is_query, u16 size, + struct ubase_ubcl_config_cmd *resp) +{ + struct ubase_ubcl_config_cmd req; + struct ubase_cmd_buf in, out; + int ret; + + memset(resp, 0, sizeof(*resp)); + memset(&req, 0, sizeof(req)); + req.offset = cpu_to_le16(offset); + req.size = cpu_to_le16(size); + req.is_query_size = cpu_to_le16(is_query); + + __ubase_fill_inout_buf(&in, UBASE_OPC_QUERY_UBCL_CONFIG, true, + sizeof(req), &req); + __ubase_fill_inout_buf(&out, UBASE_OPC_QUERY_UBCL_CONFIG, true, + sizeof(*resp), resp); + ret = __ubase_cmd_send_inout(udev, &in, &out); + if (ret && ret != -EPERM) + ubase_err(udev, "failed to query UBCL_config, ret = %d.\n", ret); + + if (ret == -EPERM) + return -EOPNOTSUPP; + + return ret; +} + +static void ubase_dbg_fill_ubcl_content(struct ubase_ubcl_config_cmd *resp, + u32 *addr, struct seq_file *s) +{ + int i, j; + + for (i = 0; i < UBASE_UBCL_CFG_DATA_NUM; i += UBASE_UBCL_CFG_DATA_ALIGN) { + seq_printf(s, "%08X: ", (*addr * UBASE_UBCL_CFG_DATA_ALIGN)); + for (j = 0; j < UBASE_UBCL_CFG_DATA_ALIGN; j++) + seq_printf(s, "%08X ", resp->data[i + j]); + seq_puts(s, "\n"); + + *addr += UBASE_UBCL_CFG_DATA_ALIGN; + if ((i * sizeof(u32)) >= resp->size) + break; + } +} + +static int ubase_dbg_dump_ubcl_config(struct seq_file *s, void *data) +{ + struct ubase_dev *udev = dev_get_drvdata(s->private); + struct ubase_ubcl_config_cmd resp = {0}; + u16 read_size = sizeof(resp.data); + u16 offset = 0; + u16 total_size; + u32 addr = 0; + int ret; + + if (!test_bit(UBASE_STATE_INITED_B, &udev->state_bits) || + test_bit(UBASE_STATE_RST_HANDLING_B, &udev->state_bits)) + return -EBUSY; + + ret = ubase_query_ubcl_config(udev, offset, 1, 0, &resp); + if (ret) + return ret; + total_size = le16_to_cpu(resp.size); + + seq_puts(s, "UBCL_config:\n"); + seq_printf(s, "total_size: %u\n", total_size); + while (offset < total_size) { + read_size = min(read_size, total_size - offset); + ret = ubase_query_ubcl_config(udev, offset, 0, read_size, &resp); + if (ret) + return ret; + offset += le16_to_cpu(resp.size); + + ubase_dbg_fill_ubcl_content(&resp, &addr, s); + } + + return 0; +} + static int ubase_dbg_dump_activate_record(struct seq_file *s, void *data) { struct ubase_dev *udev = dev_get_drvdata(s->private); @@ -264,6 +344,14 @@ static struct ubase_dbg_cmd_info ubase_dbg_cmd[] = { .init = __ubase_dbg_seq_file_init, .read_func = ubase_dbg_dump_ceq_context, }, + { + .name = "UBCL_config", + .dentry_index = UBASE_DBG_DENTRY_ROOT, + .property = UBASE_SUP_URMA | UBASE_SUP_CDMA | UBASE_SUP_UBL_ETH, + .support = __ubase_dbg_dentry_support, + .init = __ubase_dbg_seq_file_init, + .read_func = ubase_dbg_dump_ubcl_config, + }, { .name = "activate_record", .dentry_index = UBASE_DBG_DENTRY_ROOT, diff --git a/drivers/ub/ubase/ubase_cmd.h b/drivers/ub/ubase/ubase_cmd.h index 0187597493b7..63b67179f2fb 100644 --- a/drivers/ub/ubase/ubase_cmd.h +++ b/drivers/ub/ubase/ubase_cmd.h @@ -49,6 +49,16 @@ struct ubase_query_version_cmd { __le32 caps[UBASE_CAP_LEN]; }; +#define UBASE_UBCL_CFG_DATA_ALIGN 4 +#define UBASE_UBCL_CFG_DATA_NUM 60 +struct ubase_ubcl_config_cmd { + __le16 is_query_size; + __le16 offset; + __le16 size; + __le16 rsv; + __le32 data[UBASE_UBCL_CFG_DATA_NUM]; +}; + enum ubase_ue2ue_sub_cmd { UBASE_UE2UE_CTRLQ_MSG = 3, }; diff --git a/include/ub/ubase/ubase_comm_cmd.h b/include/ub/ubase/ubase_comm_cmd.h index 7e78860d7778..311a309d10bd 100644 --- a/include/ub/ubase/ubase_comm_cmd.h +++ b/include/ub/ubase/ubase_comm_cmd.h @@ -37,6 +37,7 @@ enum ubase_opcode_type { UBASE_OPC_QUERY_NET_GUID = 0x0035, UBASE_OPC_STATS_MAC_ALL = 0x0038, UBASE_OPC_QUERY_BUS_EID = 0x0047, + UBASE_OPC_QUERY_UBCL_CONFIG = 0x0050, /* NL commands */ UBASE_OPC_CFG_VL_MAP = 0x2206, -- Gitee From 1976d974ef39c2ec9719245c91142fac826a0f9b Mon Sep 17 00:00:00 2001 From: Xiongchuan Zhou Date: Wed, 29 Oct 2025 16:58:25 +0800 Subject: [PATCH 005/103] ub: ubase: Support querying dev caps. commit 7bb0989aa20b20df97785020ba318a0fc5915d37 openEuler The UB driver supports a set of code running in different business contexts. The ub driver uses dev caps to distinguish different contexts. Therefore, the debugging method of dev caps is important. This patch allows the UBASE driver to print dev caps for users. Users can use this function through debugfs. Signed-off-by: Yaoyao Tu Signed-off-by: Fengyan Mu Signed-off-by: Haibin Lu Signed-off-by: Xiongchuan Zhou Signed-off-by: huwentao --- drivers/ub/ubase/debugfs/ubase_debugfs.c | 157 +++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/drivers/ub/ubase/debugfs/ubase_debugfs.c b/drivers/ub/ubase/debugfs/ubase_debugfs.c index 76175d604366..ad97d7a58188 100644 --- a/drivers/ub/ubase/debugfs/ubase_debugfs.c +++ b/drivers/ub/ubase/debugfs/ubase_debugfs.c @@ -32,6 +32,154 @@ static int ubase_dbg_dump_rst_info(struct seq_file *s, void *data) return 0; } +static void ubase_dbg_dump_caps_bits(struct seq_file *s, struct ubase_dev *udev) +{ +#define CAP_FMT(name) "\tsupport_" #name ": %d\n" +#define PTRINT_CAP(name, func) seq_printf(s, CAP_FMT(name), func(udev)) + + PTRINT_CAP(ub_link, ubase_dev_ubl_supported); + PTRINT_CAP(ta_extdb_buffer_config, ubase_dev_ta_extdb_buf_supported); + PTRINT_CAP(ta_timer_buffer_config, ubase_dev_ta_timer_buf_supported); + PTRINT_CAP(err_handle, ubase_dev_err_handle_supported); + PTRINT_CAP(ctrlq, ubase_dev_ctrlq_supported); + PTRINT_CAP(eth_mac, ubase_dev_eth_mac_supported); + PTRINT_CAP(mac_stats, ubase_dev_mac_stats_supported); + PTRINT_CAP(prealloc, __ubase_dev_prealloc_supported); + PTRINT_CAP(udma, ubase_dev_udma_supported); + PTRINT_CAP(unic, ubase_dev_unic_supported); + PTRINT_CAP(uvb, ubase_dev_uvb_supported); + PTRINT_CAP(ip_over_urma, ubase_ip_over_urma_supported); + if (ubase_ip_over_urma_supported(udev)) + PTRINT_CAP(ip_over_urma_utp, ubase_ip_over_urma_utp_supported); + PTRINT_CAP(activate_proxy, ubase_activate_proxy_supported); + PTRINT_CAP(utp, ubase_utp_supported); +} + +static void ubase_dbg_dump_caps_info(struct seq_file *s, struct ubase_dev *udev) +{ + struct ubase_caps *dev_caps = &udev->caps.dev_caps; + struct ubase_dbg_common_caps_info { + const char *format; + u64 caps_info; + } ubase_common_caps_info[] = { + {"\tnum_ceq_vectors: %u\n", dev_caps->num_ceq_vectors}, + {"\tnum_aeq_vectors: %u\n", dev_caps->num_aeq_vectors}, + {"\tnum_misc_vectors: %u\n", dev_caps->num_misc_vectors}, + {"\taeqe_size: %u\n", dev_caps->aeqe_size}, + {"\tceqe_size: %u\n", dev_caps->ceqe_size}, + {"\taeqe_depth: %u\n", dev_caps->aeqe_depth}, + {"\tceqe_depth: %u\n", dev_caps->ceqe_depth}, + {"\ttotal_ue_num: %u\n", dev_caps->total_ue_num}, + {"\tta_extdb_buf_size: %llu\n", udev->ta_ctx.extdb_buf.size}, + {"\tta_timer_buf_size: %llu\n", udev->ta_ctx.timer_buf.size}, + {"\tpublic_jetty_cnt: %u\n", dev_caps->public_jetty_cnt}, + {"\tvl_num: %hhu\n", dev_caps->vl_num}, + {"\trsvd_jetty_cnt: %hu\n", dev_caps->rsvd_jetty_cnt}, + {"\tpacket_pattern_mode: %u\n", dev_caps->packet_pattern_mode}, + {"\tack_queue_num: %u\n", dev_caps->ack_queue_num}, + {"\toor_en: %u\n", dev_caps->oor_en}, + {"\treorder_queue_en: %u\n", dev_caps->reorder_queue_en}, + {"\ton_flight_size: %u\n", dev_caps->on_flight_size}, + {"\treorder_cap: %u\n", dev_caps->reorder_cap}, + {"\treorder_queue_shift: %u\n", dev_caps->reorder_queue_shift}, + {"\tat_times: %u\n", dev_caps->at_times}, + {"\tue_num: %u\n", dev_caps->ue_num}, + {"\tmac_stats_num: %u\n", dev_caps->mac_stats_num}, + {"\tlogic_port_bitmap: 0x%x\n", dev_caps->logic_port_bitmap}, + {"\tub_port_logic_id: %u\n", dev_caps->ub_port_logic_id}, + {"\tio_port_logic_id: %u\n", dev_caps->io_port_logic_id}, + {"\tio_port_id: %u\n", dev_caps->io_port_id}, + {"\tnl_port_id: %u\n", dev_caps->nl_port_id}, + {"\tchip_id: %u\n", dev_caps->chip_id}, + {"\tdie_id: %u\n", dev_caps->die_id}, + {"\tue_id: %u\n", dev_caps->ue_id}, + {"\tnl_id: %u\n", dev_caps->nl_id}, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(ubase_common_caps_info); i++) + seq_printf(s, ubase_common_caps_info[i].format, + ubase_common_caps_info[i].caps_info); +} + +static void ubase_dbg_dump_common_caps(struct seq_file *s, struct ubase_dev *udev) +{ + struct ubase_caps *dev_caps = &udev->caps.dev_caps; + + ubase_dbg_dump_caps_info(s, udev); + + seq_puts(s, "\treq_vl:"); + ubase_dbg_dump_arr_info(s, dev_caps->req_vl, dev_caps->vl_num); + + seq_puts(s, "\tresp_vl:"); + ubase_dbg_dump_arr_info(s, dev_caps->resp_vl, dev_caps->vl_num); +} + +static void ubase_dbg_dump_adev_caps(struct seq_file *s, + struct ubase_adev_caps *caps) +{ + struct ubase_dbg_adev_caps_info { + const char *format; + u32 caps_info; + } ubase_adev_caps_info[] = { + {"\tjfs_max_cnt: %u\n", caps->jfs.max_cnt}, + {"\tjfs_reserved_cnt: %u\n", caps->jfs.reserved_cnt}, + {"\tjfs_depth: %u\n", caps->jfs.depth}, + {"\tjfr_max_cnt: %u\n", caps->jfr.max_cnt}, + {"\tjfr_reserved_cnt: %u\n", caps->jfr.reserved_cnt}, + {"\tjfr_depth: %u\n", caps->jfr.depth}, + {"\tjfc_max_cnt: %u\n", caps->jfc.max_cnt}, + {"\tjfc_reserved_cnt: %u\n", caps->jfc.reserved_cnt}, + {"\tjfc_depth: %u\n", caps->jfc.depth}, + {"\ttp_max_cnt: %u\n", caps->tp.max_cnt}, + {"\ttp_reserved_cnt: %u\n", caps->tp.reserved_cnt}, + {"\ttp_depth: %u\n", caps->tp.depth}, + {"\ttpg_max_cnt: %u\n", caps->tpg.max_cnt}, + {"\ttpg_reserved_cnt: %u\n", caps->tpg.reserved_cnt}, + {"\ttpg_depth: %u\n", caps->tpg.depth}, + {"\tcqe_size: %hu\n", caps->cqe_size}, + {"\tutp_port_bitmap: 0x%x\n", caps->utp_port_bitmap}, + {"\tjtg_max_cnt: %u\n", caps->jtg_max_cnt}, + {"\trc_max_cnt: %u\n", caps->rc_max_cnt}, + {"\trc_depth: %u\n", caps->rc_que_depth}, + {"\tccc_max_cnt: %u\n", caps->ccc_max_cnt}, + {"\tdest_addr_max_cnt: %u\n", caps->dest_addr_max_cnt}, + {"\tseid_upi_max_cnt: %u\n", caps->seid_upi_max_cnt}, + {"\ttpm_max_cnt: %u\n", caps->tpm_max_cnt}, + {"\tprealloc_mem_dma_len: %llu\n", caps->pmem.dma_len}, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(ubase_adev_caps_info); i++) + seq_printf(s, ubase_adev_caps_info[i].format, + ubase_adev_caps_info[i].caps_info); +} + +static int ubase_dbg_dump_dev_caps(struct seq_file *s, void *data) +{ + struct ubase_dev *udev = dev_get_drvdata(s->private); + struct ubase_dev_caps *udev_caps = &udev->caps; + + seq_puts(s, "CAP_BITS:\n"); + ubase_dbg_dump_caps_bits(s, udev); + seq_puts(s, "\nCOMMON_CAPS:\n"); + ubase_dbg_dump_common_caps(s, udev); + + if (ubase_dev_pmu_supported(udev)) + return 0; + + seq_puts(s, "\nUNIC_CAPS:\n"); + ubase_dbg_dump_adev_caps(s, &udev_caps->unic_caps); + + if (ubase_dev_cdma_supported(udev)) + seq_puts(s, "\nCDMA_CAPS:\n"); + else + seq_puts(s, "\nUDMA_CAPS:\n"); + ubase_dbg_dump_adev_caps(s, &udev_caps->udma_caps); + + return 0; +} + static int ubase_query_ubcl_config(struct ubase_dev *udev, u16 offset, u16 is_query, u16 size, struct ubase_ubcl_config_cmd *resp) @@ -344,6 +492,15 @@ static struct ubase_dbg_cmd_info ubase_dbg_cmd[] = { .init = __ubase_dbg_seq_file_init, .read_func = ubase_dbg_dump_ceq_context, }, + { + .name = "caps_info", + .dentry_index = UBASE_DBG_DENTRY_ROOT, + .property = UBASE_SUP_URMA | UBASE_SUP_CDMA | UBASE_SUP_PMU | + UBASE_SUP_UBL_ETH, + .support = __ubase_dbg_dentry_support, + .init = __ubase_dbg_seq_file_init, + .read_func = ubase_dbg_dump_dev_caps, + }, { .name = "UBCL_config", .dentry_index = UBASE_DBG_DENTRY_ROOT, -- Gitee From 218499157ff747c9e3b2e2bb2b832ae4b8159bbf Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Thu, 30 Oct 2025 21:30:51 +0800 Subject: [PATCH 006/103] ub: cdma: support the probe and remove processes commit 24c71ca3842ca57c683837dd4fc18ae0637dde9d openEuler This patch implements the probe and remove processes for auxiliary bus driver devices in the CDMA driver. The implementation includes device creation and initialization, adding the device to the device list, querying the device's eid and upi, and the open, close, and ioctl processes for the device file. Signed-off-by: Zhipeng Lu Signed-off-by: Hongwu Wang Signed-off-by: zhaolichang <943677312@qq.com> --- arch/arm64/configs/tencent.config | 3 + drivers/ub/Kconfig | 1 + drivers/ub/Makefile | 1 + drivers/ub/cdma/Kconfig | 10 ++ drivers/ub/cdma/Makefile | 5 + drivers/ub/cdma/cdma.h | 113 ++++++++++++++++++ drivers/ub/cdma/cdma_chardev.c | 188 +++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_chardev.h | 19 +++ drivers/ub/cdma/cdma_cmd.c | 190 ++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_cmd.h | 79 +++++++++++++ drivers/ub/cdma/cdma_dev.c | 186 +++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_dev.h | 19 +++ drivers/ub/cdma/cdma_ioctl.c | 31 +++++ drivers/ub/cdma/cdma_ioctl.h | 12 ++ drivers/ub/cdma/cdma_main.c | 146 +++++++++++++++++++++++ drivers/ub/cdma/cdma_tid.c | 89 ++++++++++++++ drivers/ub/cdma/cdma_tid.h | 16 +++ drivers/ub/cdma/cdma_types.h | 19 +++ include/uapi/ub/cdma/cdma_abi.h | 61 ++++++++++ include/ub/cdma/cdma_api.h | 16 +++ 20 files changed, 1204 insertions(+) create mode 100644 drivers/ub/cdma/Kconfig create mode 100644 drivers/ub/cdma/Makefile create mode 100644 drivers/ub/cdma/cdma.h create mode 100644 drivers/ub/cdma/cdma_chardev.c create mode 100644 drivers/ub/cdma/cdma_chardev.h create mode 100644 drivers/ub/cdma/cdma_cmd.c create mode 100644 drivers/ub/cdma/cdma_cmd.h create mode 100644 drivers/ub/cdma/cdma_dev.c create mode 100644 drivers/ub/cdma/cdma_dev.h create mode 100644 drivers/ub/cdma/cdma_ioctl.c create mode 100644 drivers/ub/cdma/cdma_ioctl.h create mode 100644 drivers/ub/cdma/cdma_main.c create mode 100644 drivers/ub/cdma/cdma_tid.c create mode 100644 drivers/ub/cdma/cdma_tid.h create mode 100644 drivers/ub/cdma/cdma_types.h create mode 100644 include/uapi/ub/cdma/cdma_abi.h create mode 100644 include/ub/cdma/cdma_api.h diff --git a/arch/arm64/configs/tencent.config b/arch/arm64/configs/tencent.config index a8f6f34cdee6..b806c4dc225c 100644 --- a/arch/arm64/configs/tencent.config +++ b/arch/arm64/configs/tencent.config @@ -1834,6 +1834,9 @@ CONFIG_UB_UBL=m CONFIG_UB_UNIC=m CONFIG_UB_UNIC_UBL=y CONFIG_UB_UNIC_DCB=y + +# UB CDMA driver +CONFIG_UB_CDMA=m # end of unified bus # UMMU diff --git a/drivers/ub/Kconfig b/drivers/ub/Kconfig index 0b7cb0ef16cf..6197483bd71e 100644 --- a/drivers/ub/Kconfig +++ b/drivers/ub/Kconfig @@ -16,6 +16,7 @@ if UB source "drivers/ub/ubus/Kconfig" source "drivers/ub/ubfi/Kconfig" source "drivers/ub/ubase/Kconfig" +source "drivers/ub/cdma/Kconfig" source "drivers/ub/obmm/Kconfig" source "drivers/ub/sentry/Kconfig" config UB_URMA diff --git a/drivers/ub/Makefile b/drivers/ub/Makefile index d1dd2267abe0..2a40689dafac 100644 --- a/drivers/ub/Makefile +++ b/drivers/ub/Makefile @@ -4,5 +4,6 @@ obj-y += ubus/ obj-y += ubfi/ obj-$(CONFIG_UB_URMA) += urma/ obj-$(CONFIG_UB_UBASE) += ubase/ +obj-$(CONFIG_UB_CDMA) += cdma/ obj-y += obmm/ obj-$(CONFIG_UB_SENTRY) += sentry/ diff --git a/drivers/ub/cdma/Kconfig b/drivers/ub/cdma/Kconfig new file mode 100644 index 000000000000..b09e13215852 --- /dev/null +++ b/drivers/ub/cdma/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0+ +menuconfig UB_CDMA + default n + tristate "cdma driver" + depends on UB_UBASE && UB_UMMU_CORE + help + This option enables support for CDMA drivers. The CDMA driver facilitates + the creation and destruction of CDMA devices, as well as the creation of + resources within CDMA devices to perform DMA read/write tasks and retrieve + the completion status of executed tasks. diff --git a/drivers/ub/cdma/Makefile b/drivers/ub/cdma/Makefile new file mode 100644 index 000000000000..7375c6a08738 --- /dev/null +++ b/drivers/ub/cdma/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ + +cdma-$(CONFIG_UB_CDMA) := cdma_main.o cdma_dev.o cdma_chardev.o cdma_cmd.o cdma_tid.o cdma_ioctl.o + +obj-m += cdma.o diff --git a/drivers/ub/cdma/cdma.h b/drivers/ub/cdma/cdma.h new file mode 100644 index 000000000000..af45096026ee --- /dev/null +++ b/drivers/ub/cdma/cdma.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_H__ +#define __CDMA_H__ + +#include +#include +#include +#include + +#include + +#define CDMA_RESET_WAIT_TIME 3000 +#define CDMA_MAX_SL_NUM 16 + +#define CDMA_UPI_MASK 0x7FFF + +struct cdma_res { + u32 max_cnt; + u32 start_idx; + u32 depth; +}; + +struct cdma_oor_caps { + bool oor_en; + bool reorder_queue_en; + u8 reorder_cap; + u8 reorder_queue_shift; + u8 at_times; + u16 on_flight_size; +}; + +struct cdma_tbl { + u32 max_cnt; + u32 size; +}; + +struct cdma_caps { + struct cdma_res jfs; + struct cdma_res jfce; + struct cdma_res jfc; + struct cdma_res queue; + u32 jfs_sge; + u32 jfr_sge; + u32 jfs_rsge; + u32 jfs_inline_sz; + u32 comp_vector_cnt; + u32 eid_num; + u16 ue_cnt; + u8 ue_id; + u32 rc_outstd_cnt; + u32 utp_cnt; + u32 trans_mode; + u32 ta_version; + u32 tp_version; + u32 max_msg_len; + u32 feature; + u32 public_jetty_cnt; + u32 rsvd_jetty_cnt; + u16 cons_ctrl_alg; + u16 rc_queue_num; + u16 rc_queue_depth; + u8 rc_entry_size; + u8 packet_pattern_mode; + u8 ack_queue_num; + u8 port_num; + u8 cqe_size; + u8 cc_priority_cnt; + bool virtualization; + struct cdma_oor_caps oor_caps; + struct cdma_tbl src_addr; + struct cdma_tbl seid; +}; + +struct cdma_chardev { + struct device *dev; + +#define CDMA_NAME_LEN 16 + char name[CDMA_NAME_LEN]; + struct cdev cdev; + int dev_num; + dev_t devno; +}; + +struct cdma_dev { + struct dma_device base; + struct device *dev; + struct auxiliary_device *adev; + struct cdma_chardev chardev; + struct cdma_caps caps; + + u32 eid; + u32 upi; + u32 tid; + u32 ummu_tid; + u32 status; + u8 sl_num; + u8 sl[CDMA_MAX_SL_NUM]; + + void __iomem *k_db_base; + resource_size_t db_base; + struct iommu_sva *ksva; + struct mutex eu_mutex; + struct mutex db_mutex; + struct list_head db_page; + + struct mutex file_mutex; + struct list_head file_list; + struct page *arm_db_page; +}; + +#endif /* _CDMA_H_ */ diff --git a/drivers/ub/cdma/cdma_chardev.c b/drivers/ub/cdma/cdma_chardev.c new file mode 100644 index 000000000000..094a71cbc531 --- /dev/null +++ b/drivers/ub/cdma/cdma_chardev.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define pr_fmt(fmt) "CDMA: " fmt +#define dev_fmt pr_fmt + +#include +#include +#include "cdma_ioctl.h" +#include "cdma_chardev.h" +#include "cdma_types.h" +#include "cdma.h" + +#define CDMA_DEVICE_NAME "cdma/dev" + +struct cdma_num_manager { + struct idr idr; + spinlock_t lock; +}; + +static struct cdma_num_manager cdma_num_mg = { + .idr = IDR_INIT(cdma_num_mg.idr), + .lock = __SPIN_LOCK_UNLOCKED(cdma_num_mg.lock), +}; + +static void cdma_num_free(struct cdma_dev *cdev) +{ + spin_lock(&cdma_num_mg.lock); + idr_remove(&cdma_num_mg.idr, cdev->chardev.dev_num); + spin_unlock(&cdma_num_mg.lock); +} + +static int cdma_num_alloc(struct cdma_dev *cdev) +{ +#define CDMA_START 0 +#define CDMA_END 0xffff + int id; + + idr_preload(GFP_KERNEL); + spin_lock(&cdma_num_mg.lock); + id = idr_alloc(&cdma_num_mg.idr, cdev, CDMA_START, CDMA_END, GFP_NOWAIT); + spin_unlock(&cdma_num_mg.lock); + idr_preload_end(); + + return id; +} + +static long cdma_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ +#define CDMA_MAX_CMD_SIZE 8192 + struct cdma_file *cfile = (struct cdma_file *)file->private_data; + struct cdma_ioctl_hdr hdr = { 0 }; + int ret; + + if (cmd == CDMA_SYNC) { + ret = copy_from_user(&hdr, (void *)arg, sizeof(hdr)); + if (ret || hdr.args_len > CDMA_MAX_CMD_SIZE) { + pr_err("copy user ret = %d, input parameter len = %u.\n", + ret, hdr.args_len); + return -EINVAL; + } + ret = cdma_cmd_parse(cfile, &hdr); + return ret; + } + + pr_err("invalid ioctl command, command = %u.\n", cmd); + return -ENOIOCTLCMD; +} + +static int cdma_open(struct inode *inode, struct file *file) +{ + struct cdma_chardev *chardev; + struct cdma_file *cfile; + struct cdma_dev *cdev; + + chardev = container_of(inode->i_cdev, struct cdma_chardev, cdev); + cdev = container_of(chardev, struct cdma_dev, chardev); + + cfile = kzalloc(sizeof(struct cdma_file), GFP_KERNEL); + if (!cfile) + return -ENOMEM; + + mutex_lock(&cdev->file_mutex); + cfile->cdev = cdev; + kref_init(&cfile->ref); + file->private_data = cfile; + list_add_tail(&cfile->list, &cdev->file_list); + nonseekable_open(inode, file); + mutex_unlock(&cdev->file_mutex); + + return 0; +} + +static int cdma_close(struct inode *inode, struct file *file) +{ + struct cdma_file *cfile = (struct cdma_file *)file->private_data; + struct cdma_dev *cdev; + + cdev = cfile->cdev; + + mutex_lock(&cdev->file_mutex); + list_del(&cfile->list); + mutex_unlock(&cdev->file_mutex); + + kref_put(&cfile->ref, cdma_release_file); + pr_debug("cdma close success.\n"); + + return 0; +} + +static const struct file_operations cdma_ops = { + .owner = THIS_MODULE, + .unlocked_ioctl = cdma_ioctl, + .open = cdma_open, + .release = cdma_close, +}; + +void cdma_destroy_chardev(struct cdma_dev *cdev) +{ + struct cdma_chardev *chardev = &cdev->chardev; + + if (!chardev->dev) + return; + + device_destroy(cdma_cdev_class, chardev->devno); + cdev_del(&chardev->cdev); + unregister_chrdev_region(chardev->devno, CDMA_MAX_DEVICES); + cdma_num_free(cdev); +} + +int cdma_create_chardev(struct cdma_dev *cdev) +{ + struct cdma_chardev *chardev = &cdev->chardev; + int ret; + + chardev->dev_num = cdma_num_alloc(cdev); + if (chardev->dev_num < 0) { + dev_err(cdev->dev, "alloc dev_num failed, ret = %d\n", chardev->dev_num); + return -ENOMEM; + } + + ret = snprintf(chardev->name, sizeof(chardev->name), + "%s.%d", CDMA_DEVICE_NAME, chardev->dev_num); + if (ret < 0) { + dev_err(cdev->dev, "sprintf failed in create cdma chardev\n"); + goto num_free; + } + + ret = alloc_chrdev_region(&chardev->devno, 0, CDMA_MAX_DEVICES, + chardev->name); + if (ret) { + dev_err(cdev->dev, "alloc chrdev region failed, ret = %d\n", ret); + goto num_free; + } + + cdev_init(&chardev->cdev, &cdma_ops); + ret = cdev_add(&chardev->cdev, chardev->devno, CDMA_MAX_DEVICES); + if (ret) { + dev_err(cdev->dev, "cdev add failed, ret = %d\n", ret); + goto chrdev_unregister; + } + + chardev->dev = device_create(cdma_cdev_class, NULL, chardev->devno, + NULL, chardev->name); + if (IS_ERR(chardev->dev)) { + ret = PTR_ERR(chardev->dev); + dev_err(cdev->dev, "create device failed, ret = %d\n", ret); + goto cdev_delete; + } + + dev_dbg(cdev->dev, "create chardev: %s succeeded\n", chardev->name); + return 0; + +cdev_delete: + cdev_del(&chardev->cdev); +chrdev_unregister: + unregister_chrdev_region(chardev->devno, CDMA_MAX_DEVICES); +num_free: + cdma_num_free(cdev); + return ret; +} + +void cdma_release_file(struct kref *ref) +{ + struct cdma_file *cfile = container_of(ref, struct cdma_file, ref); + + kfree(cfile); +} diff --git a/drivers/ub/cdma/cdma_chardev.h b/drivers/ub/cdma/cdma_chardev.h new file mode 100644 index 000000000000..5366dd77ea54 --- /dev/null +++ b/drivers/ub/cdma/cdma_chardev.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_CHARDEV_H__ +#define __CDMA_CHARDEV_H__ + +#define CDMA_TEST_NAME "cdma_dev" +#define CDMA_MAX_DEVICES 1 +#define CDMA_JETTY_DSQE_OFFSET 0x1000 + +extern struct class *cdma_cdev_class; + +struct cdma_dev; + +void cdma_destroy_chardev(struct cdma_dev *cdev); +int cdma_create_chardev(struct cdma_dev *cdev); +void cdma_release_file(struct kref *ref); + +#endif /* _CDMA_CHARDEV_H_ */ diff --git a/drivers/ub/cdma/cdma_cmd.c b/drivers/ub/cdma/cdma_cmd.c new file mode 100644 index 000000000000..80ab8791b018 --- /dev/null +++ b/drivers/ub/cdma/cdma_cmd.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include +#include + +#include "cdma.h" +#include +#include +#include +#include "cdma_cmd.h" + +static int cdma_cmd_query_fw_resource(struct cdma_dev *cdev, struct cdma_ue_info *out_addr) +{ +#define CDMA_QUERY_UE_RES 0x0004 + struct ubase_cmd_buf out = { 0 }; + struct ubase_cmd_buf in = { 0 }; + + ubase_fill_inout_buf(&in, CDMA_QUERY_UE_RES, true, 0, NULL); + ubase_fill_inout_buf(&out, CDMA_QUERY_UE_RES, true, + sizeof(*out_addr), out_addr); + + return ubase_cmd_send_inout(cdev->adev, &in, &out); +} + +static int cdma_query_caps_from_firmware(struct cdma_dev *cdev) +{ + struct cdma_caps *caps = &cdev->caps; + struct cdma_ue_info cmd = { 0 }; + int ret; + + ret = cdma_cmd_query_fw_resource(cdev, &cmd); + if (ret) + return dev_err_probe(cdev->dev, ret, "query fw resource failed\n"); + + caps->jfs_sge = cmd.jfs_sge; + caps->trans_mode = cmd.trans_mode; + caps->seid.max_cnt = cmd.seid_upi_tbl_num; + caps->feature = cmd.cap_info; + caps->ue_cnt = cmd.ue_cnt; + caps->ue_id = cmd.ue_id; + + dev_dbg(cdev->dev, "jfs_sge = 0x%x, trans_mode = 0x%x, seid.max_cnt = 0x%x\n", + caps->jfs_sge, caps->trans_mode, caps->seid.max_cnt); + dev_dbg(cdev->dev, "feature = 0x%x, ue_cnt = 0x%x, ue_id = 0x%x\n", + caps->feature, caps->ue_cnt, caps->ue_id); + + return 0; +} + +static int cdma_set_caps_from_adev_caps(struct cdma_dev *cdev) +{ +#define MAX_WQEBB_IN_SQE 4 + struct cdma_caps *caps = &cdev->caps; + struct ubase_adev_caps *adev_caps; + + adev_caps = ubase_get_cdma_caps(cdev->adev); + if (!adev_caps) { + dev_err(cdev->dev, "get cdma adev caps failed\n"); + return -EINVAL; + } + + caps->jfs.max_cnt = adev_caps->jfs.max_cnt; + caps->jfs.depth = adev_caps->jfs.depth / MAX_WQEBB_IN_SQE; + caps->jfs.start_idx = adev_caps->jfs.start_idx; + caps->jfc.max_cnt = adev_caps->jfc.max_cnt; + caps->jfc.depth = adev_caps->jfc.depth; + caps->jfc.start_idx = adev_caps->jfc.start_idx; + caps->cqe_size = adev_caps->cqe_size; + + return 0; +} + +static int cdma_set_caps_from_ubase_caps(struct cdma_dev *cdev) +{ + struct cdma_caps *caps = &cdev->caps; + struct ubase_caps *ubase_caps; + + ubase_caps = ubase_get_dev_caps(cdev->adev); + if (!ubase_caps) { + dev_err(cdev->dev, "get cdma ubase caps failed\n"); + return -EINVAL; + } + + caps->comp_vector_cnt = ubase_caps->num_ceq_vectors; + caps->public_jetty_cnt = ubase_caps->public_jetty_cnt; + cdev->eid = ubase_caps->eid; + cdev->upi = ubase_caps->upi; + + return 0; +} + +int cdma_init_dev_caps(struct cdma_dev *cdev) +{ + struct cdma_caps *caps = &cdev->caps; + int ret; + u8 i; + + ret = cdma_query_caps_from_firmware(cdev); + if (ret) + return ret; + + ret = cdma_set_caps_from_adev_caps(cdev); + if (ret) + return ret; + + ret = cdma_set_caps_from_ubase_caps(cdev); + if (ret) + return ret; + + caps->queue.max_cnt = min(caps->jfs.max_cnt, caps->jfc.max_cnt); + caps->queue.start_idx = 0; + caps->jfce.max_cnt = caps->jfc.max_cnt; + caps->jfce.start_idx = 0; + + dev_info(cdev->dev, "query cdev eid = 0x%x, cdev upi = 0x%x\n", cdev->eid, + cdev->upi); + dev_info(cdev->dev, "queue:max_cnt = 0x%x, start_idx = 0x%x\n", + caps->queue.max_cnt, caps->queue.start_idx); + dev_info(cdev->dev, "jfs:max_cnt = 0x%x, depth = 0x%x, start_idx = 0x%x\n", + caps->jfs.max_cnt, caps->jfs.depth, caps->jfs.start_idx); + dev_info(cdev->dev, "jfce:max_cnt = 0x%x, depth = 0x%x, start_idx = 0x%x\n", + caps->jfce.max_cnt, caps->jfce.depth, caps->jfce.start_idx); + dev_info(cdev->dev, "jfc:max_cnt = 0x%x, depth = 0x%x, start_idx = 0x%x\n", + caps->jfc.max_cnt, caps->jfc.depth, caps->jfc.start_idx); + dev_info(cdev->dev, "comp_vector_cnt = 0x%x, public_jetty_cnt = 0x%x\n", + caps->comp_vector_cnt, caps->public_jetty_cnt); + dev_info(cdev->dev, "sl_num = 0x%x\n", cdev->sl_num); + for (i = 0; i < cdev->sl_num; i++) + dev_info(cdev->dev, "sl[%u] = 0x%x\n", i, cdev->sl[i]); + + return 0; +} + +int cdma_ctrlq_query_eu(struct cdma_dev *cdev) +{ +#define CDMA_CTRLQ_QUERY_SEID_UPI 0x1 +#define CDMA_CTRLQ_CMD_SEID_UPI 0xB5 + struct cdma_device_attr *attr = &cdev->base.attr; + struct eu_query_out out_query = { 0 }; + struct eu_query_in in_query = { 0 }; + struct ubase_ctrlq_msg msg = { 0 }; + struct eu_info *eus = attr->eus; + int ret; + u8 i; + + in_query.cmd = CDMA_CTRLQ_CMD_SEID_UPI; + + msg = (struct ubase_ctrlq_msg) { + .service_ver = UBASE_CTRLQ_SER_VER_01, + .service_type = UBASE_CTRLQ_SER_TYPE_DEV_REGISTER, + .opcode = CDMA_CTRLQ_QUERY_SEID_UPI, + .need_resp = 1, + .is_resp = 0, + .resv = 0, + .resp_seq = 0, + .in_size = sizeof(in_query), + .in = &in_query, + .out_size = sizeof(out_query), + .out = &out_query, + }; + + ret = ubase_ctrlq_send_msg(cdev->adev, &msg); + if (ret) { + dev_err(cdev->dev, + "query seid upi from ctrl cpu failed, ret = %d.\n", ret); + return ret; + } + + if (!out_query.seid_num || out_query.seid_num > CDMA_MAX_EU_NUM) { + dev_err(cdev->dev, + "query seid upi num is invalid, num = %u.\n", + out_query.seid_num); + return -EINVAL; + } + + mutex_lock(&cdev->eu_mutex); + memcpy(eus, out_query.eus, sizeof(struct eu_info) * out_query.seid_num); + attr->eu_num = out_query.seid_num; + + for (i = 0; i < attr->eu_num; i++) + dev_dbg(cdev->dev, + "cdma init eus[%u], upi = 0x%x, eid = 0x%x, eid_idx = 0x%x.\n", + i, eus[i].upi, eus[i].eid.dw0, eus[i].eid_idx); + mutex_unlock(&cdev->eu_mutex); + + return 0; +} diff --git a/drivers/ub/cdma/cdma_cmd.h b/drivers/ub/cdma/cdma_cmd.h new file mode 100644 index 000000000000..550f60640b36 --- /dev/null +++ b/drivers/ub/cdma/cdma_cmd.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_CMD_H__ +#define __CDMA_CMD_H__ + +#include + +struct cdma_dev; + +struct cdma_ue_info { + /* BD0 */ + u16 jfs_num_shift : 4; + u16 jfr_num_shift : 4; + u16 jfc_num_shift : 4; + u16 jetty_num_shift : 4; + + u16 jetty_grp_num; + + u16 jfs_depth_shift : 4; + u16 jfr_depth_shift : 4; + u16 jfc_depth_shift : 4; + u16 cqe_size_shift : 4; + + u16 jfs_sge : 5; + u16 jfr_sge : 5; + u16 jfs_rsge : 6; + + u16 max_jfs_inline_sz; + u16 max_jfc_inline_sz; + u32 cap_info; + + u16 trans_mode : 5; + u16 ue_num : 8; + u16 virtualization : 1; + u16 rsvd0 : 2; + + u16 ue_cnt; + u8 ue_id; + u8 default_cong_alg; + u8 cons_ctrl_alg; + u8 cc_priority_cnt; + /* BD1 */ + u16 src_addr_tbl_sz; + u16 src_addr_tbl_num; + u16 dest_addr_tbl_sz; + u16 dest_addr_tbl_num; + u16 seid_upi_tbl_sz; + u16 seid_upi_tbl_num; + u16 tpm_tbl_sz; + u16 tpm_tbl_num; + u32 tp_range; + u8 port_num; + u8 port_id; + u8 rsvd1[2]; + u16 rc_queue_num; + u16 rc_depth; + u8 rc_entry; + u8 rsvd2[3]; + /* BD2 */ + u32 rsvd3[8]; + /* BD3 */ + u32 rsvd4[8]; +}; + +struct eu_query_in { + u32 cmd : 8; + u32 rsv : 24; +}; + +struct eu_query_out { + u32 seid_num : 8; + u32 rsv : 24; + struct eu_info eus[CDMA_MAX_EU_NUM]; +}; + +int cdma_init_dev_caps(struct cdma_dev *cdev); +int cdma_ctrlq_query_eu(struct cdma_dev *cdev); +#endif diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c new file mode 100644 index 000000000000..4c883e728362 --- /dev/null +++ b/drivers/ub/cdma/cdma_dev.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include +#include +#include +#include +#include + +#include "cdma.h" +#include "cdma_cmd.h" +#include "cdma_tid.h" +#include +#include +#include "cdma_dev.h" + +static DEFINE_XARRAY(cdma_devs_tbl); +static atomic_t cdma_devs_num = ATOMIC_INIT(0); + +/* Add the device to the device list for user query. */ +static int cdma_add_device_to_list(struct cdma_dev *cdev) +{ + struct auxiliary_device *adev = cdev->adev; + int ret; + + if (adev->id >= CDMA_UE_MAX_NUM) { + dev_err(cdev->dev, "invalid ue id %u.\n", adev->id); + return -EINVAL; + } + + ret = xa_err(xa_store(&cdma_devs_tbl, adev->id, cdev, GFP_KERNEL)); + if (ret) { + dev_err(cdev->dev, + "store cdma device to table failed, adev id = %u.\n", + adev->id); + return ret; + } + + atomic_inc(&cdma_devs_num); + + return 0; +} + +static void cdma_del_device_from_list(struct cdma_dev *cdev) +{ + struct auxiliary_device *adev = cdev->adev; + + if (adev->id >= CDMA_UE_MAX_NUM) { + dev_err(cdev->dev, "invalid ue id %u.\n", adev->id); + return; + } + + atomic_dec(&cdma_devs_num); + xa_erase(&cdma_devs_tbl, adev->id); +} + +static void cdma_init_base_dev(struct cdma_dev *cdev) +{ + struct cdma_device_attr *attr = &cdev->base.attr; + struct cdma_device_cap *dev_cap = &attr->dev_cap; + struct cdma_caps *caps = &cdev->caps; + + attr->eid.dw0 = cdev->eid; + dev_cap->max_jfc = caps->jfc.max_cnt; + dev_cap->max_jfs = caps->jfs.max_cnt; + dev_cap->max_jfc_depth = caps->jfc.depth; + dev_cap->max_jfs_depth = caps->jfs.depth; + dev_cap->trans_mode = caps->trans_mode; + dev_cap->max_jfs_sge = caps->jfs_sge; + dev_cap->max_jfs_rsge = caps->jfs_rsge; + dev_cap->max_msg_size = caps->max_msg_len; + dev_cap->ceq_cnt = caps->comp_vector_cnt; + dev_cap->max_jfs_inline_len = caps->jfs_inline_sz; +} + +static int cdma_init_dev_param(struct cdma_dev *cdev, + struct auxiliary_device *adev) +{ + struct ubase_resource_space *mem_base; + int ret; + + mem_base = ubase_get_mem_base(adev); + if (!mem_base) + return -EINVAL; + + cdev->adev = adev; + cdev->dev = adev->dev.parent; + cdev->k_db_base = mem_base->addr; + cdev->db_base = mem_base->addr_unmapped; + + ret = cdma_init_dev_caps(cdev); + if (ret) + return ret; + + cdma_init_base_dev(cdev); + + dev_set_drvdata(&adev->dev, cdev); + + mutex_init(&cdev->db_mutex); + mutex_init(&cdev->eu_mutex); + INIT_LIST_HEAD(&cdev->db_page); + mutex_init(&cdev->file_mutex); + INIT_LIST_HEAD(&cdev->file_list); + + return 0; +} + +static void cdma_uninit_dev_param(struct cdma_dev *cdev) +{ + mutex_destroy(&cdev->db_mutex); + mutex_destroy(&cdev->eu_mutex); + mutex_destroy(&cdev->file_mutex); + dev_set_drvdata(&cdev->adev->dev, NULL); +} + +int cdma_create_arm_db_page(struct cdma_dev *cdev) +{ + cdev->arm_db_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!cdev->arm_db_page) { + dev_err(cdev->dev, "alloc dev arm db page failed.\n"); + return -ENOMEM; + } + return 0; +} + +void cdma_destroy_arm_db_page(struct cdma_dev *cdev) +{ + if (!cdev->arm_db_page) + return; + + put_page(cdev->arm_db_page); + cdev->arm_db_page = NULL; +} + +struct cdma_dev *cdma_create_dev(struct auxiliary_device *adev) +{ + struct cdma_dev *cdev; + + cdev = kzalloc((sizeof(*cdev)), GFP_KERNEL); + if (!cdev) + return NULL; + + if (cdma_init_dev_param(cdev, adev)) + goto free; + + if (cdma_add_device_to_list(cdev)) + goto free_param; + + if (cdma_alloc_dev_tid(cdev)) + goto del_list; + + if (cdma_create_arm_db_page(cdev)) + goto free_tid; + + dev_dbg(&adev->dev, "cdma.%u init succeeded.\n", adev->id); + + return cdev; + +free_tid: + cdma_free_dev_tid(cdev); +del_list: + cdma_del_device_from_list(cdev); +free_param: + cdma_uninit_dev_param(cdev); +free: + kfree(cdev); + return NULL; +} + +void cdma_destroy_dev(struct cdma_dev *cdev) +{ + if (!cdev) + return; + + cdma_destroy_arm_db_page(cdev); + ubase_ctrlq_unregister_crq_event(cdev->adev, + UBASE_CTRLQ_SER_TYPE_DEV_REGISTER, + CDMA_CTRLQ_EU_UPDATE); + cdma_free_dev_tid(cdev); + + cdma_del_device_from_list(cdev); + cdma_uninit_dev_param(cdev); + kfree(cdev); +} diff --git a/drivers/ub/cdma/cdma_dev.h b/drivers/ub/cdma/cdma_dev.h new file mode 100644 index 000000000000..41222a67e12a --- /dev/null +++ b/drivers/ub/cdma/cdma_dev.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_DEV_H__ +#define __CDMA_DEV_H__ + +#include + +#define CDMA_CTRLQ_EU_UPDATE 0x2 +#define CDMA_UE_MAX_NUM 64 + +struct cdma_dev; + +struct cdma_dev *cdma_create_dev(struct auxiliary_device *adev); +void cdma_destroy_dev(struct cdma_dev *cdev); +int cdma_create_arm_db_page(struct cdma_dev *cdev); +void cdma_destroy_arm_db_page(struct cdma_dev *cdev); + +#endif /* _CDMA_DEV_H_ */ diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c new file mode 100644 index 000000000000..28d21ca61ea6 --- /dev/null +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include + +#include +#include "cdma.h" +#include "cdma_types.h" +#include "cdma_ioctl.h" + +typedef int (*cdma_cmd_handler)(struct cdma_ioctl_hdr *hdr, + struct cdma_file *cfile); + +static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { +}; + +int cdma_cmd_parse(struct cdma_file *cfile, struct cdma_ioctl_hdr *hdr) +{ + struct cdma_dev *cdev = cfile->cdev; + + if (hdr->command >= CDMA_CMD_MAX || !g_cdma_cmd_handler[hdr->command]) { + dev_err(cdev->dev, + "invalid cdma user command or no handler, command = %u\n", + hdr->command); + return -EINVAL; + } + + return g_cdma_cmd_handler[hdr->command](hdr, cfile); +} diff --git a/drivers/ub/cdma/cdma_ioctl.h b/drivers/ub/cdma/cdma_ioctl.h new file mode 100644 index 000000000000..a5b20c99117e --- /dev/null +++ b/drivers/ub/cdma/cdma_ioctl.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_IOCTL_H__ +#define __CDMA_IOCTL_H__ + +struct cdma_file; +struct cdma_ioctl_hdr; + +int cdma_cmd_parse(struct cdma_file *cfile, struct cdma_ioctl_hdr *hdr); + +#endif /* _CDMA_IOCTL_H_ */ diff --git a/drivers/ub/cdma/cdma_main.c b/drivers/ub/cdma/cdma_main.c new file mode 100644 index 000000000000..d04b4b43c989 --- /dev/null +++ b/drivers/ub/cdma/cdma_main.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define pr_fmt(fmt) "CDMA: " fmt +#define dev_fmt pr_fmt + +#include + +#include "cdma.h" +#include "cdma_dev.h" +#include "cdma_chardev.h" +#include +#include "cdma_cmd.h" + +/* Enabling jfc_arm_mode will cause jfc to report cqe; otherwise, it will not. */ +uint jfc_arm_mode; +module_param(jfc_arm_mode, uint, 0444); +MODULE_PARM_DESC(jfc_arm_mode, + "Set the ARM mode of the JFC, default: 0(0:Always ARM, others: NO ARM)"); + +struct class *cdma_cdev_class; + +static int cdma_init_dev_info(struct auxiliary_device *auxdev, struct cdma_dev *cdev) +{ + int ret; + + /* query eu failure does not affect driver loading, as eu can be updated. */ + ret = cdma_ctrlq_query_eu(cdev); + if (ret) + dev_warn(&auxdev->dev, "query eu failed, ret = %d.\n", ret); + + return 0; +} + +static int cdma_init_dev(struct auxiliary_device *auxdev) +{ + struct cdma_dev *cdev; + int ret; + + dev_dbg(&auxdev->dev, "%s called, matched aux dev(%s.%u).\n", + __func__, auxdev->name, auxdev->id); + + cdev = cdma_create_dev(auxdev); + if (!cdev) + return -ENOMEM; + + ret = cdma_create_chardev(cdev); + if (ret) { + cdma_destroy_dev(cdev); + return ret; + } + + ret = cdma_init_dev_info(auxdev, cdev); + if (ret) { + cdma_destroy_chardev(cdev); + cdma_destroy_dev(cdev); + return ret; + } + + return ret; +} + +static void cdma_uninit_dev(struct auxiliary_device *auxdev) +{ + struct cdma_dev *cdev; + + dev_dbg(&auxdev->dev, "%s called, matched aux dev(%s.%u).\n", + __func__, auxdev->name, auxdev->id); + + cdev = dev_get_drvdata(&auxdev->dev); + if (!cdev) { + dev_err(&auxdev->dev, "get drvdata from ubase failed.\n"); + return; + } + + cdma_destroy_chardev(cdev); + cdma_destroy_dev(cdev); +} + +static int cdma_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *auxdev_id) +{ + int ret; + + ret = cdma_init_dev(auxdev); + if (ret) + return ret; + + return 0; +} + +static void cdma_remove(struct auxiliary_device *auxdev) +{ + cdma_uninit_dev(auxdev); +} + +static const struct auxiliary_device_id cdma_id_table[] = { + { + .name = UBASE_ADEV_NAME ".cdma", + }, + {} +}; +MODULE_DEVICE_TABLE(auxiliary, cdma_id_table); + +static struct auxiliary_driver cdma_driver = { + .probe = cdma_probe, + .remove = cdma_remove, + .name = "cdma", + .id_table = cdma_id_table, +}; + +static int __init cdma_init(void) +{ + int ret; + + cdma_cdev_class = class_create("cdma"); + if (IS_ERR(cdma_cdev_class)) { + pr_err("create cdma class failed.\n"); + return PTR_ERR(cdma_cdev_class); + } + + ret = auxiliary_driver_register(&cdma_driver); + if (ret) { + pr_err("auxiliary register failed.\n"); + goto free_class; + } + + return 0; + +free_class: + class_destroy(cdma_cdev_class); + + return ret; +} + +static void __exit cdma_exit(void) +{ + auxiliary_driver_unregister(&cdma_driver); + class_destroy(cdma_cdev_class); +} + +module_init(cdma_init); +module_exit(cdma_exit); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0"); +MODULE_DESCRIPTION("Hisilicon UBus Crystal DMA Driver"); diff --git a/drivers/ub/cdma/cdma_tid.c b/drivers/ub/cdma/cdma_tid.c new file mode 100644 index 000000000000..6e38b72bc8e0 --- /dev/null +++ b/drivers/ub/cdma/cdma_tid.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include +#include + +#include "cdma.h" +#include "cdma_tid.h" + +int cdma_alloc_dev_tid(struct cdma_dev *cdev) +{ + struct ummu_seg_attr seg_attr = { + .token = NULL, + .e_bit = UMMU_EBIT_ON, + }; + struct ummu_param drvdata = { + .mode = MAPT_MODE_TABLE, + }; + int ret; + + ret = iommu_dev_enable_feature(cdev->dev, IOMMU_DEV_FEAT_KSVA); + if (ret) { + dev_err(cdev->dev, "enable ksva failed, ret = %d.\n", ret); + return ret; + } + + ret = iommu_dev_enable_feature(cdev->dev, IOMMU_DEV_FEAT_SVA); + if (ret) { + dev_err(cdev->dev, "enable sva failed, ret = %d.\n", ret); + goto err_sva_enable_dev; + } + + cdev->ksva = ummu_ksva_bind_device(cdev->dev, &drvdata); + if (!cdev->ksva) { + dev_err(cdev->dev, "ksva bind device failed.\n"); + ret = -EINVAL; + goto err_ksva_bind_device; + } + + ret = ummu_get_tid(cdev->dev, cdev->ksva, &cdev->tid); + if (ret) { + dev_err(cdev->dev, "get tid for cdma device failed.\n"); + goto err_get_tid; + } + + ret = ummu_sva_grant_range(cdev->ksva, 0, CDMA_MAX_GRANT_SIZE, + UMMU_DEV_WRITE | UMMU_DEV_READ, + &seg_attr); + if (ret) { + dev_err(cdev->dev, "sva grant range for cdma device failed.\n"); + goto err_get_tid; + } + + return 0; + +err_get_tid: + ummu_ksva_unbind_device(cdev->ksva); +err_ksva_bind_device: + if (iommu_dev_disable_feature(cdev->dev, IOMMU_DEV_FEAT_SVA)) + dev_warn(cdev->dev, "disable sva failed, ret = %d.\n", ret); +err_sva_enable_dev: + if (iommu_dev_disable_feature(cdev->dev, IOMMU_DEV_FEAT_KSVA)) + dev_warn(cdev->dev, "disable ksva failed, ret = %d.\n", ret); + + return ret; +} + +void cdma_free_dev_tid(struct cdma_dev *cdev) +{ + int ret; + + ret = ummu_sva_ungrant_range(cdev->ksva, 0, CDMA_MAX_GRANT_SIZE, NULL); + if (ret) + dev_warn(cdev->dev, + "sva ungrant range for cdma device failed, ret = %d.\n", + ret); + + ummu_ksva_unbind_device(cdev->ksva); + + ret = iommu_dev_disable_feature(cdev->dev, IOMMU_DEV_FEAT_SVA); + if (ret) + dev_warn(cdev->dev, "disable sva failed, ret = %d.\n", ret); + + ret = iommu_dev_disable_feature(cdev->dev, IOMMU_DEV_FEAT_KSVA); + if (ret) + dev_warn(cdev->dev, "disable ksva failed, ret = %d.\n", ret); +} diff --git a/drivers/ub/cdma/cdma_tid.h b/drivers/ub/cdma/cdma_tid.h new file mode 100644 index 000000000000..8bbd8c0c979a --- /dev/null +++ b/drivers/ub/cdma/cdma_tid.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_TID_H__ +#define __CDMA_TID_H__ + +#include + +#define CDMA_MAX_GRANT_SIZE GENMASK(47, 12) + +struct cdma_dev; + +int cdma_alloc_dev_tid(struct cdma_dev *cdev); +void cdma_free_dev_tid(struct cdma_dev *cdev); + +#endif diff --git a/drivers/ub/cdma/cdma_types.h b/drivers/ub/cdma/cdma_types.h new file mode 100644 index 000000000000..4ef38c23e22c --- /dev/null +++ b/drivers/ub/cdma/cdma_types.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_TYPES_H__ +#define __CDMA_TYPES_H__ + +#include +#include +#include + +struct cdma_dev; + +struct cdma_file { + struct cdma_dev *cdev; + struct list_head list; + struct kref ref; +}; + +#endif diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h new file mode 100644 index 000000000000..ae83d18dfd8d --- /dev/null +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef _UAPI_UB_CDMA_CDMA_ABI_H_ +#define _UAPI_UB_CDMA_CDMA_ABI_H_ + +#include + +/* cdma ioctl cmd */ +#define CDMA_IOC_MAGIC 'C' +#define CDMA_SYNC _IOWR(CDMA_IOC_MAGIC, 0, struct cdma_ioctl_hdr) + +enum cdma_cmd { + CDMA_CMD_MAX +}; + +struct cdma_ioctl_hdr { + __u32 command; + __u32 args_len; + __u64 args_addr; +}; + +struct dev_eid { + __u32 dw0; + __u32 dw1; + __u32 dw2; + __u32 dw3; +}; + +struct eu_info { + __u32 eid_idx; + struct dev_eid eid; + __u32 upi; +}; + +struct cdma_device_cap { + __u32 max_jfc; + __u32 max_jfs; + __u32 max_jfc_depth; + __u32 max_jfs_depth; + __u32 max_jfs_inline_len; + __u32 max_jfs_sge; + __u32 max_jfs_rsge; + __u64 max_msg_size; + __u32 max_atomic_size; + __u16 trans_mode; + __u32 ceq_cnt; + __u32 max_eid_cnt; + __u64 page_size_cap; +}; + +struct cdma_device_attr { +#define CDMA_MAX_EU_NUM 64 + __u8 eu_num; + struct dev_eid eid; + struct eu_info eu; + struct eu_info eus[CDMA_MAX_EU_NUM]; + struct cdma_device_cap dev_cap; +}; + +#endif diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h new file mode 100644 index 000000000000..8b223fe6f5ab --- /dev/null +++ b/include/ub/cdma/cdma_api.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef _UB_CDMA_CDMA_API_H_ +#define _UB_CDMA_CDMA_API_H_ + +#include +#include + +struct dma_device { + struct cdma_device_attr attr; + atomic_t ref_cnt; + void *private_data; +}; + +#endif -- Gitee From 8a5bdd3bc9385bad255af72c2439538b749c953d Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Mon, 25 Aug 2025 16:14:36 +0800 Subject: [PATCH 007/103] ub: cdma: support querying sl information and updating eu commit ca1562136e1414353235fc99165b6c4ac7660ca3 openEuler This patch implements the querying of sl information during device initialization in the CDMA driver and the process of dynamically refreshing eu (eid/upi) through crtlq. Signed-off-by: Zhipeng Lu Signed-off-by: Hongwu Wang Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma_cmd.c | 26 +++++++ drivers/ub/cdma/cdma_dev.c | 141 ++++++++++++++++++++++++++++++++++++- drivers/ub/cdma/cdma_dev.h | 13 ++++ 3 files changed, 179 insertions(+), 1 deletion(-) diff --git a/drivers/ub/cdma/cdma_cmd.c b/drivers/ub/cdma/cdma_cmd.c index 80ab8791b018..74e6b32a58c7 100644 --- a/drivers/ub/cdma/cdma_cmd.c +++ b/drivers/ub/cdma/cdma_cmd.c @@ -92,6 +92,28 @@ static int cdma_set_caps_from_ubase_caps(struct cdma_dev *cdev) return 0; } +static int cdma_set_caps_from_adev_qos(struct cdma_dev *cdev) +{ + struct ubase_adev_qos *qos; + + qos = ubase_get_adev_qos(cdev->adev); + if (!qos) { + dev_err(cdev->dev, "get cdma adev qos failed\n"); + return -EINVAL; + } + + if (!qos->ctp_sl_num || qos->ctp_sl_num > CDMA_MAX_SL_NUM) { + dev_err(cdev->dev, "sl num %u is invalid\n", + qos->ctp_sl_num); + return -EINVAL; + } + + cdev->sl_num = qos->ctp_sl_num; + memcpy(cdev->sl, qos->ctp_sl, qos->ctp_sl_num); + + return 0; +} + int cdma_init_dev_caps(struct cdma_dev *cdev) { struct cdma_caps *caps = &cdev->caps; @@ -110,6 +132,10 @@ int cdma_init_dev_caps(struct cdma_dev *cdev) if (ret) return ret; + ret = cdma_set_caps_from_adev_qos(cdev); + if (ret) + return ret; + caps->queue.max_cnt = min(caps->jfs.max_cnt, caps->jfc.max_cnt); caps->queue.start_idx = 0; caps->jfce.max_cnt = caps->jfc.max_cnt; diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index 4c883e728362..9d7142214a45 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -115,6 +115,108 @@ static void cdma_uninit_dev_param(struct cdma_dev *cdev) dev_set_drvdata(&cdev->adev->dev, NULL); } +static int cdma_ctrlq_eu_add(struct cdma_dev *cdev, struct eu_info *eu) +{ + struct cdma_device_attr *attr = &cdev->base.attr; + struct eu_info *eus = cdev->base.attr.eus; + u8 i; + + for (i = 0; i < attr->eu_num; i++) { + if (eu->eid_idx != eus[i].eid_idx) + continue; + + dev_dbg(cdev->dev, + "cdma.%u: eid_idx[0x%x] eid[0x%x->0x%x] upi[0x%x->0x%x] update success.\n", + cdev->adev->id, eu->eid_idx, eus[i].eid.dw0, + eu->eid.dw0, eus[i].upi, eu->upi & CDMA_UPI_MASK); + + eus[i].eid = eu->eid; + eus[i].upi = eu->upi & CDMA_UPI_MASK; + + if (attr->eu.eid_idx == eu->eid_idx) { + attr->eu.eid = eu->eid; + attr->eu.upi = eu->upi & CDMA_UPI_MASK; + } + return 0; + } + + if (attr->eu_num >= CDMA_MAX_EU_NUM) { + dev_err(cdev->dev, "cdma.%u: eu table is full.\n", + cdev->adev->id); + return -EINVAL; + } + + eus[attr->eu_num++] = *eu; + dev_dbg(cdev->dev, + "cdma.%u: eid_idx[0x%x] eid[0x%x] upi[0x%x] add success.\n", + cdev->adev->id, eu->eid_idx, eu->eid.dw0, + eu->upi & CDMA_UPI_MASK); + + return 0; +} + +static int cdma_ctrlq_eu_del(struct cdma_dev *cdev, struct eu_info *eu) +{ + struct cdma_device_attr *attr = &cdev->base.attr; + struct eu_info *eus = cdev->base.attr.eus; + int ret = -EINVAL; + u8 i, j; + + if (!attr->eu_num) { + dev_err(cdev->dev, "cdma.%u: eu table is empty.\n", + cdev->adev->id); + return -EINVAL; + } + + for (i = 0; i < attr->eu_num; i++) { + if (eu->eid_idx != eus[i].eid_idx) + continue; + + for (j = i; j < attr->eu_num - 1; j++) + eus[j] = eus[j + 1]; + memset(&eus[j], 0, sizeof(*eus)); + + if (attr->eu.eid_idx == eu->eid_idx) + attr->eu = eus[0]; + attr->eu_num--; + ret = 0; + break; + } + + dev_info(cdev->dev, + "cdma.%u: eid_idx[0x%x] eid[0x%x] upi[0x%x] delete %s.\n", + cdev->adev->id, eu->eid_idx, eu->eid.dw0, + eu->upi & CDMA_UPI_MASK, ret ? "failed" : "success"); + + return ret; +} + +static int cdma_ctrlq_eu_update(struct auxiliary_device *adev, u8 service_ver, + void *data, u16 len, u16 seq) +{ + struct cdma_dev *cdev = dev_get_drvdata(&adev->dev); + struct cdma_ctrlq_eu_info *ctrlq_eu; + int ret = -EINVAL; + + if (len < sizeof(*ctrlq_eu)) { + dev_err(cdev->dev, "ctrlq data len is invalid.\n"); + return -EINVAL; + } + + ctrlq_eu = (struct cdma_ctrlq_eu_info *)data; + + mutex_lock(&cdev->eu_mutex); + if (ctrlq_eu->op == CDMA_CTRLQ_EU_ADD) + ret = cdma_ctrlq_eu_add(cdev, &ctrlq_eu->eu); + else if (ctrlq_eu->op == CDMA_CTRLQ_EU_DEL) + ret = cdma_ctrlq_eu_del(cdev, &ctrlq_eu->eu); + else + dev_err(cdev->dev, "ctrlq eu op is invalid.\n"); + mutex_unlock(&cdev->eu_mutex); + + return ret; +} + int cdma_create_arm_db_page(struct cdma_dev *cdev) { cdev->arm_db_page = alloc_page(GFP_KERNEL | __GFP_ZERO); @@ -134,6 +236,36 @@ void cdma_destroy_arm_db_page(struct cdma_dev *cdev) cdev->arm_db_page = NULL; } +int cdma_register_crq_event(struct auxiliary_device *adev) +{ + struct ubase_ctrlq_event_nb nb = { + .service_type = UBASE_CTRLQ_SER_TYPE_DEV_REGISTER, + .opcode = CDMA_CTRLQ_EU_UPDATE, + .back = adev, + .crq_handler = cdma_ctrlq_eu_update, + }; + int ret; + + if (!adev) + return -EINVAL; + + ret = ubase_ctrlq_register_crq_event(adev, &nb); + if (ret) { + dev_err(&adev->dev, "register crq event failed, id = %u, ret = %d.\n", + adev->id, ret); + return ret; + } + + return 0; +} + +void cdma_unregister_crq_event(struct auxiliary_device *adev) +{ + ubase_ctrlq_unregister_crq_event(adev, + UBASE_CTRLQ_SER_TYPE_DEV_REGISTER, + CDMA_CTRLQ_EU_UPDATE); +} + struct cdma_dev *cdma_create_dev(struct auxiliary_device *adev) { struct cdma_dev *cdev; @@ -151,13 +283,18 @@ struct cdma_dev *cdma_create_dev(struct auxiliary_device *adev) if (cdma_alloc_dev_tid(cdev)) goto del_list; - if (cdma_create_arm_db_page(cdev)) + if (cdma_register_crq_event(adev)) goto free_tid; + if (cdma_create_arm_db_page(cdev)) + goto unregister_crq; + dev_dbg(&adev->dev, "cdma.%u init succeeded.\n", adev->id); return cdev; +unregister_crq: + cdma_unregister_crq_event(adev); free_tid: cdma_free_dev_tid(cdev); del_list: @@ -174,6 +311,8 @@ void cdma_destroy_dev(struct cdma_dev *cdev) if (!cdev) return; + ubase_virt_unregister(cdev->adev); + cdma_destroy_arm_db_page(cdev); ubase_ctrlq_unregister_crq_event(cdev->adev, UBASE_CTRLQ_SER_TYPE_DEV_REGISTER, diff --git a/drivers/ub/cdma/cdma_dev.h b/drivers/ub/cdma/cdma_dev.h index 41222a67e12a..e79dc2608e24 100644 --- a/drivers/ub/cdma/cdma_dev.h +++ b/drivers/ub/cdma/cdma_dev.h @@ -11,8 +11,21 @@ struct cdma_dev; +struct cdma_ctrlq_eu_info { + struct eu_info eu; + u32 op : 4; + u32 rsvd : 28; +}; + +enum cdma_ctrlq_eu_op { + CDMA_CTRLQ_EU_ADD = 0, + CDMA_CTRLQ_EU_DEL = 1, +}; + struct cdma_dev *cdma_create_dev(struct auxiliary_device *adev); void cdma_destroy_dev(struct cdma_dev *cdev); +int cdma_register_crq_event(struct auxiliary_device *adev); +void cdma_unregister_crq_event(struct auxiliary_device *adev); int cdma_create_arm_db_page(struct cdma_dev *cdev); void cdma_destroy_arm_db_page(struct cdma_dev *cdev); -- Gitee From 13154b3e44c47b2b65748d4ca6238469fe0acb01 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Mon, 25 Aug 2025 16:18:34 +0800 Subject: [PATCH 008/103] ub: cdma: support for getting device list commit 1291f9445da2401526178bb343177b8a8a887df8 openEuler This patch implements device list-related APIs and functionalities within the CDMA driver. The implementation includes support for the interfaces dma_get_device_list and dma_free_device_list. Signed-off-by: Zhipeng Lu Signed-off-by: Hongwu Wang Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/Makefile | 3 +- drivers/ub/cdma/cdma.h | 5 ++ drivers/ub/cdma/cdma_api.c | 88 +++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_context.h | 29 +++++++++++ drivers/ub/cdma/cdma_dev.c | 7 +++ drivers/ub/cdma/cdma_dev.h | 2 + drivers/ub/cdma/cdma_ioctl.c | 41 +++++++++++++++ include/uapi/ub/cdma/cdma_abi.h | 7 +++ include/ub/cdma/cdma_api.h | 9 ++++ 9 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 drivers/ub/cdma/cdma_api.c create mode 100644 drivers/ub/cdma/cdma_context.h diff --git a/drivers/ub/cdma/Makefile b/drivers/ub/cdma/Makefile index 7375c6a08738..332700d90004 100644 --- a/drivers/ub/cdma/Makefile +++ b/drivers/ub/cdma/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0+ -cdma-$(CONFIG_UB_CDMA) := cdma_main.o cdma_dev.o cdma_chardev.o cdma_cmd.o cdma_tid.o cdma_ioctl.o +cdma-$(CONFIG_UB_CDMA) := cdma_main.o cdma_dev.o cdma_chardev.o cdma_cmd.o cdma_tid.o cdma_ioctl.o \ + cdma_api.o obj-m += cdma.o diff --git a/drivers/ub/cdma/cdma.h b/drivers/ub/cdma/cdma.h index af45096026ee..4a9720af8681 100644 --- a/drivers/ub/cdma/cdma.h +++ b/drivers/ub/cdma/cdma.h @@ -16,6 +16,11 @@ #define CDMA_UPI_MASK 0x7FFF +enum cdma_status { + CDMA_NORMAL, + CDMA_SUSPEND, +}; + struct cdma_res { u32 max_cnt; u32 start_idx; diff --git a/drivers/ub/cdma/cdma_api.c b/drivers/ub/cdma/cdma_api.c new file mode 100644 index 000000000000..1f83307ea9bc --- /dev/null +++ b/drivers/ub/cdma/cdma_api.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define pr_fmt(fmt) "CDMA: " fmt +#define dev_fmt pr_fmt + +#include "cdma_dev.h" +#include "cdma_cmd.h" +#include "cdma_context.h" +#include "cdma.h" +#include + +struct dma_device *dma_get_device_list(u32 *num_devices) +{ + struct cdma_device_attr *attr; + struct xarray *cdma_devs_tbl; + struct cdma_dev *cdev = NULL; + struct dma_device *ret_list; + unsigned long index; + u32 count = 0; + u32 devs_num; + + if (!num_devices) + return NULL; + + cdma_devs_tbl = get_cdma_dev_tbl(&devs_num); + if (devs_num == 0) { + pr_err("cdma device table is empty.\n"); + return NULL; + } + + ret_list = kcalloc(devs_num, sizeof(struct dma_device), GFP_KERNEL); + if (!ret_list) { + *num_devices = 0; + return NULL; + } + + xa_for_each(cdma_devs_tbl, index, cdev) { + attr = &cdev->base.attr; + if (cdev->status == CDMA_SUSPEND) { + pr_warn("cdma device is not prepared, eid = 0x%x.\n", + attr->eid.dw0); + continue; + } + + if (!attr->eu_num) { + pr_warn("no eu in cdma dev eid = 0x%x.\n", cdev->eid); + continue; + } + + memcpy(&attr->eu, &attr->eus[0], sizeof(attr->eu)); + attr->eid.dw0 = cdev->eid; + memcpy(&ret_list[count], &cdev->base, sizeof(*ret_list)); + ret_list[count].private_data = kzalloc( + sizeof(struct cdma_ctx_res), GFP_KERNEL); + if (!ret_list[count].private_data) + break; + count++; + } + *num_devices = count; + + return ret_list; +} +EXPORT_SYMBOL_GPL(dma_get_device_list); + +void dma_free_device_list(struct dma_device *dev_list, u32 num_devices) +{ + int ref_cnt; + u32 i; + + if (!dev_list) + return; + + for (i = 0; i < num_devices; i++) { + ref_cnt = atomic_read(&dev_list[i].ref_cnt); + if (ref_cnt > 0) { + pr_warn("the device resourse is still in use, eid = 0x%x, cnt = %d.\n", + dev_list[i].attr.eid.dw0, ref_cnt); + return; + } + } + + for (i = 0; i < num_devices; i++) + kfree(dev_list[i].private_data); + + kfree(dev_list); +} +EXPORT_SYMBOL_GPL(dma_free_device_list); diff --git a/drivers/ub/cdma/cdma_context.h b/drivers/ub/cdma/cdma_context.h new file mode 100644 index 000000000000..3614be608534 --- /dev/null +++ b/drivers/ub/cdma/cdma_context.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_CONTEXT_H__ +#define __CDMA_CONTEXT_H__ + +#include +#include +#include +#include + +struct cdma_context { + struct dma_context base_ctx; + struct cdma_dev *cdev; + struct iommu_sva *sva; + struct list_head pgdir_list; + struct mutex pgdir_mutex; + spinlock_t lock; + int handle; + u32 tid; + bool is_kernel; + atomic_t ref_cnt; +}; + +struct cdma_ctx_res { + struct cdma_context *ctx; +}; + +#endif /* CDMA_CONTEXT_H */ diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index 9d7142214a45..4fc025a6628e 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -19,6 +19,13 @@ static DEFINE_XARRAY(cdma_devs_tbl); static atomic_t cdma_devs_num = ATOMIC_INIT(0); +struct xarray *get_cdma_dev_tbl(u32 *devs_num) +{ + *devs_num = atomic_read(&cdma_devs_num); + + return &cdma_devs_tbl; +} + /* Add the device to the device list for user query. */ static int cdma_add_device_to_list(struct cdma_dev *cdev) { diff --git a/drivers/ub/cdma/cdma_dev.h b/drivers/ub/cdma/cdma_dev.h index e79dc2608e24..623ae8d1f43e 100644 --- a/drivers/ub/cdma/cdma_dev.h +++ b/drivers/ub/cdma/cdma_dev.h @@ -5,6 +5,7 @@ #define __CDMA_DEV_H__ #include +#include #define CDMA_CTRLQ_EU_UPDATE 0x2 #define CDMA_UE_MAX_NUM 64 @@ -24,6 +25,7 @@ enum cdma_ctrlq_eu_op { struct cdma_dev *cdma_create_dev(struct auxiliary_device *adev); void cdma_destroy_dev(struct cdma_dev *cdev); +struct xarray *get_cdma_dev_tbl(u32 *devices_num); int cdma_register_crq_event(struct auxiliary_device *adev); void cdma_unregister_crq_event(struct auxiliary_device *adev); int cdma_create_arm_db_page(struct cdma_dev *cdev); diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c index 28d21ca61ea6..518b5802f7e1 100644 --- a/drivers/ub/cdma/cdma_ioctl.c +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -13,7 +13,48 @@ typedef int (*cdma_cmd_handler)(struct cdma_ioctl_hdr *hdr, struct cdma_file *cfile); +static void cdma_fill_device_attr(struct cdma_dev *cdev, + struct cdma_device_cap *dev_cap) +{ + dev_cap->max_jfc = cdev->caps.jfc.max_cnt; + dev_cap->max_jfs = cdev->caps.jfs.max_cnt; + dev_cap->max_jfc_depth = cdev->caps.jfc.depth; + dev_cap->max_jfs_depth = cdev->caps.jfs.depth; + dev_cap->max_jfs_sge = cdev->caps.jfs_sge; + dev_cap->max_jfs_rsge = cdev->caps.jfs_rsge; + dev_cap->max_msg_size = cdev->caps.max_msg_len; + dev_cap->trans_mode = cdev->caps.trans_mode; + dev_cap->ceq_cnt = cdev->caps.comp_vector_cnt; +} + +static int cdma_query_dev(struct cdma_ioctl_hdr *hdr, struct cdma_file *cfile) +{ + struct cdma_cmd_query_device_attr_args args = { 0 }; + struct cdma_dev *cdev = cfile->cdev; + unsigned long ret; + + if (!hdr->args_addr || hdr->args_len < sizeof(args)) + return -EINVAL; + + args.out.attr.eid.dw0 = cdev->eid; + args.out.attr.eu_num = cdev->base.attr.eu_num; + memcpy(args.out.attr.eus, cdev->base.attr.eus, + sizeof(struct eu_info) * cdev->base.attr.eu_num); + cdma_fill_device_attr(cdev, &args.out.attr.dev_cap); + + ret = copy_to_user((void __user *)(uintptr_t)hdr->args_addr, &args, + (u32)sizeof(args)); + if (ret) { + dev_err(cdev->dev, "query dev copy to user failed, ret = %lu\n", + ret); + return -EFAULT; + } + + return 0; +} + static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { + [CDMA_CMD_QUERY_DEV_INFO] = cdma_query_dev, }; int cdma_cmd_parse(struct cdma_file *cfile, struct cdma_ioctl_hdr *hdr) diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h index ae83d18dfd8d..c72268f4460a 100644 --- a/include/uapi/ub/cdma/cdma_abi.h +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -11,6 +11,7 @@ #define CDMA_SYNC _IOWR(CDMA_IOC_MAGIC, 0, struct cdma_ioctl_hdr) enum cdma_cmd { + CDMA_CMD_QUERY_DEV_INFO, CDMA_CMD_MAX }; @@ -58,4 +59,10 @@ struct cdma_device_attr { struct cdma_device_cap dev_cap; }; +struct cdma_cmd_query_device_attr_args { + struct { + struct cdma_device_attr attr; + } out; +}; + #endif diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index 8b223fe6f5ab..c5e43bb600e3 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -13,4 +13,13 @@ struct dma_device { void *private_data; }; +struct dma_context { + struct dma_device *dma_dev; + u32 tid; /* data valid only in bit 0-19 */ +}; + +struct dma_device *dma_get_device_list(u32 *num_devices); + +void dma_free_device_list(struct dma_device *dev_list, u32 num_devices); + #endif -- Gitee From 85f2c774b2db4746f6be9b5bddbab5c3f03b45a2 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Mon, 25 Aug 2025 16:22:18 +0800 Subject: [PATCH 009/103] ub: cdma: support for getting device by eid commit a26341f5c33ecca2a6c0ca1570a80be47ad413f5 openEuler This patch implements the get device by eid API in the CDMA driver and realizes the related functionality. The implementation includes support for the dma_get_device_by_eid interface. Signed-off-by: Zhipeng Lu Signed-off-by: Jinjie Cui Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma_api.c | 51 +++++++++++++++++++++++++++++++++++++- drivers/ub/cdma/cdma_dev.c | 15 +++++++++++ drivers/ub/cdma/cdma_dev.h | 4 +++ include/ub/cdma/cdma_api.h | 2 ++ 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/ub/cdma/cdma_api.c b/drivers/ub/cdma/cdma_api.c index 1f83307ea9bc..e918f9899494 100644 --- a/drivers/ub/cdma/cdma_api.c +++ b/drivers/ub/cdma/cdma_api.c @@ -24,7 +24,7 @@ struct dma_device *dma_get_device_list(u32 *num_devices) return NULL; cdma_devs_tbl = get_cdma_dev_tbl(&devs_num); - if (devs_num == 0) { + if (!devs_num) { pr_err("cdma device table is empty.\n"); return NULL; } @@ -86,3 +86,52 @@ void dma_free_device_list(struct dma_device *dev_list, u32 num_devices) kfree(dev_list); } EXPORT_SYMBOL_GPL(dma_free_device_list); + +struct dma_device *dma_get_device_by_eid(struct dev_eid *eid) +{ + struct cdma_device_attr *attr; + struct xarray *cdma_devs_tbl; + struct cdma_dev *cdev = NULL; + struct dma_device *ret_dev; + unsigned long index; + u32 devs_num; + + if (!eid) + return NULL; + + cdma_devs_tbl = get_cdma_dev_tbl(&devs_num); + if (!devs_num) { + pr_err("cdma device table is empty.\n"); + return NULL; + } + + ret_dev = kzalloc(sizeof(struct dma_device), GFP_KERNEL); + if (!ret_dev) + return NULL; + + xa_for_each(cdma_devs_tbl, index, cdev) { + attr = &cdev->base.attr; + if (cdev->status == CDMA_SUSPEND) { + pr_warn("cdma device is not prepared, eid = 0x%x.\n", + attr->eid.dw0); + continue; + } + + if (!cdma_find_seid_in_eus(attr->eus, attr->eu_num, eid, + &attr->eu)) + continue; + + memcpy(ret_dev, &cdev->base, sizeof(*ret_dev)); + ret_dev->private_data = kzalloc( + sizeof(struct cdma_ctx_res), GFP_KERNEL); + if (!ret_dev->private_data) { + kfree(ret_dev); + return NULL; + } + return ret_dev; + } + kfree(ret_dev); + + return NULL; +} +EXPORT_SYMBOL_GPL(dma_get_device_by_eid); diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index 4fc025a6628e..10a4baa61e78 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -330,3 +330,18 @@ void cdma_destroy_dev(struct cdma_dev *cdev) cdma_uninit_dev_param(cdev); kfree(cdev); } + +bool cdma_find_seid_in_eus(struct eu_info *eus, u8 eu_num, struct dev_eid *eid, + struct eu_info *eu_out) +{ + u32 i; + + for (i = 0; i < eu_num; i++) + if (eus[i].eid.dw0 == eid->dw0 && eus[i].eid.dw1 == eid->dw1 && + eus[i].eid.dw2 == eid->dw2 && eus[i].eid.dw3 == eid->dw3) { + *eu_out = eus[i]; + return true; + } + + return false; +} diff --git a/drivers/ub/cdma/cdma_dev.h b/drivers/ub/cdma/cdma_dev.h index 623ae8d1f43e..73dc4077a74e 100644 --- a/drivers/ub/cdma/cdma_dev.h +++ b/drivers/ub/cdma/cdma_dev.h @@ -11,6 +11,8 @@ #define CDMA_UE_MAX_NUM 64 struct cdma_dev; +struct eu_info; +struct dev_eid; struct cdma_ctrlq_eu_info { struct eu_info eu; @@ -26,6 +28,8 @@ enum cdma_ctrlq_eu_op { struct cdma_dev *cdma_create_dev(struct auxiliary_device *adev); void cdma_destroy_dev(struct cdma_dev *cdev); struct xarray *get_cdma_dev_tbl(u32 *devices_num); +bool cdma_find_seid_in_eus(struct eu_info *eus, u8 eu_num, struct dev_eid *eid, + struct eu_info *eu_out); int cdma_register_crq_event(struct auxiliary_device *adev); void cdma_unregister_crq_event(struct auxiliary_device *adev); int cdma_create_arm_db_page(struct cdma_dev *cdev); diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index c5e43bb600e3..759f455581a9 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -22,4 +22,6 @@ struct dma_device *dma_get_device_list(u32 *num_devices); void dma_free_device_list(struct dma_device *dev_list, u32 num_devices); +struct dma_device *dma_get_device_by_eid(struct dev_eid *eid); + #endif -- Gitee From 830861325507362c320c71e3398236e944e86d18 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Thu, 28 Aug 2025 21:42:43 +0800 Subject: [PATCH 010/103] ub: cdma: support for allocating queue commit eecfd8889f72f8c03c8af731e508dc3cb46b4b14 openEuler This patch implements the creation of user context and the application of queue APIs in the CDMA driver. The implementation includes support for the dma_create_context and dma_alloc_queue interfaces. Signed-off-by: Zhipeng Lu Signed-off-by: Xinchi Ma Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/Makefile | 2 +- drivers/ub/cdma/cdma.h | 24 ++++++ drivers/ub/cdma/cdma_api.c | 102 ++++++++++++++++++++++++ drivers/ub/cdma/cdma_chardev.c | 12 +++ drivers/ub/cdma/cdma_context.c | 134 ++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_context.h | 7 ++ drivers/ub/cdma/cdma_dev.c | 71 +++++++++++++++++ drivers/ub/cdma/cdma_dev.h | 1 + drivers/ub/cdma/cdma_ioctl.c | 121 +++++++++++++++++++++++++++- drivers/ub/cdma/cdma_queue.c | 103 ++++++++++++++++++++++++ drivers/ub/cdma/cdma_queue.h | 26 +++++++ drivers/ub/cdma/cdma_types.h | 4 + drivers/ub/cdma/cdma_uobj.c | 121 ++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_uobj.h | 34 ++++++++ include/uapi/ub/cdma/cdma_abi.h | 25 ++++++ include/ub/cdma/cdma_api.h | 14 ++++ 16 files changed, 799 insertions(+), 2 deletions(-) create mode 100644 drivers/ub/cdma/cdma_context.c create mode 100644 drivers/ub/cdma/cdma_queue.c create mode 100644 drivers/ub/cdma/cdma_queue.h create mode 100644 drivers/ub/cdma/cdma_uobj.c create mode 100644 drivers/ub/cdma/cdma_uobj.h diff --git a/drivers/ub/cdma/Makefile b/drivers/ub/cdma/Makefile index 332700d90004..8c536d7a26c7 100644 --- a/drivers/ub/cdma/Makefile +++ b/drivers/ub/cdma/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0+ cdma-$(CONFIG_UB_CDMA) := cdma_main.o cdma_dev.o cdma_chardev.o cdma_cmd.o cdma_tid.o cdma_ioctl.o \ - cdma_api.o + cdma_api.o cdma_context.o cdma_queue.o cdma_uobj.o obj-m += cdma.o diff --git a/drivers/ub/cdma/cdma.h b/drivers/ub/cdma/cdma.h index 4a9720af8681..c527a1bee1af 100644 --- a/drivers/ub/cdma/cdma.h +++ b/drivers/ub/cdma/cdma.h @@ -21,6 +21,13 @@ enum cdma_status { CDMA_SUSPEND, }; +enum { + CDMA_CAP_FEATURE_AR = BIT(0), + CDMA_CAP_FEATURE_JFC_INLINE = BIT(4), + CDMA_CAP_FEATURE_DIRECT_WQE = BIT(11), + CDMA_CAP_FEATURE_CONG_CTRL = BIT(16), +}; + struct cdma_res { u32 max_cnt; u32 start_idx; @@ -78,6 +85,18 @@ struct cdma_caps { struct cdma_tbl seid; }; +struct cdma_idr { + struct idr idr; + u32 min; + u32 max; + u32 next; +}; + +struct cdma_table { + spinlock_t lock; + struct cdma_idr idr_tbl; +}; + struct cdma_chardev { struct device *dev; @@ -106,10 +125,15 @@ struct cdma_dev { void __iomem *k_db_base; resource_size_t db_base; struct iommu_sva *ksva; + /* ctx manager */ + struct list_head ctx_list; + struct idr ctx_idr; + spinlock_t ctx_lock; struct mutex eu_mutex; struct mutex db_mutex; struct list_head db_page; + struct cdma_table queue_table; struct mutex file_mutex; struct list_head file_list; struct page *arm_db_page; diff --git a/drivers/ub/cdma/cdma_api.c b/drivers/ub/cdma/cdma_api.c index e918f9899494..29053d5b0255 100644 --- a/drivers/ub/cdma/cdma_api.c +++ b/drivers/ub/cdma/cdma_api.c @@ -7,6 +7,7 @@ #include "cdma_dev.h" #include "cdma_cmd.h" #include "cdma_context.h" +#include "cdma_queue.h" #include "cdma.h" #include @@ -135,3 +136,104 @@ struct dma_device *dma_get_device_by_eid(struct dev_eid *eid) return NULL; } EXPORT_SYMBOL_GPL(dma_get_device_by_eid); + +int dma_create_context(struct dma_device *dma_dev) +{ + struct cdma_ctx_res *ctx_res; + struct cdma_context *ctx; + struct cdma_dev *cdev; + + if (!dma_dev || !dma_dev->private_data) { + pr_err("the dma_dev does not exist.\n"); + return -EINVAL; + } + + cdev = get_cdma_dev_by_eid(dma_dev->attr.eid.dw0); + if (!cdev) { + pr_err("can't find cdev by eid, eid = 0x%x\n", + dma_dev->attr.eid.dw0); + return -EINVAL; + } + + if (cdev->status == CDMA_SUSPEND) { + pr_warn("cdma device is not prepared, eid = 0x%x.\n", + dma_dev->attr.eid.dw0); + return -EINVAL; + } + + ctx_res = (struct cdma_ctx_res *)dma_dev->private_data; + if (ctx_res->ctx) { + pr_err("ctx has been created.\n"); + return -EEXIST; + } + + atomic_inc(&dma_dev->ref_cnt); + ctx = cdma_alloc_context(cdev, true); + if (IS_ERR(ctx)) { + pr_err("alloc context failed, ret = %ld\n", PTR_ERR(ctx)); + atomic_dec(&dma_dev->ref_cnt); + return PTR_ERR(ctx); + } + ctx_res->ctx = ctx; + + return ctx->handle; +} +EXPORT_SYMBOL_GPL(dma_create_context); + +int dma_alloc_queue(struct dma_device *dma_dev, int ctx_id, struct queue_cfg *cfg) +{ + struct cdma_ctx_res *ctx_res; + struct cdma_queue *queue; + struct cdma_context *ctx; + struct cdma_dev *cdev; + int ret; + + if (!cfg || !dma_dev || !dma_dev->private_data) + return -EINVAL; + + cdev = get_cdma_dev_by_eid(dma_dev->attr.eid.dw0); + if (!cdev) { + pr_err("can't find cdev by eid, eid = 0x%x.\n", + dma_dev->attr.eid.dw0); + return -EINVAL; + } + + if (cdev->status == CDMA_SUSPEND) { + pr_warn("cdma device is not prepared, eid = 0x%x.\n", + dma_dev->attr.eid.dw0); + return -EINVAL; + } + + ctx = cdma_find_ctx_by_handle(cdev, ctx_id); + if (!ctx) { + dev_err(cdev->dev, "invalid ctx_id = %d.\n", ctx_id); + return -EINVAL; + } + atomic_inc(&ctx->ref_cnt); + + queue = cdma_create_queue(cdev, ctx, cfg, dma_dev->attr.eu.eid_idx, + true); + if (!queue) { + dev_err(cdev->dev, "create queue failed.\n"); + ret = -EINVAL; + goto decrease_cnt; + } + + ctx_res = (struct cdma_ctx_res *)dma_dev->private_data; + ret = xa_err( + xa_store(&ctx_res->queue_xa, queue->id, queue, GFP_KERNEL)); + if (ret) { + dev_err(cdev->dev, "store queue to ctx_res failed, ret = %d\n", + ret); + goto free_queue; + } + + return queue->id; + +free_queue: + cdma_delete_queue(cdev, queue->id); +decrease_cnt: + atomic_dec(&ctx->ref_cnt); + return ret; +} +EXPORT_SYMBOL_GPL(dma_alloc_queue); diff --git a/drivers/ub/cdma/cdma_chardev.c b/drivers/ub/cdma/cdma_chardev.c index 094a71cbc531..9cd785cc6d41 100644 --- a/drivers/ub/cdma/cdma_chardev.c +++ b/drivers/ub/cdma/cdma_chardev.c @@ -7,8 +7,10 @@ #include #include #include "cdma_ioctl.h" +#include "cdma_context.h" #include "cdma_chardev.h" #include "cdma_types.h" +#include "cdma_uobj.h" #include "cdma.h" #define CDMA_DEVICE_NAME "cdma/dev" @@ -80,10 +82,13 @@ static int cdma_open(struct inode *inode, struct file *file) if (!cfile) return -ENOMEM; + cdma_init_uobj_idr(cfile); mutex_lock(&cdev->file_mutex); cfile->cdev = cdev; + cfile->uctx = NULL; kref_init(&cfile->ref); file->private_data = cfile; + mutex_init(&cfile->ctx_mutex); list_add_tail(&cfile->list, &cdev->file_list); nonseekable_open(inode, file); mutex_unlock(&cdev->file_mutex); @@ -102,6 +107,11 @@ static int cdma_close(struct inode *inode, struct file *file) list_del(&cfile->list); mutex_unlock(&cdev->file_mutex); + mutex_lock(&cfile->ctx_mutex); + cdma_cleanup_context_uobj(cfile); + cfile->uctx = NULL; + + mutex_unlock(&cfile->ctx_mutex); kref_put(&cfile->ref, cdma_release_file); pr_debug("cdma close success.\n"); @@ -184,5 +194,7 @@ void cdma_release_file(struct kref *ref) { struct cdma_file *cfile = container_of(ref, struct cdma_file, ref); + mutex_destroy(&cfile->ctx_mutex); + idr_destroy(&cfile->idr); kfree(cfile); } diff --git a/drivers/ub/cdma/cdma_context.c b/drivers/ub/cdma/cdma_context.c new file mode 100644 index 000000000000..f13dcf8ccdbd --- /dev/null +++ b/drivers/ub/cdma/cdma_context.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include +#include +#include "cdma.h" +#include "cdma_context.h" + +static void cdma_ctx_handle_free(struct cdma_dev *cdev, + struct cdma_context *ctx) +{ + spin_lock(&cdev->ctx_lock); + idr_remove(&cdev->ctx_idr, ctx->handle); + spin_unlock(&cdev->ctx_lock); +} + +static int cdma_ctx_handle_alloc(struct cdma_dev *cdev, + struct cdma_context *ctx) +{ +#define CDMA_CTX_START 0 +#define CDMA_CTX_END 0xff + int id; + + idr_preload(GFP_KERNEL); + spin_lock(&cdev->ctx_lock); + id = idr_alloc(&cdev->ctx_idr, ctx, CDMA_CTX_START, CDMA_CTX_END, + GFP_NOWAIT); + spin_unlock(&cdev->ctx_lock); + idr_preload_end(); + + return id; +} + +struct cdma_context *cdma_find_ctx_by_handle(struct cdma_dev *cdev, int handle) +{ + struct cdma_context *ctx; + + spin_lock(&cdev->ctx_lock); + ctx = idr_find(&cdev->ctx_idr, handle); + spin_unlock(&cdev->ctx_lock); + + return ctx; +} + +static int cdma_ctx_alloc_tid(struct cdma_dev *cdev, struct cdma_context *ctx) +{ + struct ummu_param drvdata = { .mode = MAPT_MODE_TABLE }; + int ret; + + if (ctx->is_kernel) + ctx->sva = ummu_ksva_bind_device(cdev->dev, &drvdata); + else + ctx->sva = ummu_sva_bind_device(cdev->dev, current->mm, NULL); + + if (!ctx->sva) { + dev_err(cdev->dev, "%s bind device failed.\n", + ctx->is_kernel ? "KSVA" : "SVA"); + return -EFAULT; + } + + ret = ummu_get_tid(cdev->dev, ctx->sva, &ctx->tid); + if (ret) { + dev_err(cdev->dev, "get tid failed, ret = %d.\n", ret); + if (ctx->is_kernel) + ummu_ksva_unbind_device(ctx->sva); + else + ummu_sva_unbind_device(ctx->sva); + } + + return ret; +} + +static void cdma_ctx_free_tid(struct cdma_dev *cdev, struct cdma_context *ctx) +{ + if (ctx->is_kernel) + ummu_ksva_unbind_device(ctx->sva); + else + ummu_sva_unbind_device(ctx->sva); +} + +struct cdma_context *cdma_alloc_context(struct cdma_dev *cdev, bool is_kernel) +{ + struct cdma_context *ctx; + int ret; + + if (!cdev) + return ERR_PTR(-EINVAL); + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return ERR_PTR(-ENOMEM); + + ctx->handle = cdma_ctx_handle_alloc(cdev, ctx); + if (ctx->handle < 0) { + dev_err(cdev->dev, + "Alloc context handle failed, ret = %d.\n", ctx->handle); + ret = ctx->handle; + goto free_ctx; + } + + ctx->cdev = cdev; + ctx->is_kernel = is_kernel; + ret = cdma_ctx_alloc_tid(cdev, ctx); + if (ret) { + dev_err(cdev->dev, "alloc ctx tid failed, ret = %d.\n", ret); + goto free_handle; + } + + spin_lock_init(&ctx->lock); + INIT_LIST_HEAD(&ctx->pgdir_list); + mutex_init(&ctx->pgdir_mutex); + INIT_LIST_HEAD(&ctx->queue_list); + + return ctx; + +free_handle: + cdma_ctx_handle_free(cdev, ctx); +free_ctx: + kfree(ctx); + return ERR_PTR(ret); +} + +void cdma_free_context(struct cdma_dev *cdev, struct cdma_context *ctx) +{ + if (!cdev || !ctx) + return; + + cdma_ctx_free_tid(cdev, ctx); + cdma_ctx_handle_free(cdev, ctx); + mutex_destroy(&ctx->pgdir_mutex); + kfree(ctx); +} diff --git a/drivers/ub/cdma/cdma_context.h b/drivers/ub/cdma/cdma_context.h index 3614be608534..8cbc980dc726 100644 --- a/drivers/ub/cdma/cdma_context.h +++ b/drivers/ub/cdma/cdma_context.h @@ -7,6 +7,7 @@ #include #include #include +#include #include struct cdma_context { @@ -20,10 +21,16 @@ struct cdma_context { u32 tid; bool is_kernel; atomic_t ref_cnt; + struct list_head queue_list; }; struct cdma_ctx_res { struct cdma_context *ctx; + struct xarray queue_xa; }; +struct cdma_context *cdma_find_ctx_by_handle(struct cdma_dev *cdev, int handle); +struct cdma_context *cdma_alloc_context(struct cdma_dev *cdev, bool is_kernel); +void cdma_free_context(struct cdma_dev *cdev, struct cdma_context *ctx); + #endif /* CDMA_CONTEXT_H */ diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index 10a4baa61e78..da730589ffd5 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -12,13 +12,27 @@ #include "cdma.h" #include "cdma_cmd.h" #include "cdma_tid.h" +#include "cdma_context.h" #include #include +#include "cdma_queue.h" #include "cdma_dev.h" static DEFINE_XARRAY(cdma_devs_tbl); static atomic_t cdma_devs_num = ATOMIC_INIT(0); +struct cdma_dev *get_cdma_dev_by_eid(u32 eid) +{ + struct cdma_dev *cdev = NULL; + unsigned long index = 0; + + xa_for_each(&cdma_devs_tbl, index, cdev) + if (cdev->eid == eid) + return cdev; + + return NULL; +} + struct xarray *get_cdma_dev_tbl(u32 *devs_num) { *devs_num = atomic_read(&cdma_devs_num); @@ -63,6 +77,40 @@ static void cdma_del_device_from_list(struct cdma_dev *cdev) xa_erase(&cdma_devs_tbl, adev->id); } +static void cdma_tbl_init(struct cdma_table *table, u32 max, u32 min) +{ + if (!max || max < min) + return; + + spin_lock_init(&table->lock); + idr_init(&table->idr_tbl.idr); + table->idr_tbl.max = max; + table->idr_tbl.min = min; + table->idr_tbl.next = min; +} + +static void cdma_tbl_destroy(struct cdma_dev *cdev, struct cdma_table *table, + const char *table_name) +{ + if (!idr_is_empty(&table->idr_tbl.idr)) + dev_err(cdev->dev, "IDR not empty in clean up %s table.\n", + table_name); + idr_destroy(&table->idr_tbl.idr); +} + +static void cdma_init_tables(struct cdma_dev *cdev) +{ + struct cdma_res *queue = &cdev->caps.queue; + + cdma_tbl_init(&cdev->queue_table, queue->start_idx + queue->max_cnt - 1, + queue->start_idx); +} + +static void cdma_destroy_tables(struct cdma_dev *cdev) +{ + cdma_tbl_destroy(cdev, &cdev->queue_table, "QUEUE"); +} + static void cdma_init_base_dev(struct cdma_dev *cdev) { struct cdma_device_attr *attr = &cdev->base.attr; @@ -102,6 +150,7 @@ static int cdma_init_dev_param(struct cdma_dev *cdev, return ret; cdma_init_base_dev(cdev); + cdma_init_tables(cdev); dev_set_drvdata(&adev->dev, cdev); @@ -120,6 +169,16 @@ static void cdma_uninit_dev_param(struct cdma_dev *cdev) mutex_destroy(&cdev->eu_mutex); mutex_destroy(&cdev->file_mutex); dev_set_drvdata(&cdev->adev->dev, NULL); + cdma_destroy_tables(cdev); +} + +static void cdma_release_table_res(struct cdma_dev *cdev) +{ + struct cdma_queue *queue; + int id; + + idr_for_each_entry(&cdev->queue_table.idr_tbl.idr, queue, id) + cdma_delete_queue(cdev, queue->id); } static int cdma_ctrlq_eu_add(struct cdma_dev *cdev, struct eu_info *eu) @@ -296,6 +355,9 @@ struct cdma_dev *cdma_create_dev(struct auxiliary_device *adev) if (cdma_create_arm_db_page(cdev)) goto unregister_crq; + idr_init(&cdev->ctx_idr); + spin_lock_init(&cdev->ctx_lock); + dev_dbg(&adev->dev, "cdma.%u init succeeded.\n", adev->id); return cdev; @@ -315,11 +377,20 @@ struct cdma_dev *cdma_create_dev(struct auxiliary_device *adev) void cdma_destroy_dev(struct cdma_dev *cdev) { + struct cdma_context *tmp; + int id; + if (!cdev) return; ubase_virt_unregister(cdev->adev); + cdma_release_table_res(cdev); + + idr_for_each_entry(&cdev->ctx_idr, tmp, id) + cdma_free_context(cdev, tmp); + idr_destroy(&cdev->ctx_idr); + cdma_destroy_arm_db_page(cdev); ubase_ctrlq_unregister_crq_event(cdev->adev, UBASE_CTRLQ_SER_TYPE_DEV_REGISTER, diff --git a/drivers/ub/cdma/cdma_dev.h b/drivers/ub/cdma/cdma_dev.h index 73dc4077a74e..75aa96b092c7 100644 --- a/drivers/ub/cdma/cdma_dev.h +++ b/drivers/ub/cdma/cdma_dev.h @@ -27,6 +27,7 @@ enum cdma_ctrlq_eu_op { struct cdma_dev *cdma_create_dev(struct auxiliary_device *adev); void cdma_destroy_dev(struct cdma_dev *cdev); +struct cdma_dev *get_cdma_dev_by_eid(u32 eid); struct xarray *get_cdma_dev_tbl(u32 *devices_num); bool cdma_find_seid_in_eus(struct eu_info *eus, u8 eu_num, struct dev_eid *eid, struct eu_info *eu_out); diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c index 518b5802f7e1..ba49d353408c 100644 --- a/drivers/ub/cdma/cdma_ioctl.c +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -7,7 +7,10 @@ #include #include "cdma.h" +#include "cdma_context.h" #include "cdma_types.h" +#include "cdma_queue.h" +#include "cdma_uobj.h" #include "cdma_ioctl.h" typedef int (*cdma_cmd_handler)(struct cdma_ioctl_hdr *hdr, @@ -53,13 +56,125 @@ static int cdma_query_dev(struct cdma_ioctl_hdr *hdr, struct cdma_file *cfile) return 0; } +static int cdma_create_ucontext(struct cdma_ioctl_hdr *hdr, + struct cdma_file *cfile) +{ + struct cdma_create_context_args args = { 0 }; + struct cdma_dev *cdev = cfile->cdev; + struct cdma_context *ctx; + int ret; + + if (cfile->uctx) { + dev_err(cdev->dev, "create jfae failed, ctx handle = %d.\n", + ctx->handle); + return -EEXIST; + } + + if (!hdr->args_addr || hdr->args_len < sizeof(args)) + return -EINVAL; + + ret = (int)copy_from_user(&args, (void *)hdr->args_addr, + (u32)sizeof(args)); + if (ret) { + dev_err(cdev->dev, "get user data failed, ret = %d.\n", ret); + return ret; + } + + ctx = cdma_alloc_context(cdev, false); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + args.out.cqe_size = cdev->caps.cqe_size; + args.out.dwqe_enable = + !!(cdev->caps.feature & CDMA_CAP_FEATURE_DIRECT_WQE); + cfile->uctx = ctx; + + ret = (int)copy_to_user((void *)hdr->args_addr, &args, + (u32)sizeof(args)); + if (ret) { + dev_err(cdev->dev, "copy ctx to user failed, ret = %d.\n", ret); + goto free_context; + } + + return ret; + +free_context: + cfile->uctx = NULL; + cdma_free_context(cdev, ctx); + + return ret; +} + +static int cdma_cmd_create_queue(struct cdma_ioctl_hdr *hdr, struct cdma_file *cfile) +{ + struct cdma_cmd_create_queue_args arg = { 0 }; + struct cdma_dev *cdev = cfile->cdev; + struct queue_cfg cfg; + struct cdma_queue *queue; + struct cdma_uobj *uobj; + int ret; + + if (!hdr->args_addr || hdr->args_len != sizeof(arg) || !cfile->uctx) + return -EINVAL; + + ret = (int)copy_from_user(&arg, (void *)hdr->args_addr, + (u32)sizeof(arg)); + if (ret) { + dev_err(cdev->dev, "create queue get user data failed, ret = %d.\n", ret); + return -EFAULT; + } + + cfg = (struct queue_cfg) { + .queue_depth = arg.in.queue_depth, + .dcna = arg.in.dcna, + .priority = arg.in.priority, + .rmt_eid.dw0 = arg.in.rmt_eid, + .user_ctx = arg.in.user_ctx, + .trans_mode = arg.in.trans_mode, + }; + + uobj = cdma_uobj_create(cfile, UOBJ_TYPE_QUEUE); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, "create queue uobj failed.\n"); + return -ENOMEM; + } + + queue = cdma_create_queue(cdev, cfile->uctx, &cfg, 0, false); + if (!queue) { + dev_err(cdev->dev, "create queue failed.\n"); + ret = -EINVAL; + goto err_create_queue; + } + + uobj->object = queue; + arg.out.queue_id = queue->id; + arg.out.handle = uobj->id; + ret = (int)copy_to_user((void *)hdr->args_addr, &arg, (u32)sizeof(arg)); + if (ret) { + dev_err(cdev->dev, "create queue copy to user failed, ret = %d.\n", ret); + ret = -EFAULT; + goto err_copy_to_user; + } + list_add_tail(&queue->list, &cfile->uctx->queue_list); + + return 0; +err_copy_to_user: + cdma_delete_queue(cdev, queue->id); +err_create_queue: + cdma_uobj_delete(uobj); + return ret; +} + static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { [CDMA_CMD_QUERY_DEV_INFO] = cdma_query_dev, + [CDMA_CMD_CREATE_CTX] = cdma_create_ucontext, + [CDMA_CMD_CREATE_QUEUE] = cdma_cmd_create_queue, }; int cdma_cmd_parse(struct cdma_file *cfile, struct cdma_ioctl_hdr *hdr) { struct cdma_dev *cdev = cfile->cdev; + int ret; if (hdr->command >= CDMA_CMD_MAX || !g_cdma_cmd_handler[hdr->command]) { dev_err(cdev->dev, @@ -68,5 +183,9 @@ int cdma_cmd_parse(struct cdma_file *cfile, struct cdma_ioctl_hdr *hdr) return -EINVAL; } - return g_cdma_cmd_handler[hdr->command](hdr, cfile); + mutex_lock(&cfile->ctx_mutex); + ret = g_cdma_cmd_handler[hdr->command](hdr, cfile); + mutex_unlock(&cfile->ctx_mutex); + + return ret; } diff --git a/drivers/ub/cdma/cdma_queue.c b/drivers/ub/cdma/cdma_queue.c new file mode 100644 index 000000000000..93ffcab5ecc6 --- /dev/null +++ b/drivers/ub/cdma/cdma_queue.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include "cdma_context.h" +#include "cdma_queue.h" +#include "cdma.h" + +struct cdma_queue *cdma_find_queue(struct cdma_dev *cdev, u32 queue_id) +{ + struct cdma_queue *queue; + + spin_lock(&cdev->queue_table.lock); + queue = (struct cdma_queue *)idr_find(&cdev->queue_table.idr_tbl.idr, + queue_id); + spin_unlock(&cdev->queue_table.lock); + + return queue; +} + +static int cdma_alloc_queue_id(struct cdma_dev *cdev, struct cdma_queue *queue) +{ + struct cdma_table *queue_tbl = &cdev->queue_table; + int id; + + idr_preload(GFP_KERNEL); + spin_lock(&queue_tbl->lock); + id = idr_alloc(&queue_tbl->idr_tbl.idr, queue, queue_tbl->idr_tbl.min, + queue_tbl->idr_tbl.max, GFP_NOWAIT); + if (id < 0) + dev_err(cdev->dev, "alloc queue id failed.\n"); + spin_unlock(&queue_tbl->lock); + idr_preload_end(); + + return id; +} + +static void cdma_delete_queue_id(struct cdma_dev *cdev, int queue_id) +{ + struct cdma_table *queue_tbl = &cdev->queue_table; + + spin_lock(&queue_tbl->lock); + idr_remove(&queue_tbl->idr_tbl.idr, queue_id); + spin_unlock(&queue_tbl->lock); +} + +struct cdma_queue *cdma_create_queue(struct cdma_dev *cdev, + struct cdma_context *uctx, + struct queue_cfg *cfg, u32 eid_index, + bool is_kernel) +{ + struct cdma_queue *queue; + int id; + + queue = kzalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) + return NULL; + + id = cdma_alloc_queue_id(cdev, queue); + if (id < 0) { + kfree(queue); + return NULL; + } + + queue->ctx = uctx; + queue->id = id; + queue->cfg = *cfg; + + if (is_kernel) + queue->is_kernel = true; + + return queue; +} + +int cdma_delete_queue(struct cdma_dev *cdev, u32 queue_id) +{ + struct cdma_queue *queue; + + if (!cdev) + return -EINVAL; + + if (queue_id >= cdev->caps.queue.start_idx + cdev->caps.queue.max_cnt) { + dev_err(cdev->dev, + "queue id invalid, queue_id = %u, start_idx = %u, max_cnt = %u.\n", + queue_id, cdev->caps.queue.start_idx, + cdev->caps.queue.max_cnt); + return -EINVAL; + } + + queue = cdma_find_queue(cdev, queue_id); + if (!queue) { + dev_err(cdev->dev, "get queue from table failed, id = %u.\n", + queue_id); + return -EINVAL; + } + + cdma_delete_queue_id(cdev, queue_id); + + kfree(queue); + + return 0; +} diff --git a/drivers/ub/cdma/cdma_queue.h b/drivers/ub/cdma/cdma_queue.h new file mode 100644 index 000000000000..0299a026a14b --- /dev/null +++ b/drivers/ub/cdma/cdma_queue.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_QUEUE_H__ +#define __CDMA_QUEUE_H__ + +struct cdma_dev; +struct cdma_context; +struct queue_cfg; + +struct cdma_queue { + struct cdma_context *ctx; + u32 id; + struct queue_cfg cfg; + bool is_kernel; + struct list_head list; +}; + +struct cdma_queue *cdma_find_queue(struct cdma_dev *cdev, u32 queue_id); +struct cdma_queue *cdma_create_queue(struct cdma_dev *cdev, + struct cdma_context *uctx, + struct queue_cfg *cfg, u32 eid_index, + bool is_kernel); +int cdma_delete_queue(struct cdma_dev *cdev, u32 queue_id); + +#endif diff --git a/drivers/ub/cdma/cdma_types.h b/drivers/ub/cdma/cdma_types.h index 4ef38c23e22c..9f3af5c06bbe 100644 --- a/drivers/ub/cdma/cdma_types.h +++ b/drivers/ub/cdma/cdma_types.h @@ -13,6 +13,10 @@ struct cdma_dev; struct cdma_file { struct cdma_dev *cdev; struct list_head list; + struct mutex ctx_mutex; + struct cdma_context *uctx; + struct idr idr; + spinlock_t idr_lock; struct kref ref; }; diff --git a/drivers/ub/cdma/cdma_uobj.c b/drivers/ub/cdma/cdma_uobj.c new file mode 100644 index 000000000000..3e6e1f9ad1b6 --- /dev/null +++ b/drivers/ub/cdma/cdma_uobj.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#include +#include "cdma_uobj.h" +#include "cdma_chardev.h" + +static int cdma_uobj_alloc_idr(struct cdma_uobj *uobj) +{ + int ret; + + idr_preload(GFP_KERNEL); + spin_lock(&uobj->cfile->idr_lock); + + ret = idr_alloc(&uobj->cfile->idr, uobj, 0, U32_MAX, GFP_NOWAIT); + if (ret >= 0) + uobj->id = ret; + + spin_unlock(&uobj->cfile->idr_lock); + idr_preload_end(); + + return ret < 0 ? ret : 0; +} + +static inline void cdma_uobj_remove_idr(struct cdma_uobj *uobj) +{ + spin_lock(&uobj->cfile->idr_lock); + idr_remove(&uobj->cfile->idr, uobj->id); + spin_unlock(&uobj->cfile->idr_lock); +} + +static struct cdma_uobj *cdma_uobj_alloc(struct cdma_file *cfile, + enum UOBJ_TYPE obj_type) +{ + struct cdma_uobj *uobj; + + uobj = kzalloc(sizeof(*uobj), GFP_KERNEL); + if (uobj == NULL) + return ERR_PTR(-ENOMEM); + + atomic_set(&uobj->rcnt, 0); + uobj->cfile = cfile; + uobj->type = obj_type; + + return uobj; +} + +static inline void cdma_uobj_free(struct cdma_uobj *uobj) +{ + kfree(uobj); +} + +static inline void cdma_uobj_remove(struct cdma_uobj *uobj) +{ + idr_remove(&uobj->cfile->idr, uobj->id); + cdma_uobj_free(uobj); +} + +void cdma_init_uobj_idr(struct cdma_file *cfile) +{ + idr_init(&cfile->idr); + spin_lock_init(&cfile->idr_lock); +} + +struct cdma_uobj *cdma_uobj_create(struct cdma_file *cfile, + enum UOBJ_TYPE obj_type) +{ + struct cdma_uobj *uobj; + int ret; + + uobj = cdma_uobj_alloc(cfile, obj_type); + if (IS_ERR(uobj)) + return uobj; + + ret = cdma_uobj_alloc_idr(uobj); + if (ret) + goto err_free_uobj; + + return uobj; + +err_free_uobj: + cdma_uobj_free(uobj); + + return ERR_PTR(ret); +} + +void cdma_uobj_delete(struct cdma_uobj *uobj) +{ + cdma_uobj_remove_idr(uobj); + cdma_uobj_free(uobj); +} + +struct cdma_uobj *cdma_uobj_get(struct cdma_file *cfile, int id, + enum UOBJ_TYPE obj_type) +{ + struct cdma_uobj *uobj; + + spin_lock(&cfile->idr_lock); + uobj = idr_find(&cfile->idr, id); + if (uobj == NULL || uobj->type != obj_type) + uobj = ERR_PTR(-ENOENT); + spin_unlock(&cfile->idr_lock); + + return uobj; +} + +void cdma_cleanup_context_uobj(struct cdma_file *cfile) +{ + struct cdma_uobj *uobj; + int id; + + spin_lock(&cfile->idr_lock); + idr_for_each_entry(&cfile->idr, uobj, id) + cdma_uobj_remove(uobj); + spin_unlock(&cfile->idr_lock); +} + +void cdma_close_uobj_fd(struct cdma_file *cfile) +{ + kref_put(&cfile->ref, cdma_release_file); +} diff --git a/drivers/ub/cdma/cdma_uobj.h b/drivers/ub/cdma/cdma_uobj.h new file mode 100644 index 000000000000..505a66911960 --- /dev/null +++ b/drivers/ub/cdma/cdma_uobj.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_UOBJ_H__ +#define __CDMA_UOBJ_H__ +#include "cdma_types.h" + +enum UOBJ_TYPE { + UOBJ_TYPE_JFCE, + UOBJ_TYPE_JFC, + UOBJ_TYPE_CTP, + UOBJ_TYPE_JFS, + UOBJ_TYPE_QUEUE, + UOBJ_TYPE_SEGMENT +}; + +struct cdma_uobj { + struct cdma_file *cfile; + enum UOBJ_TYPE type; + int id; + void *object; + atomic_t rcnt; +}; + +void cdma_init_uobj_idr(struct cdma_file *cfile); +struct cdma_uobj *cdma_uobj_create(struct cdma_file *cfile, + enum UOBJ_TYPE obj_type); +void cdma_uobj_delete(struct cdma_uobj *uobj); +struct cdma_uobj *cdma_uobj_get(struct cdma_file *cfile, int id, + enum UOBJ_TYPE type); +void cdma_cleanup_context_uobj(struct cdma_file *cfile); +void cdma_close_uobj_fd(struct cdma_file *cfile); + +#endif diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h index c72268f4460a..a5142e0700ab 100644 --- a/include/uapi/ub/cdma/cdma_abi.h +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -12,6 +12,8 @@ enum cdma_cmd { CDMA_CMD_QUERY_DEV_INFO, + CDMA_CMD_CREATE_CTX, + CDMA_CMD_CREATE_QUEUE, CDMA_CMD_MAX }; @@ -65,4 +67,27 @@ struct cdma_cmd_query_device_attr_args { } out; }; +struct cdma_create_context_args { + struct { + __u8 cqe_size; + __u8 dwqe_enable; + int async_fd; + } out; +}; + +struct cdma_cmd_create_queue_args { + struct { + __u32 queue_depth; + __u32 dcna; + __u32 rmt_eid; + __u8 priority; + __u64 user_ctx; + __u32 trans_mode; + } in; + struct { + int queue_id; + __u64 handle; + } out; +}; + #endif diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index 759f455581a9..5b64d1498a48 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -13,6 +13,15 @@ struct dma_device { void *private_data; }; +struct queue_cfg { + u32 queue_depth; + u8 priority; + u64 user_ctx; + u32 dcna; + struct dev_eid rmt_eid; + u32 trans_mode; +}; + struct dma_context { struct dma_device *dma_dev; u32 tid; /* data valid only in bit 0-19 */ @@ -24,4 +33,9 @@ void dma_free_device_list(struct dma_device *dev_list, u32 num_devices); struct dma_device *dma_get_device_by_eid(struct dev_eid *eid); +int dma_create_context(struct dma_device *dma_dev); + +int dma_alloc_queue(struct dma_device *dma_dev, int ctx_id, + struct queue_cfg *cfg); + #endif -- Gitee From a91b2cf5c6b0043f063bd2a08c0ed0ff60922d87 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Thu, 28 Aug 2025 21:47:12 +0800 Subject: [PATCH 011/103] ub: cdma: support for releasing queue commit f72102db2ef32d4d05890e6d9827cd3e955655f9 openEuler This patch implements the functionality of removing user context and deleting queue APIs in the CDMA driver. The implementation includes support for the dma_delete_context and dma_free_queue interfaces. Signed-off-by: Zhipeng Lu Signed-off-by: Xinchi Ma Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma_api.c | 71 +++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_ioctl.c | 60 ++++++++++++++++++++++++++++ include/uapi/ub/cdma/cdma_abi.h | 9 +++++ include/ub/cdma/cdma_api.h | 4 ++ 4 files changed, 144 insertions(+) diff --git a/drivers/ub/cdma/cdma_api.c b/drivers/ub/cdma/cdma_api.c index 29053d5b0255..34a2d96f7c3c 100644 --- a/drivers/ub/cdma/cdma_api.c +++ b/drivers/ub/cdma/cdma_api.c @@ -180,6 +180,44 @@ int dma_create_context(struct dma_device *dma_dev) } EXPORT_SYMBOL_GPL(dma_create_context); +void dma_delete_context(struct dma_device *dma_dev, int handle) +{ + struct cdma_ctx_res *ctx_res; + struct cdma_context *ctx; + struct cdma_dev *cdev; + int ref_cnt; + + if (!dma_dev || !dma_dev->private_data) + return; + + cdev = get_cdma_dev_by_eid(dma_dev->attr.eid.dw0); + if (!cdev) { + pr_err("can't find cdev by eid, eid = 0x%x\n", + dma_dev->attr.eid.dw0); + return; + } + + ctx_res = (struct cdma_ctx_res *)dma_dev->private_data; + ctx = ctx_res->ctx; + if (!ctx) { + dev_err(cdev->dev, "no context needed to be free\n"); + return; + } + + ref_cnt = atomic_read(&ctx->ref_cnt); + if (ref_cnt > 0) { + dev_warn(cdev->dev, + "context resourse is still in use, cnt = %d.\n", + ref_cnt); + return; + } + + cdma_free_context(cdev, ctx); + ctx_res->ctx = NULL; + atomic_dec(&dma_dev->ref_cnt); +} +EXPORT_SYMBOL_GPL(dma_delete_context); + int dma_alloc_queue(struct dma_device *dma_dev, int ctx_id, struct queue_cfg *cfg) { struct cdma_ctx_res *ctx_res; @@ -237,3 +275,36 @@ int dma_alloc_queue(struct dma_device *dma_dev, int ctx_id, struct queue_cfg *cf return ret; } EXPORT_SYMBOL_GPL(dma_alloc_queue); + +void dma_free_queue(struct dma_device *dma_dev, int queue_id) +{ + struct cdma_ctx_res *ctx_res; + struct cdma_context *ctx; + struct cdma_queue *queue; + struct cdma_dev *cdev; + + if (!dma_dev || !dma_dev->private_data) + return; + + cdev = get_cdma_dev_by_eid(dma_dev->attr.eid.dw0); + if (!cdev) { + pr_err("can't find cdev by eid, eid = 0x%x\n", + dma_dev->attr.eid.dw0); + return; + } + + ctx_res = (struct cdma_ctx_res *)dma_dev->private_data; + queue = (struct cdma_queue *)xa_load(&ctx_res->queue_xa, queue_id); + if (!queue) { + dev_err(cdev->dev, "no queue found in this device, id = %d\n", + queue_id); + return; + } + xa_erase(&ctx_res->queue_xa, queue_id); + ctx = queue->ctx; + + cdma_delete_queue(cdev, queue_id); + + atomic_dec(&ctx->ref_cnt); +} +EXPORT_SYMBOL_GPL(dma_free_queue); diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c index ba49d353408c..89094aaebc1f 100644 --- a/drivers/ub/cdma/cdma_ioctl.c +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -105,6 +105,28 @@ static int cdma_create_ucontext(struct cdma_ioctl_hdr *hdr, return ret; } +static int cdma_delete_ucontext(struct cdma_ioctl_hdr *hdr, + struct cdma_file *cfile) +{ + struct cdma_dev *cdev = cfile->cdev; + + if (!cfile->uctx) { + dev_err(cdev->dev, "cdma context has not been created.\n"); + return -ENOENT; + } + if (!list_empty(&cfile->uctx->queue_list)) { + dev_err(cdev->dev, + "queue/segment is still in use, ctx handle = %d.\n", + cfile->uctx->handle); + return -EBUSY; + } + + cdma_free_context(cdev, cfile->uctx); + cfile->uctx = NULL; + + return 0; +} + static int cdma_cmd_create_queue(struct cdma_ioctl_hdr *hdr, struct cdma_file *cfile) { struct cdma_cmd_create_queue_args arg = { 0 }; @@ -165,10 +187,48 @@ static int cdma_cmd_create_queue(struct cdma_ioctl_hdr *hdr, struct cdma_file *c return ret; } +static int cdma_cmd_delete_queue(struct cdma_ioctl_hdr *hdr, struct cdma_file *cfile) +{ + struct cdma_cmd_delete_queue_args arg = { 0 }; + struct cdma_dev *cdev = cfile->cdev; + struct cdma_queue *queue; + struct cdma_uobj *uobj; + int ret; + + if (!hdr->args_addr || hdr->args_len != sizeof(arg)) + return -EINVAL; + + ret = (int)copy_from_user(&arg, (void *)hdr->args_addr, + (u32)sizeof(arg)); + if (ret) { + dev_err(cdev->dev, "delete queue get user data failed, ret = %d.\n", ret); + return -EFAULT; + } + + uobj = cdma_uobj_get(cfile, arg.in.handle, UOBJ_TYPE_QUEUE); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, "get queue uobj failed, handle = %llu.\n", + arg.in.handle); + return -EINVAL; + } + + queue = (struct cdma_queue *)uobj->object; + + cdma_uobj_delete(uobj); + list_del(&queue->list); + ret = cdma_delete_queue(cdev, queue->id); + if (ret) + dev_err(cdev->dev, "delete queue failed, ret = %d.\n", ret); + + return ret; +} + static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { [CDMA_CMD_QUERY_DEV_INFO] = cdma_query_dev, [CDMA_CMD_CREATE_CTX] = cdma_create_ucontext, + [CDMA_CMD_DELETE_CTX] = cdma_delete_ucontext, [CDMA_CMD_CREATE_QUEUE] = cdma_cmd_create_queue, + [CDMA_CMD_DELETE_QUEUE] = cdma_cmd_delete_queue, }; int cdma_cmd_parse(struct cdma_file *cfile, struct cdma_ioctl_hdr *hdr) diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h index a5142e0700ab..50bca1fab02b 100644 --- a/include/uapi/ub/cdma/cdma_abi.h +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -13,7 +13,9 @@ enum cdma_cmd { CDMA_CMD_QUERY_DEV_INFO, CDMA_CMD_CREATE_CTX, + CDMA_CMD_DELETE_CTX, CDMA_CMD_CREATE_QUEUE, + CDMA_CMD_DELETE_QUEUE, CDMA_CMD_MAX }; @@ -90,4 +92,11 @@ struct cdma_cmd_create_queue_args { } out; }; +struct cdma_cmd_delete_queue_args { + struct { + __u32 queue_id; + __u64 handle; + } in; +}; + #endif diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index 5b64d1498a48..5ebe4feebd1c 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -35,7 +35,11 @@ struct dma_device *dma_get_device_by_eid(struct dev_eid *eid); int dma_create_context(struct dma_device *dma_dev); +void dma_delete_context(struct dma_device *dma_dev, int handle); + int dma_alloc_queue(struct dma_device *dma_dev, int ctx_id, struct queue_cfg *cfg); +void dma_free_queue(struct dma_device *dma_dev, int queue_id); + #endif -- Gitee From 21f36cc94c335a59b8fe9dd2fe0bb68d04d0e5d8 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 09:04:22 +0800 Subject: [PATCH 012/103] ub: cdma: support the deletion of jfc commit 9d00a496c9121ebddeb9d8278da2669952db3d4d openEuler This patch implements the deletion functionality of jfc in the CDMA driver. The implementation involves deleting the jfc corresponding to the queue during the queue release process. Signed-off-by: Zhipeng Lu Signed-off-by: Bangwei Zhang Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/Makefile | 3 +- drivers/ub/cdma/cdma.h | 41 +++++++++ drivers/ub/cdma/cdma_common.c | 51 +++++++++++ drivers/ub/cdma/cdma_common.h | 20 +++++ drivers/ub/cdma/cdma_db.c | 45 ++++++++++ drivers/ub/cdma/cdma_db.h | 39 +++++++++ drivers/ub/cdma/cdma_dev.c | 6 ++ drivers/ub/cdma/cdma_ioctl.c | 62 ++++++++++++++ drivers/ub/cdma/cdma_jfc.c | 145 ++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_jfc.h | 104 +++++++++++++++++++++++ drivers/ub/cdma/cdma_mbox.c | 65 ++++++++++++++ drivers/ub/cdma/cdma_mbox.h | 44 ++++++++++ drivers/ub/cdma/cdma_queue.c | 31 +++++++ drivers/ub/cdma/cdma_queue.h | 9 +- drivers/ub/cdma/cdma_types.h | 15 ++++ include/uapi/ub/cdma/cdma_abi.h | 58 +++++++++++++ 16 files changed, 736 insertions(+), 2 deletions(-) create mode 100644 drivers/ub/cdma/cdma_common.c create mode 100644 drivers/ub/cdma/cdma_common.h create mode 100644 drivers/ub/cdma/cdma_db.c create mode 100644 drivers/ub/cdma/cdma_db.h create mode 100644 drivers/ub/cdma/cdma_jfc.c create mode 100644 drivers/ub/cdma/cdma_jfc.h create mode 100644 drivers/ub/cdma/cdma_mbox.c create mode 100644 drivers/ub/cdma/cdma_mbox.h diff --git a/drivers/ub/cdma/Makefile b/drivers/ub/cdma/Makefile index 8c536d7a26c7..5bb71587ed6d 100644 --- a/drivers/ub/cdma/Makefile +++ b/drivers/ub/cdma/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+ cdma-$(CONFIG_UB_CDMA) := cdma_main.o cdma_dev.o cdma_chardev.o cdma_cmd.o cdma_tid.o cdma_ioctl.o \ - cdma_api.o cdma_context.o cdma_queue.o cdma_uobj.o + cdma_api.o cdma_context.o cdma_queue.o cdma_uobj.o cdma_jfc.o cdma_common.o \ + cdma_db.o cdma_mbox.o obj-m += cdma.o diff --git a/drivers/ub/cdma/cdma.h b/drivers/ub/cdma/cdma.h index c527a1bee1af..d43fc7be17d1 100644 --- a/drivers/ub/cdma/cdma.h +++ b/drivers/ub/cdma/cdma.h @@ -11,6 +11,8 @@ #include +extern u32 jfc_arm_mode; + #define CDMA_RESET_WAIT_TIME 3000 #define CDMA_MAX_SL_NUM 16 @@ -107,6 +109,44 @@ struct cdma_chardev { dev_t devno; }; +union cdma_umem_flag { + struct { + u32 non_pin : 1; /* 0: pinned to physical memory. 1: non pin. */ + u32 writable : 1; /* 0: read-only. 1: writable. */ + u32 reserved : 30; + } bs; + u32 value; +}; + +struct cdma_umem { + struct mm_struct *owning_mm; + union cdma_umem_flag flag; + struct sg_table sg_head; + struct cdma_dev *dev; + + u64 length; + u32 nmap; + u64 va; +}; + +struct cdma_buf { + dma_addr_t addr; /* pass to hw */ + union { + void *kva; /* used for kernel mode */ + struct iova_slot *slot; + void *kva_or_slot; + }; + void *aligned_va; + struct cdma_umem *umem; + u32 entry_cnt_mask; + u32 entry_cnt_mask_ilog2; + u32 entry_size; + u32 entry_cnt; + u32 cnt_per_page_shift; + struct xarray id_table_xa; + struct mutex id_table_mutex; +}; + struct cdma_dev { struct dma_device base; struct device *dev; @@ -134,6 +174,7 @@ struct cdma_dev { struct list_head db_page; struct cdma_table queue_table; + struct cdma_table jfc_table; struct mutex file_mutex; struct list_head file_list; struct page *arm_db_page; diff --git a/drivers/ub/cdma/cdma_common.c b/drivers/ub/cdma/cdma_common.c new file mode 100644 index 000000000000..291231eab627 --- /dev/null +++ b/drivers/ub/cdma/cdma_common.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include +#include +#include +#include "cdma_common.h" +#include "cdma.h" + +static void cdma_unpin_pages(struct cdma_umem *umem, u64 nents, bool is_kernel) +{ + struct scatterlist *sg; + struct page *page; + u32 i; + + for_each_sg(umem->sg_head.sgl, sg, nents, i) { + page = sg_page(sg); + + if (is_kernel) + put_page(page); + else + unpin_user_page(page); + } +} + +void cdma_umem_release(struct cdma_umem *umem, bool is_kernel) +{ + if (IS_ERR_OR_NULL(umem)) + return; + + cdma_unpin_pages(umem, umem->sg_head.nents, is_kernel); + sg_free_table(&umem->sg_head); + kfree(umem); +} + +void cdma_k_free_buf(struct cdma_dev *cdev, size_t memory_size, + struct cdma_buf *buf) +{ + cdma_umem_release(buf->umem, true); + vfree(buf->aligned_va); + buf->aligned_va = NULL; + buf->kva = NULL; + buf->addr = 0; +} + +void cdma_unpin_queue_addr(struct cdma_umem *umem) +{ + cdma_umem_release(umem, false); +} diff --git a/drivers/ub/cdma/cdma_common.h b/drivers/ub/cdma/cdma_common.h new file mode 100644 index 000000000000..644868418bf5 --- /dev/null +++ b/drivers/ub/cdma/cdma_common.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_COMMON_H__ +#define __CDMA_COMMON_H__ + +#include + +struct cdma_umem; +struct cdma_dev; +struct cdma_buf; + +void cdma_umem_release(struct cdma_umem *umem, bool is_kernel); + +void cdma_k_free_buf(struct cdma_dev *cdev, size_t memory_size, + struct cdma_buf *buf); + +void cdma_unpin_queue_addr(struct cdma_umem *umem); + +#endif diff --git a/drivers/ub/cdma/cdma_db.c b/drivers/ub/cdma/cdma_db.c new file mode 100644 index 000000000000..e1c39e612bf4 --- /dev/null +++ b/drivers/ub/cdma/cdma_db.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include +#include "cdma_common.h" +#include "cdma_context.h" +#include "cdma_db.h" + +static void cdma_free_db_page(struct cdma_dev *cdev, struct cdma_sw_db *db) +{ + cdma_k_free_buf(cdev, PAGE_SIZE, &db->kpage->db_buf); + bitmap_free(db->kpage->bitmap); + kfree(db->kpage); + db->kpage = NULL; +} + +void cdma_unpin_sw_db(struct cdma_context *ctx, struct cdma_sw_db *db) +{ + mutex_lock(&ctx->pgdir_mutex); + + if (refcount_dec_and_test(&db->page->refcount)) { + list_del(&db->page->list); + cdma_umem_release(db->page->umem, false); + kfree(db->page); + db->page = NULL; + } + + mutex_unlock(&ctx->pgdir_mutex); +} + +void cdma_free_sw_db(struct cdma_dev *cdev, struct cdma_sw_db *db) +{ + mutex_lock(&cdev->db_mutex); + + set_bit(db->index, db->kpage->bitmap); + + if (bitmap_full(db->kpage->bitmap, db->kpage->num_db)) { + list_del(&db->kpage->list); + cdma_free_db_page(cdev, db); + } + + mutex_unlock(&cdev->db_mutex); +} diff --git a/drivers/ub/cdma/cdma_db.h b/drivers/ub/cdma/cdma_db.h new file mode 100644 index 000000000000..5337b41d4a78 --- /dev/null +++ b/drivers/ub/cdma/cdma_db.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_DB_H__ +#define __CDMA_DB_H__ + +#include "cdma.h" + +struct cdma_context; + +struct cdma_sw_db_page { + struct list_head list; + struct cdma_umem *umem; + u64 user_virt; + refcount_t refcount; +}; + +struct cdma_k_sw_db_page { + struct list_head list; + u32 num_db; + unsigned long *bitmap; + struct cdma_buf db_buf; +}; + +struct cdma_sw_db { + union { + struct cdma_sw_db_page *page; + struct cdma_k_sw_db_page *kpage; + }; + u32 index; + u64 db_addr; + u32 *db_record; +}; + +void cdma_unpin_sw_db(struct cdma_context *ctx, struct cdma_sw_db *db); + +void cdma_free_sw_db(struct cdma_dev *dev, struct cdma_sw_db *db); + +#endif /* CDMA_DB_H */ diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index da730589ffd5..69eb70d47ae6 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -15,6 +15,7 @@ #include "cdma_context.h" #include #include +#include "cdma_jfc.h" #include "cdma_queue.h" #include "cdma_dev.h" @@ -108,6 +109,7 @@ static void cdma_init_tables(struct cdma_dev *cdev) static void cdma_destroy_tables(struct cdma_dev *cdev) { + cdma_tbl_destroy(cdev, &cdev->jfc_table, "JFC"); cdma_tbl_destroy(cdev, &cdev->queue_table, "QUEUE"); } @@ -175,8 +177,12 @@ static void cdma_uninit_dev_param(struct cdma_dev *cdev) static void cdma_release_table_res(struct cdma_dev *cdev) { struct cdma_queue *queue; + struct cdma_jfc *jfc; int id; + idr_for_each_entry(&cdev->jfc_table.idr_tbl.idr, jfc, id) + cdma_delete_jfc(cdev, jfc->jfcn, NULL); + idr_for_each_entry(&cdev->queue_table.idr_tbl.idr, queue, id) cdma_delete_queue(cdev, queue->id); } diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c index 89094aaebc1f..310d0fb6add4 100644 --- a/drivers/ub/cdma/cdma_ioctl.c +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -10,6 +10,7 @@ #include "cdma_context.h" #include "cdma_types.h" #include "cdma_queue.h" +#include "cdma_jfc.h" #include "cdma_uobj.h" #include "cdma_ioctl.h" @@ -213,6 +214,10 @@ static int cdma_cmd_delete_queue(struct cdma_ioctl_hdr *hdr, struct cdma_file *c } queue = (struct cdma_queue *)uobj->object; + if (queue->jfc) { + dev_err(cdev->dev, "jfc is still in use."); + return -EBUSY; + } cdma_uobj_delete(uobj); list_del(&queue->list); @@ -223,12 +228,69 @@ static int cdma_cmd_delete_queue(struct cdma_ioctl_hdr *hdr, struct cdma_file *c return ret; } +static int cdma_cmd_delete_jfc(struct cdma_ioctl_hdr *hdr, + struct cdma_file *cfile) +{ + struct cdma_cmd_delete_jfc_args arg = { 0 }; + struct cdma_dev *cdev = cfile->cdev; + struct cdma_base_jfc *base_jfc; + struct cdma_queue *queue; + struct cdma_uobj *uobj; + int ret; + + if (!hdr->args_addr || hdr->args_len != (u32)sizeof(arg)) + return -EINVAL; + + ret = (int)copy_from_user(&arg, (void *)hdr->args_addr, + (u32)sizeof(arg)); + if (ret) { + dev_err(cdev->dev, "get user data failed, ret = %d.\n", ret); + return -EFAULT; + } + + uobj = cdma_uobj_get(cfile, arg.in.queue_id, UOBJ_TYPE_QUEUE); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, + "delete jfc, get queue uobj failed, queue id = %u.\n", + arg.in.queue_id); + return -EINVAL; + } + queue = (struct cdma_queue *)uobj->object; + + uobj = cdma_uobj_get(cfile, arg.in.handle, UOBJ_TYPE_JFC); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, "get jfc uobj failed.\n"); + return -EINVAL; + } + + base_jfc = (struct cdma_base_jfc *)uobj->object; + ret = cdma_delete_jfc(cdev, base_jfc->id, &arg); + if (ret) { + dev_err(cdev->dev, "cdma delete jfc failed, ret = %d.\n", ret); + return -EFAULT; + } + + cdma_set_queue_res(cdev, queue, QUEUE_RES_JFC, NULL); + cdma_uobj_delete(uobj); + + ret = (int)copy_to_user((void *)hdr->args_addr, &arg, (u32)sizeof(arg)); + if (ret) { + dev_err(cdev->dev, + "delete jfc copy to user data failed, ret = %d.\n", + ret); + return -EFAULT; + } + + return 0; +} + static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { [CDMA_CMD_QUERY_DEV_INFO] = cdma_query_dev, [CDMA_CMD_CREATE_CTX] = cdma_create_ucontext, [CDMA_CMD_DELETE_CTX] = cdma_delete_ucontext, [CDMA_CMD_CREATE_QUEUE] = cdma_cmd_create_queue, [CDMA_CMD_DELETE_QUEUE] = cdma_cmd_delete_queue, + [CDMA_CMD_DELETE_JFC] = cdma_cmd_delete_jfc, }; int cdma_cmd_parse(struct cdma_file *cfile, struct cdma_ioctl_hdr *hdr) diff --git a/drivers/ub/cdma/cdma_jfc.c b/drivers/ub/cdma/cdma_jfc.c new file mode 100644 index 000000000000..83f55462f297 --- /dev/null +++ b/drivers/ub/cdma/cdma_jfc.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include +#include "cdma_cmd.h" +#include "cdma_mbox.h" +#include "cdma_common.h" +#include "cdma_db.h" +#include "cdma_jfc.h" + +static void cdma_jfc_id_free(struct cdma_dev *cdev, u32 jfcn) +{ + struct cdma_table *jfc_tbl = &cdev->jfc_table; + unsigned long flags; + + spin_lock_irqsave(&jfc_tbl->lock, flags); + idr_remove(&jfc_tbl->idr_tbl.idr, jfcn); + spin_unlock_irqrestore(&jfc_tbl->lock, flags); +} + +static struct cdma_jfc *cdma_id_find_jfc(struct cdma_dev *cdev, u32 jfcn) +{ + struct cdma_table *jfc_tbl = &cdev->jfc_table; + struct cdma_jfc *jfc; + unsigned long flags; + + spin_lock_irqsave(&jfc_tbl->lock, flags); + jfc = idr_find(&jfc_tbl->idr_tbl.idr, jfcn); + if (!jfc) + dev_err(cdev->dev, "find jfc failed, id = %u.\n", jfcn); + spin_unlock_irqrestore(&jfc_tbl->lock, flags); + + return jfc; +} + +static void cdma_free_jfc_buf(struct cdma_dev *cdev, struct cdma_jfc *jfc) +{ + u32 size; + + if (!jfc->buf.kva) { + cdma_unpin_sw_db(jfc->base.ctx, &jfc->db); + cdma_unpin_queue_addr(jfc->buf.umem); + } else { + size = jfc->buf.entry_size * jfc->buf.entry_cnt; + cdma_k_free_buf(cdev, size, &jfc->buf); + cdma_free_sw_db(cdev, &jfc->db); + } +} + +static int cdma_query_jfc_destroy_done(struct cdma_dev *cdev, uint32_t jfcn) +{ + struct ubase_mbx_attr attr = { 0 }; + struct ubase_cmd_mailbox *mailbox; + struct cdma_jfc_ctx *jfc_ctx; + int ret; + + cdma_fill_mbx_attr(&attr, jfcn, CDMA_CMD_QUERY_JFC_CONTEXT, 0); + mailbox = cdma_mailbox_query_ctx(cdev, &attr); + if (!mailbox) + return -ENOMEM; + + jfc_ctx = mailbox->buf; + ret = jfc_ctx->pi == jfc_ctx->wr_cqe_idx ? 0 : -EAGAIN; + + cdma_free_cmd_mailbox(cdev, mailbox); + + return ret; +} + +static int cdma_destroy_and_flush_jfc(struct cdma_dev *cdev, u32 jfcn) +{ +#define QUERY_MAX_TIMES 5 + u32 wait_times = 0; + int ret; + + ret = cdma_post_destroy_jfc_mbox(cdev, jfcn, CDMA_JFC_STATE_INVALID); + if (ret) { + dev_err(cdev->dev, "post mbox to destroy jfc failed, id: %u.\n", jfcn); + return ret; + } + + while (true) { + if (!cdma_query_jfc_destroy_done(cdev, jfcn)) + return 0; + if (wait_times > QUERY_MAX_TIMES) + break; + msleep(1 << wait_times); + wait_times++; + } + dev_err(cdev->dev, "jfc flush time out, id = %u.\n", jfcn); + + return -ETIMEDOUT; +} + +int cdma_post_destroy_jfc_mbox(struct cdma_dev *cdev, u32 jfcn, + enum cdma_jfc_state state) +{ + struct ubase_mbx_attr attr = { 0 }; + struct cdma_jfc_ctx ctx = { 0 }; + + ctx.state = state; + cdma_fill_mbx_attr(&attr, jfcn, CDMA_CMD_DESTROY_JFC_CONTEXT, 0); + + return cdma_post_mailbox_ctx(cdev, (void *)&ctx, sizeof(ctx), &attr); +} + +int cdma_delete_jfc(struct cdma_dev *cdev, u32 jfcn, + struct cdma_cmd_delete_jfc_args *arg) +{ + struct cdma_jfc *jfc; + int ret; + + if (!cdev) + return -EINVAL; + + if (jfcn >= cdev->caps.jfc.max_cnt + cdev->caps.jfc.start_idx || + jfcn < cdev->caps.jfc.start_idx) { + dev_err(cdev->dev, + "jfc id invalid, jfcn = %u, start_idx = %u, max_cnt = %u.\n", + jfcn, cdev->caps.jfc.start_idx, + cdev->caps.jfc.max_cnt); + return -EINVAL; + } + + jfc = cdma_id_find_jfc(cdev, jfcn); + if (!jfc) { + dev_err(cdev->dev, "find jfc failed, jfcn = %u.\n", jfcn); + return -EINVAL; + } + + ret = cdma_destroy_and_flush_jfc(cdev, jfc->jfcn); + if (ret) + dev_err(cdev->dev, "jfc delete failed, jfcn = %u.\n", jfcn); + + cdma_free_jfc_buf(cdev, jfc); + cdma_jfc_id_free(cdev, jfc->jfcn); + + pr_debug("Leave %s, jfcn: %u.\n", __func__, jfc->jfcn); + + kfree(jfc); + + return 0; +} diff --git a/drivers/ub/cdma/cdma_jfc.h b/drivers/ub/cdma/cdma_jfc.h new file mode 100644 index 000000000000..28144b317774 --- /dev/null +++ b/drivers/ub/cdma/cdma_jfc.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_JFC_H__ +#define __CDMA_JFC_H__ + +#include "cdma_types.h" +#include "cdma_db.h" + +enum cdma_jfc_state { + CDMA_JFC_STATE_INVALID, + CDMA_JFC_STATE_VALID, + CDMA_JFC_STATE_ERROR +}; + +struct cdma_jfc { + struct cdma_base_jfc base; + u32 jfcn; + u32 ceqn; + u32 tid; + struct cdma_buf buf; + struct cdma_sw_db db; + u32 ci; + u32 arm_sn; + spinlock_t lock; + u32 mode; +}; + +struct cdma_jfc_ctx { + /* DW0 */ + u32 state : 2; + u32 arm_st : 2; + u32 shift : 4; + u32 cqe_size : 1; + u32 record_db_en : 1; + u32 jfc_type : 1; + u32 inline_en : 1; + u32 cqe_va_l : 20; + /* DW1 */ + u32 cqe_va_h; + /* DW2 */ + u32 cqe_token_id : 20; + u32 cq_cnt_mode : 1; + u32 rsv0 : 3; + u32 ceqn : 8; + /* DW3 */ + u32 cqe_token_value : 24; + u32 rsv1 : 8; + /* DW4 */ + u32 pi : 22; + u32 cqe_coalesce_cnt : 10; + /* DW5 */ + u32 ci : 22; + u32 cqe_coalesce_period : 3; + u32 rsv2 : 7; + /* DW6 */ + u32 record_db_addr_l; + /* DW7 */ + u32 record_db_addr_h : 26; + u32 rsv3 : 6; + /* DW8 */ + u32 push_usi_en : 1; + u32 push_cqe_en : 1; + u32 token_en : 1; + u32 rsv4 : 9; + u32 tpn : 20; + /* DW9 ~ DW12 */ + u32 rmt_eid[4]; + /* DW13 */ + u32 seid_idx : 10; + u32 rmt_token_id : 20; + u32 rsv5 : 2; + /* DW14 */ + u32 remote_token_value; + /* DW15 */ + u32 int_vector : 16; + u32 stars_en : 1; + u32 rsv6 : 15; + /* DW16 */ + u32 poll : 1; + u32 cqe_report_timer : 24; + u32 se : 1; + u32 arm_sn : 2; + u32 rsv7 : 4; + /* DW17 */ + u32 se_cqe_idx : 24; + u32 rsv8 : 8; + /* DW18 */ + u32 wr_cqe_idx : 22; + u32 rsv9 : 10; + /* DW19 */ + u32 cqe_cnt : 24; + u32 rsv10 : 8; + /* DW20 ~ DW31 */ + u32 rsv11[12]; +}; + +int cdma_post_destroy_jfc_mbox(struct cdma_dev *cdev, u32 jfcn, + enum cdma_jfc_state state); + +int cdma_delete_jfc(struct cdma_dev *cdev, u32 jfcn, + struct cdma_cmd_delete_jfc_args *arg); + +#endif /* CDMA_JFC_H */ diff --git a/drivers/ub/cdma/cdma_mbox.c b/drivers/ub/cdma/cdma_mbox.c new file mode 100644 index 000000000000..194eba8a920d --- /dev/null +++ b/drivers/ub/cdma/cdma_mbox.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include "cdma_mbox.h" + +static int cdma_post_mailbox(struct cdma_dev *cdev, struct ubase_mbx_attr *attr, + struct ubase_cmd_mailbox *mailbox) +{ + int ret; + + ret = ubase_hw_upgrade_ctx_ex(cdev->adev, attr, mailbox); + if (ret) + dev_err(cdev->dev, + "send mailbox err, tag = 0x%x, op = %u, mbx_ue_id = %u.\n", + attr->tag, attr->op, attr->mbx_ue_id); + + return ret; +} + +int cdma_post_mailbox_ctx(struct cdma_dev *cdev, void *ctx, u32 size, + struct ubase_mbx_attr *attr) +{ + struct ubase_cmd_mailbox *mailbox; + int ret; + + mailbox = cdma_alloc_cmd_mailbox(cdev); + if (!mailbox) { + dev_err(cdev->dev, "alloc mailbox failed, opcode = %u.\n", + attr->op); + return -ENOMEM; + } + + if (ctx && size) + memcpy(mailbox->buf, ctx, size); + + ret = cdma_post_mailbox(cdev, attr, mailbox); + + cdma_free_cmd_mailbox(cdev, mailbox); + + return ret; +} + +struct ubase_cmd_mailbox *cdma_mailbox_query_ctx(struct cdma_dev *cdev, + struct ubase_mbx_attr *attr) +{ + struct ubase_cmd_mailbox *mailbox; + int ret; + + mailbox = cdma_alloc_cmd_mailbox(cdev); + if (!mailbox) { + dev_err(cdev->dev, "alloc mailbox failed, opcode = %u.\n", + attr->op); + return NULL; + } + + ret = cdma_post_mailbox(cdev, attr, mailbox); + if (ret) { + cdma_free_cmd_mailbox(cdev, mailbox); + return NULL; + } + + return mailbox; +} diff --git a/drivers/ub/cdma/cdma_mbox.h b/drivers/ub/cdma/cdma_mbox.h new file mode 100644 index 000000000000..0841ea606bbd --- /dev/null +++ b/drivers/ub/cdma/cdma_mbox.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_MBOX_H__ +#define __CDMA_MBOX_H__ + +#include "cdma.h" +#include + +enum { + /* JFC CMDS */ + CDMA_CMD_WRITE_JFC_CONTEXT_VA = 0x20, + CDMA_CMD_READ_JFC_CONTEXT_VA = 0x21, + CDMA_CMD_DESTROY_JFC_CONTEXT_VA = 0x22, + CDMA_CMD_CREATE_JFC_CONTEXT = 0x24, + CDMA_CMD_MODIFY_JFC_CONTEXT = 0x25, + CDMA_CMD_QUERY_JFC_CONTEXT = 0x26, + CDMA_CMD_DESTROY_JFC_CONTEXT = 0x27, +}; + +/* The mailbox operation is as follows: */ +static inline void cdma_fill_mbx_attr(struct ubase_mbx_attr *attr, u32 tag, + u8 op, u8 mbx_ue_id) +{ + ubase_fill_mbx_attr(attr, tag, op, mbx_ue_id); +} + +static inline struct ubase_cmd_mailbox *cdma_alloc_cmd_mailbox(struct cdma_dev *cdev) +{ + return ubase_alloc_cmd_mailbox(cdev->adev); +} + +static inline void cdma_free_cmd_mailbox(struct cdma_dev *cdev, + struct ubase_cmd_mailbox *mailbox) +{ + ubase_free_cmd_mailbox(cdev->adev, mailbox); +} + +int cdma_post_mailbox_ctx(struct cdma_dev *cdev, void *ctx, u32 size, + struct ubase_mbx_attr *attr); +struct ubase_cmd_mailbox *cdma_mailbox_query_ctx(struct cdma_dev *cdev, + struct ubase_mbx_attr *attr); + +#endif /* CDMA_MBOX_H */ diff --git a/drivers/ub/cdma/cdma_queue.c b/drivers/ub/cdma/cdma_queue.c index 93ffcab5ecc6..a25de76cdb4e 100644 --- a/drivers/ub/cdma/cdma_queue.c +++ b/drivers/ub/cdma/cdma_queue.c @@ -3,7 +3,9 @@ #define dev_fmt(fmt) "CDMA: " fmt +#include "cdma_common.h" #include "cdma_context.h" +#include "cdma_jfc.h" #include "cdma_queue.h" #include "cdma.h" @@ -19,6 +21,13 @@ struct cdma_queue *cdma_find_queue(struct cdma_dev *cdev, u32 queue_id) return queue; } +static void cdma_delete_queue_res(struct cdma_dev *cdev, + struct cdma_queue *queue) +{ + cdma_delete_jfc(cdev, queue->jfc->id, NULL); + queue->jfc = NULL; +} + static int cdma_alloc_queue_id(struct cdma_dev *cdev, struct cdma_queue *queue) { struct cdma_table *queue_tbl = &cdev->queue_table; @@ -97,7 +106,29 @@ int cdma_delete_queue(struct cdma_dev *cdev, u32 queue_id) cdma_delete_queue_id(cdev, queue_id); + if (queue->is_kernel) + cdma_delete_queue_res(cdev, queue); kfree(queue); return 0; } + +void cdma_set_queue_res(struct cdma_dev *cdev, struct cdma_queue *queue, + enum cdma_queue_res_type type, void *res) +{ + dev_dbg(cdev->dev, + "set queue %u resource type = %u, null flag = %u.\n", + queue->id, type, res == NULL); + + spin_lock(&cdev->queue_table.lock); + switch (type) { + case QUEUE_RES_JFC: + queue->jfc = res; + if (queue->jfc) + queue->jfc_id = queue->jfc->id; + break; + default: + break; + } + spin_unlock(&cdev->queue_table.lock); +} diff --git a/drivers/ub/cdma/cdma_queue.h b/drivers/ub/cdma/cdma_queue.h index 0299a026a14b..3808c23a1934 100644 --- a/drivers/ub/cdma/cdma_queue.h +++ b/drivers/ub/cdma/cdma_queue.h @@ -8,12 +8,18 @@ struct cdma_dev; struct cdma_context; struct queue_cfg; +enum cdma_queue_res_type { + QUEUE_RES_JFC +}; + struct cdma_queue { + struct cdma_base_jfc *jfc; struct cdma_context *ctx; u32 id; struct queue_cfg cfg; bool is_kernel; struct list_head list; + u32 jfc_id; }; struct cdma_queue *cdma_find_queue(struct cdma_dev *cdev, u32 queue_id); @@ -22,5 +28,6 @@ struct cdma_queue *cdma_create_queue(struct cdma_dev *cdev, struct queue_cfg *cfg, u32 eid_index, bool is_kernel); int cdma_delete_queue(struct cdma_dev *cdev, u32 queue_id); - +void cdma_set_queue_res(struct cdma_dev *cdev, struct cdma_queue *queue, + enum cdma_queue_res_type type, void *res); #endif diff --git a/drivers/ub/cdma/cdma_types.h b/drivers/ub/cdma/cdma_types.h index 9f3af5c06bbe..f8f97a9f9f6d 100644 --- a/drivers/ub/cdma/cdma_types.h +++ b/drivers/ub/cdma/cdma_types.h @@ -10,6 +10,21 @@ struct cdma_dev; +struct cdma_jfc_cfg { + u32 depth; + u32 ceqn; + u32 queue_id; +}; + +struct cdma_base_jfc { + struct cdma_dev *dev; + struct cdma_context *ctx; + struct cdma_jfc_cfg jfc_cfg; + u32 id; + struct hlist_node hnode; + atomic_t use_cnt; +}; + struct cdma_file { struct cdma_dev *cdev; struct list_head list; diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h index 50bca1fab02b..da4aefa119d8 100644 --- a/include/uapi/ub/cdma/cdma_abi.h +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -10,12 +10,21 @@ #define CDMA_IOC_MAGIC 'C' #define CDMA_SYNC _IOWR(CDMA_IOC_MAGIC, 0, struct cdma_ioctl_hdr) +#define MAP_COMMAND_MASK 0xff + +enum db_mmap_type { + CDMA_MMAP_JFC_PAGE, + CDMA_MMAP_JETTY_DSQE +}; + enum cdma_cmd { CDMA_CMD_QUERY_DEV_INFO, CDMA_CMD_CREATE_CTX, CDMA_CMD_DELETE_CTX, CDMA_CMD_CREATE_QUEUE, CDMA_CMD_DELETE_QUEUE, + CDMA_CMD_CREATE_JFC, + CDMA_CMD_DELETE_JFC, CDMA_CMD_MAX }; @@ -25,6 +34,37 @@ struct cdma_ioctl_hdr { __u64 args_addr; }; +struct cdma_cmd_udrv_priv { + __u64 in_addr; + __u32 in_len; + __u64 out_addr; + __u32 out_len; +}; + +struct cdma_cmd_create_jfc_args { + struct { + __u32 depth; /* in terms of CQEBB */ + int jfce_fd; + int jfce_id; + __u32 ceqn; + __u32 queue_id; + } in; + struct { + __u32 id; + __u32 depth; + __u64 handle; /* handle of the allocated jfc obj in kernel */ + } out; + struct cdma_cmd_udrv_priv udata; +}; + +struct cdma_cmd_delete_jfc_args { + struct { + __u32 jfcn; + __u64 handle; /* handle of jfc */ + __u32 queue_id; + } in; +}; + struct dev_eid { __u32 dw0; __u32 dw1; @@ -77,6 +117,24 @@ struct cdma_create_context_args { } out; }; +struct cdma_jfc_db { + __u32 ci : 24; + __u32 notify : 1; + __u32 arm_sn : 2; + __u32 type : 1; + __u32 rsv1 : 4; + __u32 jfcn : 20; + __u32 rsv2 : 12; +}; + +struct cdma_create_jfc_ucmd { + __u64 buf_addr; + __u32 buf_len; + __u64 db_addr; + __u32 mode; + __u32 tid; +}; + struct cdma_cmd_create_queue_args { struct { __u32 queue_depth; -- Gitee From dea3b64bfab29aa296ec378acf33b08f014618e2 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 09:54:00 +0800 Subject: [PATCH 013/103] ub: cdma: support the creation of jfc commit 681171cd155e62f4a64ef5e8612819a049d88478 openEuler This patch implements the creation functionality of jfc in the CDMA driver. The implementation involves creating the jfc corresponding to the queue during the queue creation process. Signed-off-by: Zhipeng Lu Signed-off-by: Bangwei Zhang Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma.h | 10 ++ drivers/ub/cdma/cdma_chardev.c | 58 ++++++++ drivers/ub/cdma/cdma_common.c | 236 ++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_common.h | 26 +++- drivers/ub/cdma/cdma_db.c | 123 +++++++++++++++++ drivers/ub/cdma/cdma_db.h | 7 +- drivers/ub/cdma/cdma_dev.c | 3 + drivers/ub/cdma/cdma_dev.h | 2 - drivers/ub/cdma/cdma_ioctl.c | 73 ++++++++++ drivers/ub/cdma/cdma_jfc.c | 239 +++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_jfc.h | 39 ++++++ drivers/ub/cdma/cdma_main.c | 4 + drivers/ub/cdma/cdma_mbox.h | 4 - drivers/ub/cdma/cdma_queue.c | 40 +++++- drivers/ub/cdma/cdma_types.h | 12 ++ 15 files changed, 863 insertions(+), 13 deletions(-) diff --git a/drivers/ub/cdma/cdma.h b/drivers/ub/cdma/cdma.h index d43fc7be17d1..b379a3f43884 100644 --- a/drivers/ub/cdma/cdma.h +++ b/drivers/ub/cdma/cdma.h @@ -12,12 +12,22 @@ #include extern u32 jfc_arm_mode; +extern bool cqe_mode; +#define CDMA_HW_PAGE_SHIFT 12 +#define CDMA_HW_PAGE_SIZE (1 << CDMA_HW_PAGE_SHIFT) + +#define CDMA_DEFAULT_CQE_SIZE 128 #define CDMA_RESET_WAIT_TIME 3000 #define CDMA_MAX_SL_NUM 16 #define CDMA_UPI_MASK 0x7FFF +enum cdma_cqe_size { + CDMA_64_CQE_SIZE, + CDMA_128_CQE_SIZE, +}; + enum cdma_status { CDMA_NORMAL, CDMA_SUSPEND, diff --git a/drivers/ub/cdma/cdma_chardev.c b/drivers/ub/cdma/cdma_chardev.c index 9cd785cc6d41..b3a8b75b019e 100644 --- a/drivers/ub/cdma/cdma_chardev.c +++ b/drivers/ub/cdma/cdma_chardev.c @@ -32,6 +32,11 @@ static void cdma_num_free(struct cdma_dev *cdev) spin_unlock(&cdma_num_mg.lock); } +static inline int cdma_get_mmap_cmd(struct vm_area_struct *vma) +{ + return (vma->vm_pgoff & MAP_COMMAND_MASK); +} + static int cdma_num_alloc(struct cdma_dev *cdev) { #define CDMA_START 0 @@ -69,6 +74,58 @@ static long cdma_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return -ENOIOCTLCMD; } +static int cdma_remap_pfn_range(struct cdma_file *cfile, struct vm_area_struct *vma) +{ +#define JFC_DB_UNMAP_BOUND 1 + struct cdma_dev *cdev = cfile->cdev; + resource_size_t db_addr; + u32 cmd; + + db_addr = cdev->db_base; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + cmd = cdma_get_mmap_cmd(vma); + switch (cmd) { + case CDMA_MMAP_JFC_PAGE: + if (io_remap_pfn_range(vma, vma->vm_start, + jfc_arm_mode > JFC_DB_UNMAP_BOUND ? + (uint64_t)db_addr >> PAGE_SHIFT : + page_to_pfn(cdev->arm_db_page), + PAGE_SIZE, vma->vm_page_prot)) { + dev_err(cdev->dev, "remap jfc page fail.\n"); + return -EAGAIN; + } + break; + default: + dev_err(cdev->dev, + "mmap failed, cmd(%u) is not supported.\n", cmd); + return -EINVAL; + } + + return 0; +} + +static int cdma_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct cdma_file *cfile = (struct cdma_file *)file->private_data; + int ret; + + if (((vma->vm_end - vma->vm_start) % PAGE_SIZE) != 0) { + pr_err("mmap failed, expect vm area size to be an integer multiple of page size.\n"); + return -EINVAL; + } + + mutex_lock(&cfile->ctx_mutex); + ret = cdma_remap_pfn_range(cfile, vma); + if (ret) { + mutex_unlock(&cfile->ctx_mutex); + return ret; + } + mutex_unlock(&cfile->ctx_mutex); + + return 0; +} + static int cdma_open(struct inode *inode, struct file *file) { struct cdma_chardev *chardev; @@ -121,6 +178,7 @@ static int cdma_close(struct inode *inode, struct file *file) static const struct file_operations cdma_ops = { .owner = THIS_MODULE, .unlocked_ioctl = cdma_ioctl, + .mmap = cdma_mmap, .open = cdma_open, .release = cdma_close, }; diff --git a/drivers/ub/cdma/cdma_common.c b/drivers/ub/cdma/cdma_common.c index 291231eab627..62ae5f8be48c 100644 --- a/drivers/ub/cdma/cdma_common.c +++ b/drivers/ub/cdma/cdma_common.c @@ -9,6 +9,97 @@ #include "cdma_common.h" #include "cdma.h" +static inline void cdma_fill_umem(struct cdma_umem *umem, + struct cdma_umem_param *param) +{ + umem->dev = param->dev; + umem->va = param->va; + umem->length = param->len; + umem->flag = param->flag; +} + +static int cdma_pin_part_of_pages(u64 cur_base, u64 npages, u32 gup_flags, + struct page **page_list) +{ + /* + * page_list size is 4kB, the nr_pages should not larger than + * PAGE_SIZE / sizeof(struct page *) + */ + return pin_user_pages_fast(cur_base, + min_t(unsigned long, (unsigned long)npages, + PAGE_SIZE / sizeof(struct page *)), + gup_flags | FOLL_LONGTERM, page_list); +} + +static struct scatterlist *cdma_sg_set_page(struct scatterlist *sg_start, + int pinned, struct page **page_list) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sg_start, sg, pinned, i) + sg_set_page(sg, page_list[i], PAGE_SIZE, 0); + + return sg; +} + +static u64 cdma_pin_pages(struct cdma_dev *cdev, struct cdma_umem *umem, + u64 npages, u32 gup_flags, struct page **pages) +{ + struct scatterlist *sg_list_start = umem->sg_head.sgl; + u64 cur_base = umem->va & PAGE_MASK; + u64 page_count = npages; + int pinned; + + while (page_count > 0) { + cond_resched(); + + pinned = cdma_pin_part_of_pages(cur_base, page_count, gup_flags, + pages); + if (pinned <= 0) { + dev_err(cdev->dev, + "pin pages failed, page_count = 0x%llx, pinned = %d.\n", + page_count, pinned); + return npages - page_count; + } + cur_base += (u64)pinned * PAGE_SIZE; + page_count -= (u64)pinned; + sg_list_start = cdma_sg_set_page(sg_list_start, pinned, pages); + } + + return npages; +} + +static u64 cdma_k_pin_pages(struct cdma_dev *cdev, struct cdma_umem *umem, + u64 npages) +{ + struct scatterlist *sg_cur = umem->sg_head.sgl; + u64 cur_base = umem->va & PAGE_MASK; + struct page *pg; + u64 n; + + for (n = 0; n < npages; n++) { + if (is_vmalloc_addr((void *)(uintptr_t)cur_base)) + pg = vmalloc_to_page((void *)(uintptr_t)cur_base); + else + pg = kmap_to_page((void *)(uintptr_t)cur_base); + + if (!pg) { + dev_err(cdev->dev, "vmalloc or kmap to page failed.\n"); + break; + } + + get_page(pg); + + cur_base += PAGE_SIZE; + + sg_set_page(sg_cur, pg, PAGE_SIZE, 0); + sg_cur = sg_next(sg_cur); + } + + return n; +} + static void cdma_unpin_pages(struct cdma_umem *umem, u64 nents, bool is_kernel) { struct scatterlist *sg; @@ -25,6 +116,99 @@ static void cdma_unpin_pages(struct cdma_umem *umem, u64 nents, bool is_kernel) } } +static struct cdma_umem *cdma_get_target_umem(struct cdma_umem_param *param, + struct page **page_list) +{ + struct cdma_dev *cdev = param->dev; + struct cdma_umem *umem; + u64 npages, pinned; + u32 gup_flags; + int ret = 0; + + umem = kzalloc(sizeof(*umem), GFP_KERNEL); + if (!umem) { + ret = -ENOMEM; + goto out; + } + + cdma_fill_umem(umem, param); + + npages = cdma_cal_npages(umem->va, umem->length); + if (!npages || npages > UINT_MAX) { + dev_err(cdev->dev, + "invalid npages %llu in getting target umem process.\n", npages); + ret = -EINVAL; + goto umem_kfree; + } + + ret = sg_alloc_table(&umem->sg_head, (unsigned int)npages, GFP_KERNEL); + if (ret) + goto umem_kfree; + + if (param->is_kernel) { + pinned = cdma_k_pin_pages(cdev, umem, npages); + } else { + gup_flags = param->flag.bs.writable ? FOLL_WRITE : 0; + pinned = cdma_pin_pages(cdev, umem, npages, gup_flags, + page_list); + } + + if (pinned != npages) { + ret = -ENOMEM; + goto umem_release; + } + + goto out; + +umem_release: + cdma_unpin_pages(umem, pinned, param->is_kernel); + sg_free_table(&umem->sg_head); +umem_kfree: + kfree(umem); +out: + return ret != 0 ? ERR_PTR(ret) : umem; +} + +static int cdma_verify_input(struct cdma_dev *cdev, u64 va, u64 len) +{ + if (((va + len) <= va) || PAGE_ALIGN(va + len) < (va + len)) { + dev_err(cdev->dev, "invalid address parameter, len = %llu.\n", + len); + return -EINVAL; + } + return 0; +} + +struct cdma_umem *cdma_umem_get(struct cdma_dev *cdev, u64 va, u64 len, + bool is_kernel) +{ + struct cdma_umem_param param; + struct page **page_list; + struct cdma_umem *umem; + int ret; + + ret = cdma_verify_input(cdev, va, len); + if (ret) + return ERR_PTR(ret); + + page_list = (struct page **)__get_free_page(GFP_KERNEL); + if (!page_list) + return ERR_PTR(-ENOMEM); + + param.dev = cdev; + param.va = va; + param.len = len; + param.flag.bs.writable = true; + param.flag.bs.non_pin = 0; + param.is_kernel = is_kernel; + umem = cdma_get_target_umem(¶m, page_list); + if (IS_ERR(umem)) + dev_err(cdev->dev, "get target umem failed.\n"); + + free_page((unsigned long)(uintptr_t)page_list); + return umem; +} + void cdma_umem_release(struct cdma_umem *umem, bool is_kernel) { if (IS_ERR_OR_NULL(umem)) @@ -35,6 +219,38 @@ void cdma_umem_release(struct cdma_umem *umem, bool is_kernel) kfree(umem); } +int cdma_k_alloc_buf(struct cdma_dev *cdev, size_t memory_size, + struct cdma_buf *buf) +{ + size_t aligned_memory_size; + int ret; + + aligned_memory_size = memory_size + CDMA_HW_PAGE_SIZE - 1; + buf->aligned_va = vmalloc(aligned_memory_size); + if (!buf->aligned_va) { + dev_err(cdev->dev, + "vmalloc kernel buf failed, size = %lu.\n", + aligned_memory_size); + return -ENOMEM; + } + + memset(buf->aligned_va, 0, aligned_memory_size); + buf->umem = cdma_umem_get(cdev, (u64)buf->aligned_va, + aligned_memory_size, true); + if (IS_ERR(buf->umem)) { + ret = PTR_ERR(buf->umem); + vfree(buf->aligned_va); + dev_err(cdev->dev, "pin kernel buf failed, ret = %d.\n", ret); + return ret; + } + + buf->addr = ((u64)buf->aligned_va + CDMA_HW_PAGE_SIZE - 1) & + ~(CDMA_HW_PAGE_SIZE - 1); + buf->kva = (void *)buf->addr; + + return 0; +} + void cdma_k_free_buf(struct cdma_dev *cdev, size_t memory_size, struct cdma_buf *buf) { @@ -45,6 +261,26 @@ void cdma_k_free_buf(struct cdma_dev *cdev, size_t memory_size, buf->addr = 0; } +int cdma_pin_queue_addr(struct cdma_dev *cdev, u64 addr, u32 len, + struct cdma_buf *buf) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(buf)) + return -EINVAL; + + buf->umem = cdma_umem_get(cdev, addr, len, false); + if (IS_ERR(buf->umem)) { + dev_err(cdev->dev, "get umem failed.\n"); + ret = PTR_ERR(buf->umem); + return ret; + } + + buf->addr = addr; + + return ret; +} + void cdma_unpin_queue_addr(struct cdma_umem *umem) { cdma_umem_release(umem, false); diff --git a/drivers/ub/cdma/cdma_common.h b/drivers/ub/cdma/cdma_common.h index 644868418bf5..57e241c3b946 100644 --- a/drivers/ub/cdma/cdma_common.h +++ b/drivers/ub/cdma/cdma_common.h @@ -5,16 +5,34 @@ #define __CDMA_COMMON_H__ #include +#include "cdma.h" -struct cdma_umem; -struct cdma_dev; -struct cdma_buf; +#define CDMA_DB_SIZE 64 +struct cdma_umem_param { + struct cdma_dev *dev; + u64 va; + u64 len; + union cdma_umem_flag flag; + bool is_kernel; +}; + +static inline u64 cdma_cal_npages(u64 va, u64 len) +{ + return (ALIGN(va + len, PAGE_SIZE) - ALIGN_DOWN(va, PAGE_SIZE)) / + PAGE_SIZE; +} + +struct cdma_umem *cdma_umem_get(struct cdma_dev *cdev, u64 va, u64 len, + bool is_kernel); void cdma_umem_release(struct cdma_umem *umem, bool is_kernel); +int cdma_k_alloc_buf(struct cdma_dev *cdev, size_t memory_size, + struct cdma_buf *buf); void cdma_k_free_buf(struct cdma_dev *cdev, size_t memory_size, struct cdma_buf *buf); - +int cdma_pin_queue_addr(struct cdma_dev *cdev, u64 addr, u32 len, + struct cdma_buf *buf); void cdma_unpin_queue_addr(struct cdma_umem *umem); #endif diff --git a/drivers/ub/cdma/cdma_db.c b/drivers/ub/cdma/cdma_db.c index e1c39e612bf4..d241144a6845 100644 --- a/drivers/ub/cdma/cdma_db.c +++ b/drivers/ub/cdma/cdma_db.c @@ -8,6 +8,57 @@ #include "cdma_context.h" #include "cdma_db.h" +static int cdma_alloc_db_from_page(struct cdma_k_sw_db_page *page, + struct cdma_sw_db *db) +{ + u32 index; + + index = find_first_bit(page->bitmap, page->num_db); + if (index == page->num_db) + return -ENOMEM; + + clear_bit(index, page->bitmap); + + db->index = index; + db->kpage = page; + db->db_addr = page->db_buf.addr + db->index * CDMA_DB_SIZE; + db->db_record = (u32 *)(page->db_buf.kva + db->index * CDMA_DB_SIZE); + + return 0; +} + +static struct cdma_k_sw_db_page *cdma_alloc_db_page(struct cdma_dev *dev) +{ + struct cdma_k_sw_db_page *page; + int ret; + + page = kzalloc(sizeof(*page), GFP_KERNEL); + if (!page) + return NULL; + + page->num_db = PAGE_SIZE / CDMA_DB_SIZE; + + page->bitmap = bitmap_alloc(page->num_db, GFP_KERNEL); + if (!page->bitmap) { + dev_err(dev->dev, "alloc db bitmap failed.\n"); + goto err_bitmap; + } + + bitmap_fill(page->bitmap, page->num_db); + + ret = cdma_k_alloc_buf(dev, PAGE_SIZE, &page->db_buf); + if (ret) + goto err_kva; + + return page; +err_kva: + bitmap_free(page->bitmap); +err_bitmap: + kfree(page); + + return NULL; +} + static void cdma_free_db_page(struct cdma_dev *cdev, struct cdma_sw_db *db) { cdma_k_free_buf(cdev, PAGE_SIZE, &db->kpage->db_buf); @@ -16,6 +67,49 @@ static void cdma_free_db_page(struct cdma_dev *cdev, struct cdma_sw_db *db) db->kpage = NULL; } +int cdma_pin_sw_db(struct cdma_context *ctx, struct cdma_sw_db *db) +{ + u64 page_addr = db->db_addr & PAGE_MASK; + struct cdma_sw_db_page *page; + int ret = 0; + + mutex_lock(&ctx->pgdir_mutex); + + list_for_each_entry(page, &ctx->pgdir_list, list) { + if (page->user_virt == page_addr) + goto found; + } + + page = kzalloc(sizeof(*page), GFP_KERNEL); + if (!page) { + ret = -ENOMEM; + goto out; + } + + refcount_set(&page->refcount, 1); + page->user_virt = page_addr; + page->umem = cdma_umem_get(ctx->cdev, page_addr, PAGE_SIZE, false); + if (IS_ERR(page->umem)) { + ret = PTR_ERR(page->umem); + dev_err(ctx->cdev->dev, "get umem failed, ret = %d.\n", ret); + kfree(page); + goto out; + } + + list_add(&page->list, &ctx->pgdir_list); + db->page = page; + mutex_unlock(&ctx->pgdir_mutex); + return 0; + +found: + db->page = page; + refcount_inc(&page->refcount); +out: + mutex_unlock(&ctx->pgdir_mutex); + + return ret; +} + void cdma_unpin_sw_db(struct cdma_context *ctx, struct cdma_sw_db *db) { mutex_lock(&ctx->pgdir_mutex); @@ -30,6 +124,35 @@ void cdma_unpin_sw_db(struct cdma_context *ctx, struct cdma_sw_db *db) mutex_unlock(&ctx->pgdir_mutex); } +int cdma_alloc_sw_db(struct cdma_dev *cdev, struct cdma_sw_db *db) +{ + struct cdma_k_sw_db_page *page; + int ret = 0; + + mutex_lock(&cdev->db_mutex); + + list_for_each_entry(page, &cdev->db_page, list) + if (!cdma_alloc_db_from_page(page, db)) + goto out; + + page = cdma_alloc_db_page(cdev); + if (!page) { + ret = -ENOMEM; + dev_err(cdev->dev, "alloc sw db page failed.\n"); + goto out; + } + + list_add(&page->list, &cdev->db_page); + + ret = cdma_alloc_db_from_page(page, db); + if (ret) + dev_err(cdev->dev, "alloc sw db from page failed, ret = %d.\n", ret); +out: + mutex_unlock(&cdev->db_mutex); + + return ret; +} + void cdma_free_sw_db(struct cdma_dev *cdev, struct cdma_sw_db *db) { mutex_lock(&cdev->db_mutex); diff --git a/drivers/ub/cdma/cdma_db.h b/drivers/ub/cdma/cdma_db.h index 5337b41d4a78..fa3ef8c0f570 100644 --- a/drivers/ub/cdma/cdma_db.h +++ b/drivers/ub/cdma/cdma_db.h @@ -4,9 +4,8 @@ #ifndef __CDMA_DB_H__ #define __CDMA_DB_H__ -#include "cdma.h" - struct cdma_context; +struct cdma_dev; struct cdma_sw_db_page { struct list_head list; @@ -32,8 +31,12 @@ struct cdma_sw_db { u32 *db_record; }; +int cdma_pin_sw_db(struct cdma_context *ctx, struct cdma_sw_db *db); + void cdma_unpin_sw_db(struct cdma_context *ctx, struct cdma_sw_db *db); +int cdma_alloc_sw_db(struct cdma_dev *dev, struct cdma_sw_db *db); + void cdma_free_sw_db(struct cdma_dev *dev, struct cdma_sw_db *db); #endif /* CDMA_DB_H */ diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index 69eb70d47ae6..bbf44a75fffc 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -102,9 +102,12 @@ static void cdma_tbl_destroy(struct cdma_dev *cdev, struct cdma_table *table, static void cdma_init_tables(struct cdma_dev *cdev) { struct cdma_res *queue = &cdev->caps.queue; + struct cdma_res *jfc = &cdev->caps.jfc; cdma_tbl_init(&cdev->queue_table, queue->start_idx + queue->max_cnt - 1, queue->start_idx); + cdma_tbl_init(&cdev->jfc_table, jfc->start_idx + jfc->max_cnt - 1, + jfc->start_idx); } static void cdma_destroy_tables(struct cdma_dev *cdev) diff --git a/drivers/ub/cdma/cdma_dev.h b/drivers/ub/cdma/cdma_dev.h index 75aa96b092c7..85d41cbe0773 100644 --- a/drivers/ub/cdma/cdma_dev.h +++ b/drivers/ub/cdma/cdma_dev.h @@ -11,8 +11,6 @@ #define CDMA_UE_MAX_NUM 64 struct cdma_dev; -struct eu_info; -struct dev_eid; struct cdma_ctrlq_eu_info { struct eu_info eu; diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c index 310d0fb6add4..c95230dcc443 100644 --- a/drivers/ub/cdma/cdma_ioctl.c +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -228,6 +228,78 @@ static int cdma_cmd_delete_queue(struct cdma_ioctl_hdr *hdr, struct cdma_file *c return ret; } +static int cdma_cmd_create_jfc(struct cdma_ioctl_hdr *hdr, + struct cdma_file *cfile) +{ + struct cdma_cmd_create_jfc_args arg = { 0 }; + struct cdma_dev *cdev = cfile->cdev; + struct cdma_jfc_cfg cfg = { 0 }; + struct cdma_udata udata = { 0 }; + struct cdma_base_jfc *jfc; + struct cdma_queue *queue; + struct cdma_uobj *uobj; + int ret = 0; + + if (!hdr->args_addr || hdr->args_len != (u32)sizeof(arg) || !cfile->uctx) + return -EINVAL; + + ret = (int)copy_from_user(&arg, (void *)hdr->args_addr, + (u32)sizeof(arg)); + if (ret) { + dev_err(cdev->dev, "get user data failed, ret = %d.\n", ret); + return -EFAULT; + } + + uobj = cdma_uobj_get(cfile, arg.in.queue_id, UOBJ_TYPE_QUEUE); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, + "create jfc, get queue uobj failed, queue id = %u.\n", + arg.in.queue_id); + return -EINVAL; + } + queue = (struct cdma_queue *)uobj->object; + + uobj = cdma_uobj_create(cfile, UOBJ_TYPE_JFC); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, "create jfc uobj failed.\n"); + return -ENOMEM; + } + + cfg.depth = arg.in.depth; + cfg.ceqn = arg.in.ceqn; + cfg.queue_id = queue->id; + udata.uctx = cfile->uctx; + udata.udrv_data = (struct cdma_udrv_priv *)&arg.udata; + jfc = cdma_create_jfc(cdev, &cfg, &udata); + if (!jfc) { + dev_err(cdev->dev, "create jfc failed.\n"); + ret = -EFAULT; + goto err_create_jfc; + } + + uobj->object = jfc; + + arg.out.id = jfc->id; + arg.out.depth = jfc->jfc_cfg.depth; + arg.out.handle = uobj->id; + + ret = (int)copy_to_user((void *)hdr->args_addr, &arg, (u32)sizeof(arg)); + if (ret != 0) { + dev_err(cdev->dev, "copy jfc to user failed, ret = %d.\n", ret); + ret = -EFAULT; + goto err_copy_to_user; + } else { + cdma_set_queue_res(cdev, queue, QUEUE_RES_JFC, jfc); + } + + return 0; +err_copy_to_user: + cdma_delete_jfc(cdev, jfc->id, NULL); +err_create_jfc: + cdma_uobj_delete(uobj); + return ret; +} + static int cdma_cmd_delete_jfc(struct cdma_ioctl_hdr *hdr, struct cdma_file *cfile) { @@ -290,6 +362,7 @@ static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { [CDMA_CMD_DELETE_CTX] = cdma_delete_ucontext, [CDMA_CMD_CREATE_QUEUE] = cdma_cmd_create_queue, [CDMA_CMD_DELETE_QUEUE] = cdma_cmd_delete_queue, + [CDMA_CMD_CREATE_JFC] = cdma_cmd_create_jfc, [CDMA_CMD_DELETE_JFC] = cdma_cmd_delete_jfc, }; diff --git a/drivers/ub/cdma/cdma_jfc.c b/drivers/ub/cdma/cdma_jfc.c index 83f55462f297..4609fd22382a 100644 --- a/drivers/ub/cdma/cdma_jfc.c +++ b/drivers/ub/cdma/cdma_jfc.c @@ -5,11 +5,113 @@ #include #include "cdma_cmd.h" +#include "cdma_context.h" #include "cdma_mbox.h" #include "cdma_common.h" #include "cdma_db.h" #include "cdma_jfc.h" +static int cdma_get_cmd_from_user(struct cdma_create_jfc_ucmd *ucmd, + struct cdma_dev *cdev, + struct cdma_udata *udata, + struct cdma_jfc *jfc, + struct cdma_jfc_cfg *cfg) +{ + struct cdma_context *ctx; + u32 depth = cfg->depth; + int ret; + + if (!udata) { + jfc->arm_sn = 1; + jfc->buf.entry_cnt = depth ? roundup_pow_of_two(depth) : depth; + return 0; + } + + if (!udata->udrv_data || !udata->udrv_data->in_addr || + udata->udrv_data->in_len != (u32)sizeof(*ucmd)) { + dev_err(cdev->dev, "invalid parameter.\n"); + return -EINVAL; + } + + ret = (int)copy_from_user(ucmd, (void *)udata->udrv_data->in_addr, + (u32)sizeof(*ucmd)); + if (ret) { + dev_err(cdev->dev, + "copy udata from user failed, ret = %d.\n", ret); + return -EFAULT; + } + + jfc->mode = ucmd->mode; + jfc->db.db_addr = ucmd->db_addr; + + ctx = udata->uctx; + jfc->base.ctx = ctx; + jfc->tid = ctx->tid; + + if (cdev->caps.cqe_size == CDMA_DEFAULT_CQE_SIZE) + jfc->buf.entry_cnt = ucmd->buf_len >> CDMA_JFC_DEFAULT_CQE_SHIFT; + else + jfc->buf.entry_cnt = ucmd->buf_len >> CDMA_JFC_OTHER_CQE_SHIFT; + + return ret; +} + +static int cdma_check_jfc_cfg(struct cdma_dev *cdev, struct cdma_jfc *jfc, + struct cdma_jfc_cfg *cfg) +{ + if (!jfc->buf.entry_cnt || jfc->buf.entry_cnt > cdev->caps.jfc.depth) { + dev_err(cdev->dev, "invalid jfc depth = %u, cap depth = %u.\n", + jfc->buf.entry_cnt, cdev->caps.jfc.depth); + return -EINVAL; + } + + if (jfc->buf.entry_cnt < CDMA_JFC_DEPTH_MIN) + jfc->buf.entry_cnt = CDMA_JFC_DEPTH_MIN; + + if (cfg->ceqn >= cdev->caps.comp_vector_cnt) { + dev_err(cdev->dev, "invalid ceqn = %u, cap ceq cnt = %u.\n", + cfg->ceqn, cdev->caps.comp_vector_cnt); + return -EINVAL; + } + + return 0; +} + +static void cdma_init_jfc_param(struct cdma_jfc_cfg *cfg, struct cdma_jfc *jfc) +{ + jfc->base.id = jfc->jfcn; + jfc->base.jfc_cfg = *cfg; + jfc->ceqn = cfg->ceqn; +} + +static int cdma_jfc_id_alloc(struct cdma_dev *cdev, struct cdma_jfc *jfc) +{ + struct cdma_table *jfc_tbl = &cdev->jfc_table; + u32 min = jfc_tbl->idr_tbl.min; + u32 max = jfc_tbl->idr_tbl.max; + unsigned long flags; + int id; + + idr_preload(GFP_KERNEL); + spin_lock_irqsave(&jfc_tbl->lock, flags); + id = idr_alloc(&jfc_tbl->idr_tbl.idr, jfc, jfc_tbl->idr_tbl.next, max, + GFP_NOWAIT); + if (id < 0) { + id = idr_alloc(&jfc_tbl->idr_tbl.idr, jfc, min, max, + GFP_NOWAIT); + if (id < 0) + dev_err(cdev->dev, "alloc jfc id failed.\n"); + } + + jfc_tbl->idr_tbl.next = (id >= 0 && id + 1 <= max) ? id + 1 : min; + spin_unlock_irqrestore(&jfc_tbl->lock, flags); + idr_preload_end(); + + jfc->jfcn = id; + + return id; +} + static void cdma_jfc_id_free(struct cdma_dev *cdev, u32 jfcn) { struct cdma_table *jfc_tbl = &cdev->jfc_table; @@ -35,6 +137,50 @@ static struct cdma_jfc *cdma_id_find_jfc(struct cdma_dev *cdev, u32 jfcn) return jfc; } +static int cdma_get_jfc_buf(struct cdma_dev *cdev, + struct cdma_create_jfc_ucmd *ucmd, + struct cdma_udata *udata, struct cdma_jfc *jfc) +{ + u32 size; + int ret; + + if (udata) { + jfc->buf.umem = cdma_umem_get(cdev, ucmd->buf_addr, + ucmd->buf_len, false); + if (IS_ERR(jfc->buf.umem)) { + ret = PTR_ERR(jfc->buf.umem); + dev_err(cdev->dev, "get umem failed, ret = %d.\n", + ret); + return ret; + } + jfc->buf.addr = ucmd->buf_addr; + ret = cdma_pin_sw_db(jfc->base.ctx, &jfc->db); + if (ret) + cdma_umem_release(jfc->buf.umem, false); + + return ret; + } + + spin_lock_init(&jfc->lock); + jfc->buf.entry_size = cdev->caps.cqe_size; + jfc->tid = cdev->tid; + size = jfc->buf.entry_size * jfc->buf.entry_cnt; + ret = cdma_k_alloc_buf(cdev, size, &jfc->buf); + if (ret) { + dev_err(cdev->dev, "alloc buffer for jfc failed.\n"); + return ret; + } + + ret = cdma_alloc_sw_db(cdev, &jfc->db); + if (ret) { + dev_err(cdev->dev, "alloc sw db for jfc failed: %u.\n", + jfc->jfcn); + cdma_k_free_buf(cdev, size, &jfc->buf); + } + + return ret; +} + static void cdma_free_jfc_buf(struct cdma_dev *cdev, struct cdma_jfc *jfc) { u32 size; @@ -49,6 +195,37 @@ static void cdma_free_jfc_buf(struct cdma_dev *cdev, struct cdma_jfc *jfc) } } +static void cdma_construct_jfc_ctx(struct cdma_dev *cdev, + struct cdma_jfc *jfc, + struct cdma_jfc_ctx *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + + ctx->state = CDMA_JFC_STATE_VALID; + ctx->arm_st = jfc_arm_mode ? CDMA_CTX_NO_ARMED : CDMA_CTX_ALWAYS_ARMED; + ctx->shift = ilog2(jfc->buf.entry_cnt) - CDMA_JFC_DEPTH_SHIFT_BASE; + + if (cdev->caps.cqe_size == CDMA_DEFAULT_CQE_SIZE) + ctx->cqe_size = CDMA_128_CQE_SIZE; + else + ctx->cqe_size = CDMA_64_CQE_SIZE; + + ctx->record_db_en = CDMA_RECORD_EN; + ctx->jfc_type = CDMA_NORMAL_JFC_TYPE; + ctx->cqe_va_l = jfc->buf.addr >> CQE_VA_L_OFFSET; + ctx->cqe_va_h = jfc->buf.addr >> CQE_VA_H_OFFSET; + ctx->cqe_token_id = jfc->tid; + + if (cqe_mode) + ctx->cq_cnt_mode = CDMA_CQE_CNT_MODE_BY_CI_PI_GAP; + else + ctx->cq_cnt_mode = CDMA_CQE_CNT_MODE_BY_COUNT; + + ctx->ceqn = jfc->ceqn; + ctx->record_db_addr_l = jfc->db.db_addr >> CDMA_DB_L_OFFSET; + ctx->record_db_addr_h = jfc->db.db_addr >> CDMA_DB_H_OFFSET; +} + static int cdma_query_jfc_destroy_done(struct cdma_dev *cdev, uint32_t jfcn) { struct ubase_mbx_attr attr = { 0 }; @@ -94,6 +271,17 @@ static int cdma_destroy_and_flush_jfc(struct cdma_dev *cdev, u32 jfcn) return -ETIMEDOUT; } +static int cdma_post_create_jfc_mbox(struct cdma_dev *cdev, struct cdma_jfc *jfc) +{ + struct ubase_mbx_attr attr = { 0 }; + struct cdma_jfc_ctx ctx = { 0 }; + + cdma_construct_jfc_ctx(cdev, jfc, &ctx); + cdma_fill_mbx_attr(&attr, jfc->jfcn, CDMA_CMD_CREATE_JFC_CONTEXT, 0); + + return cdma_post_mailbox_ctx(cdev, (void *)&ctx, sizeof(ctx), &attr); +} + int cdma_post_destroy_jfc_mbox(struct cdma_dev *cdev, u32 jfcn, enum cdma_jfc_state state) { @@ -106,6 +294,57 @@ int cdma_post_destroy_jfc_mbox(struct cdma_dev *cdev, u32 jfcn, return cdma_post_mailbox_ctx(cdev, (void *)&ctx, sizeof(ctx), &attr); } +struct cdma_base_jfc *cdma_create_jfc(struct cdma_dev *cdev, + struct cdma_jfc_cfg *cfg, + struct cdma_udata *udata) +{ + struct cdma_create_jfc_ucmd ucmd = { 0 }; + struct cdma_jfc *jfc; + int ret; + + jfc = kzalloc(sizeof(*jfc), GFP_KERNEL); + if (!jfc) + return NULL; + + ret = cdma_get_cmd_from_user(&ucmd, cdev, udata, jfc, cfg); + if (ret) + goto err_get_cmd; + + ret = cdma_check_jfc_cfg(cdev, jfc, cfg); + if (ret) + goto err_check_cfg; + + ret = cdma_jfc_id_alloc(cdev, jfc); + if (ret < 0) + goto err_alloc_jfc_id; + + cdma_init_jfc_param(cfg, jfc); + ret = cdma_get_jfc_buf(cdev, &ucmd, udata, jfc); + if (ret) + goto err_get_jfc_buf; + + ret = cdma_post_create_jfc_mbox(cdev, jfc); + if (ret) + goto err_alloc_cqc; + + jfc->base.dev = cdev; + + dev_dbg(cdev->dev, "create jfc id = %u, queue id = %u.\n", + jfc->jfcn, cfg->queue_id); + + return &jfc->base; + +err_alloc_cqc: + cdma_free_jfc_buf(cdev, jfc); +err_get_jfc_buf: + cdma_jfc_id_free(cdev, jfc->jfcn); +err_alloc_jfc_id: +err_check_cfg: +err_get_cmd: + kfree(jfc); + return NULL; +} + int cdma_delete_jfc(struct cdma_dev *cdev, u32 jfcn, struct cdma_cmd_delete_jfc_args *arg) { diff --git a/drivers/ub/cdma/cdma_jfc.h b/drivers/ub/cdma/cdma_jfc.h index 28144b317774..612887837e39 100644 --- a/drivers/ub/cdma/cdma_jfc.h +++ b/drivers/ub/cdma/cdma_jfc.h @@ -7,12 +7,45 @@ #include "cdma_types.h" #include "cdma_db.h" +#define CDMA_JFC_DEPTH_MIN 64 +#define CDMA_JFC_DEPTH_SHIFT_BASE 6 +#define CDMA_JFC_DEFAULT_CQE_SHIFT 7 +#define CDMA_JFC_OTHER_CQE_SHIFT 6 + +#define CDMA_DB_L_OFFSET 6 +#define CDMA_DB_H_OFFSET 38 + +#define CQE_VA_L_OFFSET 12 +#define CQE_VA_H_OFFSET 32 + +enum cdma_record_db { + CDMA_NO_RECORD_EN, + CDMA_RECORD_EN +}; + enum cdma_jfc_state { CDMA_JFC_STATE_INVALID, CDMA_JFC_STATE_VALID, CDMA_JFC_STATE_ERROR }; +enum cdma_armed_jfc { + CDMA_CTX_NO_ARMED, + CDMA_CTX_ALWAYS_ARMED, + CDMA_CTX_REG_NEXT_CEQE, + CDMA_CTX_REG_NEXT_SOLICITED_CEQE +}; + +enum cdma_jfc_type { + CDMA_NORMAL_JFC_TYPE, + CDMA_RAW_JFC_TYPE +}; + +enum cdma_cq_cnt_mode { + CDMA_CQE_CNT_MODE_BY_COUNT, + CDMA_CQE_CNT_MODE_BY_CI_PI_GAP +}; + struct cdma_jfc { struct cdma_base_jfc base; u32 jfcn; @@ -23,6 +56,8 @@ struct cdma_jfc { u32 ci; u32 arm_sn; spinlock_t lock; + refcount_t event_refcount; + struct completion event_comp; u32 mode; }; @@ -98,6 +133,10 @@ struct cdma_jfc_ctx { int cdma_post_destroy_jfc_mbox(struct cdma_dev *cdev, u32 jfcn, enum cdma_jfc_state state); +struct cdma_base_jfc *cdma_create_jfc(struct cdma_dev *cdev, + struct cdma_jfc_cfg *cfg, + struct cdma_udata *udata); + int cdma_delete_jfc(struct cdma_dev *cdev, u32 jfcn, struct cdma_cmd_delete_jfc_args *arg); diff --git a/drivers/ub/cdma/cdma_main.c b/drivers/ub/cdma/cdma_main.c index d04b4b43c989..8519d972c48f 100644 --- a/drivers/ub/cdma/cdma_main.c +++ b/drivers/ub/cdma/cdma_main.c @@ -18,6 +18,10 @@ module_param(jfc_arm_mode, uint, 0444); MODULE_PARM_DESC(jfc_arm_mode, "Set the ARM mode of the JFC, default: 0(0:Always ARM, others: NO ARM)"); +bool cqe_mode = true; +module_param(cqe_mode, bool, 0444); +MODULE_PARM_DESC(cqe_mode, "Set cqe reporting mode, default: 1 (0:BY_COUNT, 1:BY_CI_PI_GAP)"); + struct class *cdma_cdev_class; static int cdma_init_dev_info(struct auxiliary_device *auxdev, struct cdma_dev *cdev) diff --git a/drivers/ub/cdma/cdma_mbox.h b/drivers/ub/cdma/cdma_mbox.h index 0841ea606bbd..584508b592aa 100644 --- a/drivers/ub/cdma/cdma_mbox.h +++ b/drivers/ub/cdma/cdma_mbox.h @@ -9,11 +9,7 @@ enum { /* JFC CMDS */ - CDMA_CMD_WRITE_JFC_CONTEXT_VA = 0x20, - CDMA_CMD_READ_JFC_CONTEXT_VA = 0x21, - CDMA_CMD_DESTROY_JFC_CONTEXT_VA = 0x22, CDMA_CMD_CREATE_JFC_CONTEXT = 0x24, - CDMA_CMD_MODIFY_JFC_CONTEXT = 0x25, CDMA_CMD_QUERY_JFC_CONTEXT = 0x26, CDMA_CMD_DESTROY_JFC_CONTEXT = 0x27, }; diff --git a/drivers/ub/cdma/cdma_queue.c b/drivers/ub/cdma/cdma_queue.c index a25de76cdb4e..a638efe33af1 100644 --- a/drivers/ub/cdma/cdma_queue.c +++ b/drivers/ub/cdma/cdma_queue.c @@ -21,6 +21,35 @@ struct cdma_queue *cdma_find_queue(struct cdma_dev *cdev, u32 queue_id) return queue; } +static void cdma_k_assemble_jfc_cfg(struct cdma_jfc_cfg *jfc_cfg, + struct queue_cfg *cfg, + struct cdma_queue *queue) +{ + jfc_cfg->depth = cfg->queue_depth; + jfc_cfg->queue_id = queue->id; +} + +static int cdma_create_queue_res(struct cdma_dev *cdev, struct queue_cfg *cfg, + struct cdma_queue *queue, u32 eid_index) +{ + struct cdma_jfc_cfg jfc_cfg = { 0 }; + + cdma_k_assemble_jfc_cfg(&jfc_cfg, cfg, queue); + + queue->jfc = cdma_create_jfc(cdev, &jfc_cfg, NULL); + if (!queue->jfc) { + dev_err(cdev->dev, "create jfc failed.\n"); + return -EFAULT; + } + + queue->jfc_id = queue->jfc->id; + + dev_dbg(cdev->dev, "set queue %u jfc id: %u.\n", + queue->id, queue->jfc_id); + + return 0; +} + static void cdma_delete_queue_res(struct cdma_dev *cdev, struct cdma_queue *queue) { @@ -60,6 +89,7 @@ struct cdma_queue *cdma_create_queue(struct cdma_dev *cdev, bool is_kernel) { struct cdma_queue *queue; + int ret; int id; queue = kzalloc(sizeof(*queue), GFP_KERNEL); @@ -76,8 +106,16 @@ struct cdma_queue *cdma_create_queue(struct cdma_dev *cdev, queue->id = id; queue->cfg = *cfg; - if (is_kernel) + if (is_kernel) { + ret = cdma_create_queue_res(cdev, cfg, queue, eid_index); + if (ret) { + dev_err(cdev->dev, "create queue res failed.\n"); + cdma_delete_queue_id(cdev, id); + kfree(queue); + return NULL; + } queue->is_kernel = true; + } return queue; } diff --git a/drivers/ub/cdma/cdma_types.h b/drivers/ub/cdma/cdma_types.h index f8f97a9f9f6d..f55214b84352 100644 --- a/drivers/ub/cdma/cdma_types.h +++ b/drivers/ub/cdma/cdma_types.h @@ -10,6 +10,18 @@ struct cdma_dev; +struct cdma_udrv_priv { + u64 in_addr; + u32 in_len; + u64 out_addr; + u32 out_len; +}; + +struct cdma_udata { + struct cdma_context *uctx; + struct cdma_udrv_priv *udrv_data; +}; + struct cdma_jfc_cfg { u32 depth; u32 ceqn; -- Gitee From 0dca26f9279b41b2cf9cef4b0cce08c01bf2d491 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 10:16:38 +0800 Subject: [PATCH 014/103] ub: cdma: support the deletion of ctp commit 0fb06bebea508db2a00b06bd46bb1b08c2654f4b openEuler This patch implements the deletion functionality of ctp in the CDMA driver. The implementation involves deleting the ctp corresponding to the queue during the queue release process. Signed-off-by: Zhipeng Lu Signed-off-by: Sunyi Nan Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/Makefile | 2 +- drivers/ub/cdma/cdma.h | 1 + drivers/ub/cdma/cdma_dev.c | 7 ++ drivers/ub/cdma/cdma_ioctl.c | 51 ++++++++++++- drivers/ub/cdma/cdma_queue.c | 6 ++ drivers/ub/cdma/cdma_queue.h | 2 + drivers/ub/cdma/cdma_tp.c | 127 ++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_tp.h | 60 +++++++++++++++ drivers/ub/cdma/cdma_types.h | 21 ++++++ include/uapi/ub/cdma/cdma_abi.h | 11 +++ 10 files changed, 285 insertions(+), 3 deletions(-) create mode 100644 drivers/ub/cdma/cdma_tp.c create mode 100644 drivers/ub/cdma/cdma_tp.h diff --git a/drivers/ub/cdma/Makefile b/drivers/ub/cdma/Makefile index 5bb71587ed6d..10bc5ed6b71c 100644 --- a/drivers/ub/cdma/Makefile +++ b/drivers/ub/cdma/Makefile @@ -2,6 +2,6 @@ cdma-$(CONFIG_UB_CDMA) := cdma_main.o cdma_dev.o cdma_chardev.o cdma_cmd.o cdma_tid.o cdma_ioctl.o \ cdma_api.o cdma_context.o cdma_queue.o cdma_uobj.o cdma_jfc.o cdma_common.o \ - cdma_db.o cdma_mbox.o + cdma_db.o cdma_mbox.o cdma_tp.o obj-m += cdma.o diff --git a/drivers/ub/cdma/cdma.h b/drivers/ub/cdma/cdma.h index b379a3f43884..b121ef4bc704 100644 --- a/drivers/ub/cdma/cdma.h +++ b/drivers/ub/cdma/cdma.h @@ -184,6 +184,7 @@ struct cdma_dev { struct list_head db_page; struct cdma_table queue_table; + struct cdma_table ctp_table; struct cdma_table jfc_table; struct mutex file_mutex; struct list_head file_list; diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index bbf44a75fffc..57e5939b3205 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -15,6 +15,8 @@ #include "cdma_context.h" #include #include +#include "cdma_common.h" +#include "cdma_tp.h" #include "cdma_jfc.h" #include "cdma_queue.h" #include "cdma_dev.h" @@ -112,6 +114,7 @@ static void cdma_init_tables(struct cdma_dev *cdev) static void cdma_destroy_tables(struct cdma_dev *cdev) { + cdma_tbl_destroy(cdev, &cdev->ctp_table, "CTP"); cdma_tbl_destroy(cdev, &cdev->jfc_table, "JFC"); cdma_tbl_destroy(cdev, &cdev->queue_table, "QUEUE"); } @@ -181,8 +184,12 @@ static void cdma_release_table_res(struct cdma_dev *cdev) { struct cdma_queue *queue; struct cdma_jfc *jfc; + struct cdma_tp *tmp; int id; + idr_for_each_entry(&cdev->ctp_table.idr_tbl.idr, tmp, id) + cdma_destroy_ctp_imm(cdev, tmp->base.tp_id); + idr_for_each_entry(&cdev->jfc_table.idr_tbl.idr, jfc, id) cdma_delete_jfc(cdev, jfc->jfcn, NULL); diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c index c95230dcc443..5ddc21ae0e76 100644 --- a/drivers/ub/cdma/cdma_ioctl.c +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -9,6 +9,7 @@ #include "cdma.h" #include "cdma_context.h" #include "cdma_types.h" +#include "cdma_tp.h" #include "cdma_queue.h" #include "cdma_jfc.h" #include "cdma_uobj.h" @@ -128,6 +129,51 @@ static int cdma_delete_ucontext(struct cdma_ioctl_hdr *hdr, return 0; } +static int cdma_cmd_delete_ctp(struct cdma_ioctl_hdr *hdr, + struct cdma_file *cfile) +{ + struct cdma_cmd_delete_ctp_args arg = { 0 }; + struct cdma_dev *cdev = cfile->cdev; + struct cdma_base_tp *ctp; + struct cdma_queue *queue; + struct cdma_uobj *uobj; + int ret; + + if (!hdr->args_addr || hdr->args_len < sizeof(arg)) + return -EINVAL; + + ret = (int)copy_from_user(&arg, (void *)hdr->args_addr, + (u32)sizeof(arg)); + if (ret) { + dev_err(&cdev->adev->dev, + "delete tp get user data failed, ret = %d.\n", ret); + return -EFAULT; + } + + uobj = cdma_uobj_get(cfile, arg.in.queue_id, UOBJ_TYPE_QUEUE); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, + "delete ctp, get queue uobj failed, queue id = %u.\n", + arg.in.queue_id); + return -EINVAL; + } + queue = uobj->object; + + uobj = cdma_uobj_get(cfile, arg.in.handle, UOBJ_TYPE_CTP); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, "get ctp uobj failed, handle = %llu.\n", + arg.in.handle); + return -EINVAL; + } + ctp = uobj->object; + + cdma_delete_ctp(cdev, ctp->tp_id); + cdma_uobj_delete(uobj); + cdma_set_queue_res(cdev, queue, QUEUE_RES_TP, NULL); + + return ret; +} + static int cdma_cmd_create_queue(struct cdma_ioctl_hdr *hdr, struct cdma_file *cfile) { struct cdma_cmd_create_queue_args arg = { 0 }; @@ -214,8 +260,8 @@ static int cdma_cmd_delete_queue(struct cdma_ioctl_hdr *hdr, struct cdma_file *c } queue = (struct cdma_queue *)uobj->object; - if (queue->jfc) { - dev_err(cdev->dev, "jfc is still in use."); + if (queue->jfc || queue->tp) { + dev_err(cdev->dev, "jfc/tp is still in use."); return -EBUSY; } @@ -360,6 +406,7 @@ static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { [CDMA_CMD_QUERY_DEV_INFO] = cdma_query_dev, [CDMA_CMD_CREATE_CTX] = cdma_create_ucontext, [CDMA_CMD_DELETE_CTX] = cdma_delete_ucontext, + [CDMA_CMD_DELETE_CTP] = cdma_cmd_delete_ctp, [CDMA_CMD_CREATE_QUEUE] = cdma_cmd_create_queue, [CDMA_CMD_DELETE_QUEUE] = cdma_cmd_delete_queue, [CDMA_CMD_CREATE_JFC] = cdma_cmd_create_jfc, diff --git a/drivers/ub/cdma/cdma_queue.c b/drivers/ub/cdma/cdma_queue.c index a638efe33af1..6b28cb679548 100644 --- a/drivers/ub/cdma/cdma_queue.c +++ b/drivers/ub/cdma/cdma_queue.c @@ -6,6 +6,7 @@ #include "cdma_common.h" #include "cdma_context.h" #include "cdma_jfc.h" +#include "cdma_tp.h" #include "cdma_queue.h" #include "cdma.h" @@ -53,6 +54,8 @@ static int cdma_create_queue_res(struct cdma_dev *cdev, struct queue_cfg *cfg, static void cdma_delete_queue_res(struct cdma_dev *cdev, struct cdma_queue *queue) { + cdma_delete_ctp(cdev, queue->tp->tp_id); + queue->tp = NULL; cdma_delete_jfc(cdev, queue->jfc->id, NULL); queue->jfc = NULL; } @@ -160,6 +163,9 @@ void cdma_set_queue_res(struct cdma_dev *cdev, struct cdma_queue *queue, spin_lock(&cdev->queue_table.lock); switch (type) { + case QUEUE_RES_TP: + queue->tp = res; + break; case QUEUE_RES_JFC: queue->jfc = res; if (queue->jfc) diff --git a/drivers/ub/cdma/cdma_queue.h b/drivers/ub/cdma/cdma_queue.h index 3808c23a1934..af1c54b771ba 100644 --- a/drivers/ub/cdma/cdma_queue.h +++ b/drivers/ub/cdma/cdma_queue.h @@ -9,11 +9,13 @@ struct cdma_context; struct queue_cfg; enum cdma_queue_res_type { + QUEUE_RES_TP, QUEUE_RES_JFC }; struct cdma_queue { struct cdma_base_jfc *jfc; + struct cdma_base_tp *tp; struct cdma_context *ctx; u32 id; struct queue_cfg cfg; diff --git a/drivers/ub/cdma/cdma_tp.c b/drivers/ub/cdma/cdma_tp.c new file mode 100644 index 000000000000..ea8ed73d0b76 --- /dev/null +++ b/drivers/ub/cdma/cdma_tp.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include "cdma_common.h" +#include "cdma_mbox.h" +#include "cdma_tp.h" +#include + +static inline int cdma_ctrlq_msg_send(struct cdma_dev *cdev, + struct ubase_ctrlq_msg *msg) +{ + int ret; + + ret = ubase_ctrlq_send_msg(cdev->adev, msg); + if (ret) + dev_err(cdev->dev, "ctrlq send msg failed, ret = %d.\n", ret); + + return ret; +} + +static void cdma_ctrlq_delete_ctp(struct cdma_dev *cdev, u32 tpn, + struct cdma_tp_cfg *cfg) +{ + struct cdma_ctrlq_tp_delete_cfg ctrlq_tp = { 0 }; + struct cdma_ctrlq_tp_ret tp_out = { 0 }; + struct ubase_ctrlq_msg msg = { 0 }; + int ret; + + ctrlq_tp.seid_flag = CDMA_CTRLQ_FLAG_ON; + ctrlq_tp.deid_flag = CDMA_CTRLQ_FLAG_ON; + ctrlq_tp.scna = cfg->scna; + ctrlq_tp.dcna = cfg->dcna; + ctrlq_tp.seid[0] = cfg->seid; + ctrlq_tp.deid[0] = cfg->deid; + ctrlq_tp.tpn = tpn; + ctrlq_tp.route_type = CDMA_ROUTE_TYPE_CNA; + ctrlq_tp.trans_type = CDMA_TRANS_TYPE_CDMA_CTP; + + msg.service_ver = UBASE_CTRLQ_SER_VER_01; + msg.service_type = UBASE_CTRLQ_SER_TYPE_TP_ACL; + msg.opcode = CDMA_CTRLQ_DELETE_CTP; + msg.need_resp = CDMA_CTRLQ_FLAG_ON; + msg.is_resp = CDMA_CTRLQ_FLAG_OFF; + msg.in_size = sizeof(ctrlq_tp); + msg.in = &ctrlq_tp; + msg.out_size = sizeof(tp_out); + msg.out = &tp_out; + + ret = cdma_ctrlq_msg_send(cdev, &msg); + if (ret) + dev_err(cdev->dev, + "delete ctp failed, tpn = %u, dcna = %u, ret = %d.\n", + tpn, cfg->dcna, ret); +} + +static struct cdma_tp *cdma_id_find_ctp(struct cdma_dev *cdev, u32 id) +{ + struct cdma_tp *tp; + + spin_lock(&cdev->ctp_table.lock); + tp = idr_find(&cdev->ctp_table.idr_tbl.idr, id); + if (!tp) + dev_err(cdev->dev, + "get tp from table failed, id = %u.\n", id); + spin_unlock(&cdev->ctp_table.lock); + + return tp; +} + +void cdma_delete_ctp(struct cdma_dev *cdev, u32 tp_id) +{ + struct cdma_tp_cfg cfg = { 0 }; + struct cdma_tp *tp; + bool flag = false; + u32 tpn; + + if (!cdev) + return; + + tp = cdma_id_find_ctp(cdev, tp_id); + if (!tp) + return; + + spin_lock(&cdev->ctp_table.lock); + refcount_dec(&tp->refcount); + if (refcount_dec_if_one(&tp->refcount)) { + if (cdev->status != CDMA_SUSPEND) { + flag = true; + tpn = tp->base.tpn; + cfg = tp->base.cfg; + } + + dev_dbg(cdev->dev, + "refcout of tp %u is equal to one and erased.\n", tp_id); + idr_remove(&cdev->ctp_table.idr_tbl.idr, tp_id); + kfree(tp); + } + spin_unlock(&cdev->ctp_table.lock); + + if (flag) + cdma_ctrlq_delete_ctp(cdev, tpn, &cfg); +} + +void cdma_destroy_ctp_imm(struct cdma_dev *cdev, u32 tp_id) +{ + struct cdma_tp_cfg cfg = { 0 }; + struct cdma_tp *tp; + u32 tpn; + + if (!cdev) + return; + + tp = cdma_id_find_ctp(cdev, tp_id); + if (!tp) + return; + + spin_lock(&cdev->ctp_table.lock); + tpn = tp->base.tpn; + cfg = tp->base.cfg; + idr_remove(&cdev->ctp_table.idr_tbl.idr, tp_id); + kfree(tp); + spin_unlock(&cdev->ctp_table.lock); + + cdma_ctrlq_delete_ctp(cdev, tpn, &cfg); +} diff --git a/drivers/ub/cdma/cdma_tp.h b/drivers/ub/cdma/cdma_tp.h new file mode 100644 index 000000000000..51ae0bbe5035 --- /dev/null +++ b/drivers/ub/cdma/cdma_tp.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_TP_H__ +#define __CDMA_TP_H__ + +#include "cdma_types.h" + +#define CDMA_CTRLQ_FLAG_ON 1 +#define CDMA_CTRLQ_FLAG_OFF 0 +#define CDMA_EID_DW_SIZE 4 + +struct cdma_tp { + struct cdma_dev *dev; + struct cdma_base_tp base; + refcount_t refcount; + struct completion ae_comp; +}; + +enum cdma_tp_ctrlq_cmd { + CDMA_CTRLQ_CREATE_CTP = 0x01, + CDMA_CTRLQ_DELETE_CTP = 0x02 +}; + +enum cdma_tp_route_type { + CDMA_ROUTE_TYPE_IPV4, + CDMA_ROUTE_TYPE_IPV6, + CDMA_ROUTE_TYPE_CNA, + CDMA_ROUTE_TYPE_MAX +}; + +enum cdma_tp_trans_type { + CDMA_TRANS_TYPE_URMA_TP, + CDMA_TRANS_TYPE_URMA_CTP, + CDMA_TRANS_TYPE_UMS_TP, + CDMA_TRANS_TYPE_CDMA_CTP, + CDMA_TRANS_TYPE_MAX +}; + +struct cdma_ctrlq_tp_ret { + int ret; +}; + +struct cdma_ctrlq_tp_delete_cfg { + u32 seid_flag; + u32 seid[CDMA_EID_DW_SIZE]; + u32 scna; + u32 deid_flag; + u32 deid[CDMA_EID_DW_SIZE]; + u32 dcna; + u32 route_type : 4; /* 0-IPv4, 1-IPv6, 2-CNA */ + u32 trans_type : 4; + u32 rsv : 24; + u32 tpn; +}; + +void cdma_delete_ctp(struct cdma_dev *cdev, uint32_t tp_id); + +void cdma_destroy_ctp_imm(struct cdma_dev *cdev, uint32_t tp_id); +#endif /* CDMA_TP_H */ diff --git a/drivers/ub/cdma/cdma_types.h b/drivers/ub/cdma/cdma_types.h index f55214b84352..8458926b1605 100644 --- a/drivers/ub/cdma/cdma_types.h +++ b/drivers/ub/cdma/cdma_types.h @@ -10,6 +10,12 @@ struct cdma_dev; +struct cdma_ucontext { + struct cdma_dev *dev; + u32 eid; + u32 eid_index; +}; + struct cdma_udrv_priv { u64 in_addr; u32 in_len; @@ -17,6 +23,21 @@ struct cdma_udrv_priv { u32 out_len; }; +struct cdma_tp_cfg { + u32 scna; + u32 dcna; + u32 seid; + u32 deid; +}; + +struct cdma_base_tp { + struct cdma_ucontext *uctx; + struct cdma_tp_cfg cfg; + u64 usr_tp; + u32 tpn; + u32 tp_id; +}; + struct cdma_udata { struct cdma_context *uctx; struct cdma_udrv_priv *udrv_data; diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h index da4aefa119d8..38de05508049 100644 --- a/include/uapi/ub/cdma/cdma_abi.h +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -21,6 +21,7 @@ enum cdma_cmd { CDMA_CMD_QUERY_DEV_INFO, CDMA_CMD_CREATE_CTX, CDMA_CMD_DELETE_CTX, + CDMA_CMD_DELETE_CTP, CDMA_CMD_CREATE_QUEUE, CDMA_CMD_DELETE_QUEUE, CDMA_CMD_CREATE_JFC, @@ -41,6 +42,16 @@ struct cdma_cmd_udrv_priv { __u32 out_len; }; +struct cdma_cmd_delete_ctp_args { + struct { + __u32 tpn; + __u64 handle; + __u32 queue_id; + } in; + struct { + } out; +}; + struct cdma_cmd_create_jfc_args { struct { __u32 depth; /* in terms of CQEBB */ -- Gitee From 550cb621d2961fae9e3f2ec2824b2a943424c19d Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 11:10:28 +0800 Subject: [PATCH 015/103] ub: cdma: support the creation of ctp commit 574cc24bc868dac8e37a1a5cc369cbde1867b46d openEuler This patch implements the creation functionality of ctp in the CDMA driver. The implementation involves creating the ctp corresponding to the queue during the queue creation process. Signed-off-by: Zhipeng Lu Signed-off-by: Sunyi Nan Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma_common.h | 2 + drivers/ub/cdma/cdma_dev.c | 1 + drivers/ub/cdma/cdma_ioctl.c | 72 ++++++++++++++++++ drivers/ub/cdma/cdma_queue.c | 24 ++++++ drivers/ub/cdma/cdma_tp.c | 129 ++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_tp.h | 16 ++++ include/uapi/ub/cdma/cdma_abi.h | 18 +++++ 7 files changed, 262 insertions(+) diff --git a/drivers/ub/cdma/cdma_common.h b/drivers/ub/cdma/cdma_common.h index 57e241c3b946..4580038b5b1b 100644 --- a/drivers/ub/cdma/cdma_common.h +++ b/drivers/ub/cdma/cdma_common.h @@ -7,6 +7,8 @@ #include #include "cdma.h" +#define CDMA_RANGE_INDEX_ENTRY_CNT 0x100000 + #define CDMA_DB_SIZE 64 struct cdma_umem_param { diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index 57e5939b3205..88367e69b8c4 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -110,6 +110,7 @@ static void cdma_init_tables(struct cdma_dev *cdev) queue->start_idx); cdma_tbl_init(&cdev->jfc_table, jfc->start_idx + jfc->max_cnt - 1, jfc->start_idx); + cdma_tbl_init(&cdev->ctp_table, CDMA_RANGE_INDEX_ENTRY_CNT, 0); } static void cdma_destroy_tables(struct cdma_dev *cdev) diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c index 5ddc21ae0e76..c8ba6d9bfd8a 100644 --- a/drivers/ub/cdma/cdma_ioctl.c +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -129,6 +129,77 @@ static int cdma_delete_ucontext(struct cdma_ioctl_hdr *hdr, return 0; } +static int cdma_cmd_create_ctp(struct cdma_ioctl_hdr *hdr, + struct cdma_file *cfile) +{ + struct cdma_cmd_create_ctp_args arg = { 0 }; + struct cdma_dev *cdev = cfile->cdev; + struct cdma_tp_cfg cfg = { 0 }; + struct cdma_base_tp *ctp; + struct cdma_queue *queue; + struct cdma_uobj *uobj; + int ret; + + if (!hdr->args_addr || hdr->args_len < sizeof(arg) || !cfile->uctx) + return -EINVAL; + + ret = (int)copy_from_user(&arg, (void *)hdr->args_addr, + (u32)sizeof(arg)); + if (ret) { + dev_err(&cdev->adev->dev, + "create tp get user data failed, ret = %d.\n", ret); + return -EFAULT; + } + + uobj = cdma_uobj_get(cfile, arg.in.queue_id, UOBJ_TYPE_QUEUE); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, + "create ctp, get queue uobj failed, queue id = %u.\n", + arg.in.queue_id); + return -EINVAL; + } + queue = (struct cdma_queue *)uobj->object; + + uobj = cdma_uobj_create(cfile, UOBJ_TYPE_CTP); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, "create ctp uobj failed.\n"); + return -ENOMEM; + } + + cfg.scna = arg.in.scna; + cfg.dcna = arg.in.dcna; + cfg.seid = arg.in.seid; + cfg.deid = arg.in.deid; + ctp = cdma_create_ctp(cdev, &cfg); + if (!ctp) { + dev_err(&cdev->adev->dev, "create tp failed.\n"); + ret = -EINVAL; + goto delete_obj; + } + uobj->object = ctp; + + arg.out.handle = uobj->id; + arg.out.tpn = ctp->tpn; + ret = (int)copy_to_user((void *)hdr->args_addr, &arg, (u32)sizeof(arg)); + if (ret) { + dev_err(&cdev->adev->dev, + "create tp copy to user data failed, ret = %d.\n", ret); + ret = -EFAULT; + goto delete_ctp; + } + + cdma_set_queue_res(cdev, queue, QUEUE_RES_TP, ctp); + + return 0; + +delete_ctp: + cdma_delete_ctp(cdev, ctp->tp_id); +delete_obj: + cdma_uobj_delete(uobj); + + return ret; +} + static int cdma_cmd_delete_ctp(struct cdma_ioctl_hdr *hdr, struct cdma_file *cfile) { @@ -406,6 +477,7 @@ static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { [CDMA_CMD_QUERY_DEV_INFO] = cdma_query_dev, [CDMA_CMD_CREATE_CTX] = cdma_create_ucontext, [CDMA_CMD_DELETE_CTX] = cdma_delete_ucontext, + [CDMA_CMD_CREATE_CTP] = cdma_cmd_create_ctp, [CDMA_CMD_DELETE_CTP] = cdma_cmd_delete_ctp, [CDMA_CMD_CREATE_QUEUE] = cdma_cmd_create_queue, [CDMA_CMD_DELETE_QUEUE] = cdma_cmd_delete_queue, diff --git a/drivers/ub/cdma/cdma_queue.c b/drivers/ub/cdma/cdma_queue.c index 6b28cb679548..28fdedc258ad 100644 --- a/drivers/ub/cdma/cdma_queue.c +++ b/drivers/ub/cdma/cdma_queue.c @@ -30,12 +30,24 @@ static void cdma_k_assemble_jfc_cfg(struct cdma_jfc_cfg *jfc_cfg, jfc_cfg->queue_id = queue->id; } +static void cdma_k_assemble_tp_cfg(struct cdma_tp_cfg *tp_cfg, + struct cdma_dev *cdev, + struct queue_cfg *cfg) +{ + tp_cfg->seid = cdev->base.attr.eu.eid.dw0; + tp_cfg->dcna = cfg->dcna; + tp_cfg->deid = cfg->rmt_eid.dw0; +} + static int cdma_create_queue_res(struct cdma_dev *cdev, struct queue_cfg *cfg, struct cdma_queue *queue, u32 eid_index) { struct cdma_jfc_cfg jfc_cfg = { 0 }; + struct cdma_tp_cfg tp_cfg = { 0 }; + int ret; cdma_k_assemble_jfc_cfg(&jfc_cfg, cfg, queue); + cdma_k_assemble_tp_cfg(&tp_cfg, cdev, cfg); queue->jfc = cdma_create_jfc(cdev, &jfc_cfg, NULL); if (!queue->jfc) { @@ -43,12 +55,24 @@ static int cdma_create_queue_res(struct cdma_dev *cdev, struct queue_cfg *cfg, return -EFAULT; } + queue->tp = cdma_create_ctp(cdev, &tp_cfg); + if (!queue->tp) { + dev_err(cdev->dev, "create tp failed.\n"); + ret = -EFAULT; + goto delete_jfc; + } + queue->jfc_id = queue->jfc->id; dev_dbg(cdev->dev, "set queue %u jfc id: %u.\n", queue->id, queue->jfc_id); return 0; + +delete_jfc: + cdma_delete_jfc(cdev, queue->jfc->id, NULL); + + return ret; } static void cdma_delete_queue_res(struct cdma_dev *cdev, diff --git a/drivers/ub/cdma/cdma_tp.c b/drivers/ub/cdma/cdma_tp.c index ea8ed73d0b76..a77f1164b416 100644 --- a/drivers/ub/cdma/cdma_tp.c +++ b/drivers/ub/cdma/cdma_tp.c @@ -20,6 +20,53 @@ static inline int cdma_ctrlq_msg_send(struct cdma_dev *cdev, return ret; } +static int cdma_ctrlq_create_ctp(struct cdma_dev *cdev, + struct cdma_tp_cfg *cfg, u32 *tpn) +{ + struct cdma_ctrlq_tp_create_cfg ctrlq_tp; + struct cdma_ctrlq_tp_ret tp_out = { 0 }; + struct ubase_ctrlq_msg msg = { 0 }; + int ret; + + ctrlq_tp = (struct cdma_ctrlq_tp_create_cfg) { + .seid_flag = CDMA_CTRLQ_FLAG_ON, + .deid_flag = CDMA_CTRLQ_FLAG_ON, + .scna = cfg->scna, + .dcna = cfg->dcna, + .seid[0] = cfg->seid, + .deid[0] = cfg->deid, + .route_type = CDMA_ROUTE_TYPE_CNA, + .trans_type = CDMA_TRANS_TYPE_CDMA_CTP + }; + + msg = (struct ubase_ctrlq_msg) { + .service_ver = UBASE_CTRLQ_SER_VER_01, + .service_type = UBASE_CTRLQ_SER_TYPE_TP_ACL, + .opcode = CDMA_CTRLQ_CREATE_CTP, + .need_resp = CDMA_CTRLQ_FLAG_ON, + .is_resp = CDMA_CTRLQ_FLAG_OFF, + .in_size = sizeof(ctrlq_tp), + .in = &ctrlq_tp, + .out_size = sizeof(tp_out), + .out = &tp_out + }; + + ret = cdma_ctrlq_msg_send(cdev, &msg); + if (ret) + return ret; + + ret = tp_out.ret; + if (ret <= 0) { + dev_err(cdev->dev, + "create ctp failed, scna = %u, dcna = %u, ret = %d.\n", + ctrlq_tp.scna, ctrlq_tp.dcna, ret); + return -EFAULT; + } + *tpn = ret & CDMA_TPN_MASK; + + return 0; +} + static void cdma_ctrlq_delete_ctp(struct cdma_dev *cdev, u32 tpn, struct cdma_tp_cfg *cfg) { @@ -69,6 +116,88 @@ static struct cdma_tp *cdma_id_find_ctp(struct cdma_dev *cdev, u32 id) return tp; } +static struct cdma_tp *cdma_tpn_find_ctp(struct cdma_dev *cdev, u32 tpn) +{ + struct cdma_tp *tmp; + int id; + + spin_lock(&cdev->ctp_table.lock); + idr_for_each_entry(&cdev->ctp_table.idr_tbl.idr, tmp, id) { + if (tmp && tmp->base.tpn == tpn) { + spin_unlock(&cdev->ctp_table.lock); + return tmp; + } + } + + spin_unlock(&cdev->ctp_table.lock); + return NULL; +} + +static int cdma_alloc_tp_id(struct cdma_dev *cdev, struct cdma_tp *tp) +{ + struct cdma_table *tp_tbl = &cdev->ctp_table; + int id; + + idr_preload(GFP_KERNEL); + spin_lock(&tp_tbl->lock); + id = idr_alloc(&tp_tbl->idr_tbl.idr, tp, tp_tbl->idr_tbl.min, + tp_tbl->idr_tbl.max, GFP_NOWAIT); + if (id < 0) + dev_err(cdev->dev, "cdma tp id alloc failed.\n"); + spin_unlock(&tp_tbl->lock); + idr_preload_end(); + + return id; +} + +struct cdma_base_tp *cdma_create_ctp(struct cdma_dev *cdev, + struct cdma_tp_cfg *cfg) +{ + struct cdma_tp *tp; + u32 tpn; + int ret; + + ret = cdma_ctrlq_create_ctp(cdev, cfg, &tpn); + if (ret) { + dev_err(cdev->dev, "get tp failed, ret = %d.\n", ret); + return NULL; + } + + tp = (struct cdma_tp *)cdma_tpn_find_ctp(cdev, tpn); + if (tp) { + refcount_inc(&tp->refcount); + return &tp->base; + } + + tp = kzalloc(sizeof(*tp), GFP_KERNEL); + if (!tp) + goto err_alloc_tp; + + refcount_set(&tp->refcount, 1); + tp->base.cfg = *cfg; + tp->base.tpn = tpn; + tp->dev = cdev; + + ret = cdma_alloc_tp_id(cdev, tp); + if (ret < 0) + goto err_alloc_tpid; + + tp->base.tp_id = ret; + refcount_inc(&tp->refcount); + + dev_dbg(cdev->dev, "create ctp id = %u, tpn = %u, seid = %u, dcna = %u\n", + tp->base.tp_id, tpn, cfg->seid, cfg->dcna); + + return &tp->base; + +err_alloc_tpid: + kfree(tp); +err_alloc_tp: + cdma_ctrlq_delete_ctp(cdev, tpn, cfg); + + return NULL; +} + void cdma_delete_ctp(struct cdma_dev *cdev, u32 tp_id) { struct cdma_tp_cfg cfg = { 0 }; diff --git a/drivers/ub/cdma/cdma_tp.h b/drivers/ub/cdma/cdma_tp.h index 51ae0bbe5035..72019df35d74 100644 --- a/drivers/ub/cdma/cdma_tp.h +++ b/drivers/ub/cdma/cdma_tp.h @@ -8,6 +8,7 @@ #define CDMA_CTRLQ_FLAG_ON 1 #define CDMA_CTRLQ_FLAG_OFF 0 +#define CDMA_TPN_MASK 0xffffff #define CDMA_EID_DW_SIZE 4 struct cdma_tp { @@ -37,6 +38,18 @@ enum cdma_tp_trans_type { CDMA_TRANS_TYPE_MAX }; +struct cdma_ctrlq_tp_create_cfg { + u32 seid_flag; /* 0: 128bits eid, 1: 20bits eid */ + u32 seid[CDMA_EID_DW_SIZE]; + u32 scna; + u32 deid_flag; + u32 deid[CDMA_EID_DW_SIZE]; + u32 dcna; + u32 route_type : 4; /* 0-IPv4, 1-IPv6, 2-CNA */ + u32 trans_type : 4; + u32 rsv : 24; +}; + struct cdma_ctrlq_tp_ret { int ret; }; @@ -54,6 +67,9 @@ struct cdma_ctrlq_tp_delete_cfg { u32 tpn; }; +struct cdma_base_tp *cdma_create_ctp(struct cdma_dev *cdev, + struct cdma_tp_cfg *cfg); + void cdma_delete_ctp(struct cdma_dev *cdev, uint32_t tp_id); void cdma_destroy_ctp_imm(struct cdma_dev *cdev, uint32_t tp_id); diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h index 38de05508049..1d34391de601 100644 --- a/include/uapi/ub/cdma/cdma_abi.h +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -21,6 +21,7 @@ enum cdma_cmd { CDMA_CMD_QUERY_DEV_INFO, CDMA_CMD_CREATE_CTX, CDMA_CMD_DELETE_CTX, + CDMA_CMD_CREATE_CTP, CDMA_CMD_DELETE_CTP, CDMA_CMD_CREATE_QUEUE, CDMA_CMD_DELETE_QUEUE, @@ -42,6 +43,23 @@ struct cdma_cmd_udrv_priv { __u32 out_len; }; +struct cdma_cmd_create_ctp_args { + struct { + __u32 scna; + __u32 dcna; + __u32 eid_idx; + __u32 upi; + __u64 dma_tp; + __u32 seid; + __u32 deid; + __u32 queue_id; + } in; + struct { + __u32 tpn; + __u64 handle; + } out; +}; + struct cdma_cmd_delete_ctp_args { struct { __u32 tpn; -- Gitee From 11d65d0b12c68312b2b2de2fd2f8264dc6c29697 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 11:21:09 +0800 Subject: [PATCH 016/103] ub: cdma: support the deletion of jfs commit e3525452704396bd4c8213f09f728c06f4df5302 openEuler This patch implements the deletion functionality of jfs in the CDMA driver. The implementation involves deleting the jfs corresponding to the queue during the queue release process. Signed-off-by: Zhipeng Lu Signed-off-by: Sunyi Nan Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/Makefile | 2 +- drivers/ub/cdma/cdma.h | 1 + drivers/ub/cdma/cdma_common.h | 27 ++++ drivers/ub/cdma/cdma_dev.c | 6 + drivers/ub/cdma/cdma_ioctl.c | 56 ++++++- drivers/ub/cdma/cdma_jfs.c | 250 ++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_jfs.h | 145 ++++++++++++++++++ drivers/ub/cdma/cdma_mbox.h | 6 + drivers/ub/cdma/cdma_queue.c | 8 + drivers/ub/cdma/cdma_queue.h | 3 + drivers/ub/cdma/cdma_types.h | 37 +++++ include/uapi/ub/cdma/cdma_abi.h | 11 ++ 12 files changed, 549 insertions(+), 3 deletions(-) create mode 100644 drivers/ub/cdma/cdma_jfs.c create mode 100644 drivers/ub/cdma/cdma_jfs.h diff --git a/drivers/ub/cdma/Makefile b/drivers/ub/cdma/Makefile index 10bc5ed6b71c..92cd9c3b9f58 100644 --- a/drivers/ub/cdma/Makefile +++ b/drivers/ub/cdma/Makefile @@ -2,6 +2,6 @@ cdma-$(CONFIG_UB_CDMA) := cdma_main.o cdma_dev.o cdma_chardev.o cdma_cmd.o cdma_tid.o cdma_ioctl.o \ cdma_api.o cdma_context.o cdma_queue.o cdma_uobj.o cdma_jfc.o cdma_common.o \ - cdma_db.o cdma_mbox.o cdma_tp.o + cdma_db.o cdma_mbox.o cdma_tp.o cdma_jfs.o obj-m += cdma.o diff --git a/drivers/ub/cdma/cdma.h b/drivers/ub/cdma/cdma.h index b121ef4bc704..20835ae6429d 100644 --- a/drivers/ub/cdma/cdma.h +++ b/drivers/ub/cdma/cdma.h @@ -185,6 +185,7 @@ struct cdma_dev { struct cdma_table queue_table; struct cdma_table ctp_table; + struct cdma_table jfs_table; struct cdma_table jfc_table; struct mutex file_mutex; struct list_head file_list; diff --git a/drivers/ub/cdma/cdma_common.h b/drivers/ub/cdma/cdma_common.h index 4580038b5b1b..5e2c84114e35 100644 --- a/drivers/ub/cdma/cdma_common.h +++ b/drivers/ub/cdma/cdma_common.h @@ -11,6 +11,33 @@ #define CDMA_DB_SIZE 64 +enum cdma_jetty_state { + CDMA_JETTY_RESET, + CDMA_JETTY_READY, + CDMA_JETTY_SUSPENDED, + CDMA_JETTY_ERROR, +}; + +struct cdma_jetty_queue { + struct cdma_buf buf; + void *kva_curr; + u32 id; + void __iomem *db_addr; + void __iomem *dwqe_addr; + u32 pi; + u32 ci; + spinlock_t lock; + u32 max_inline_size; + u32 max_sge_num; + u32 tid; + bool flush_flag; + bool is_jetty; + u32 sqe_bb_cnt; + enum cdma_jetty_state state; + u32 non_pin; + u32 ta_tmo; +}; + struct cdma_umem_param { struct cdma_dev *dev; u64 va; diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index 88367e69b8c4..3806b19f8d52 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -17,6 +17,7 @@ #include #include "cdma_common.h" #include "cdma_tp.h" +#include "cdma_jfs.h" #include "cdma_jfc.h" #include "cdma_queue.h" #include "cdma_dev.h" @@ -116,6 +117,7 @@ static void cdma_init_tables(struct cdma_dev *cdev) static void cdma_destroy_tables(struct cdma_dev *cdev) { cdma_tbl_destroy(cdev, &cdev->ctp_table, "CTP"); + cdma_tbl_destroy(cdev, &cdev->jfs_table, "JFS"); cdma_tbl_destroy(cdev, &cdev->jfc_table, "JFC"); cdma_tbl_destroy(cdev, &cdev->queue_table, "QUEUE"); } @@ -185,12 +187,16 @@ static void cdma_release_table_res(struct cdma_dev *cdev) { struct cdma_queue *queue; struct cdma_jfc *jfc; + struct cdma_jfs *jfs; struct cdma_tp *tmp; int id; idr_for_each_entry(&cdev->ctp_table.idr_tbl.idr, tmp, id) cdma_destroy_ctp_imm(cdev, tmp->base.tp_id); + idr_for_each_entry(&cdev->jfs_table.idr_tbl.idr, jfs, id) + cdma_delete_jfs(cdev, jfs->id); + idr_for_each_entry(&cdev->jfc_table.idr_tbl.idr, jfc, id) cdma_delete_jfc(cdev, jfc->jfcn, NULL); diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c index c8ba6d9bfd8a..28ca199eee3a 100644 --- a/drivers/ub/cdma/cdma_ioctl.c +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -10,6 +10,7 @@ #include "cdma_context.h" #include "cdma_types.h" #include "cdma_tp.h" +#include "cdma_jfs.h" #include "cdma_queue.h" #include "cdma_jfc.h" #include "cdma_uobj.h" @@ -245,6 +246,56 @@ static int cdma_cmd_delete_ctp(struct cdma_ioctl_hdr *hdr, return ret; } +static int cdma_cmd_delete_jfs(struct cdma_ioctl_hdr *hdr, + struct cdma_file *cfile) +{ + struct cdma_cmd_delete_jfs_args arg = { 0 }; + struct cdma_dev *cdev = cfile->cdev; + struct cdma_base_jfs *base_jfs; + struct cdma_queue *queue; + struct cdma_uobj *uobj; + int ret; + + if (!hdr->args_addr || hdr->args_len != (u32)sizeof(arg)) + return -EINVAL; + + ret = (int)copy_from_user(&arg, (void *)hdr->args_addr, + (u32)sizeof(arg)); + if (ret) { + dev_err(&cdev->adev->dev, + "delete jfs get user data failed, ret = %d.\n", ret); + return -EFAULT; + } + + uobj = cdma_uobj_get(cfile, arg.in.queue_id, UOBJ_TYPE_QUEUE); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, + "delete jfs, get queue uobj failed, queue id = %u.\n", + arg.in.queue_id); + return -EINVAL; + } + queue = uobj->object; + + uobj = cdma_uobj_get(cfile, arg.in.handle, UOBJ_TYPE_JFS); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, "get jfs uobj failed, handle = %llu.\n", + arg.in.handle); + return -EINVAL; + } + + base_jfs = uobj->object; + ret = cdma_delete_jfs(cdev, base_jfs->id); + if (ret) { + dev_err(&cdev->adev->dev, "delete jfs failed.\n"); + return ret; + } + + cdma_set_queue_res(cdev, queue, QUEUE_RES_JFS, NULL); + cdma_uobj_delete(uobj); + + return 0; +} + static int cdma_cmd_create_queue(struct cdma_ioctl_hdr *hdr, struct cdma_file *cfile) { struct cdma_cmd_create_queue_args arg = { 0 }; @@ -331,8 +382,8 @@ static int cdma_cmd_delete_queue(struct cdma_ioctl_hdr *hdr, struct cdma_file *c } queue = (struct cdma_queue *)uobj->object; - if (queue->jfc || queue->tp) { - dev_err(cdev->dev, "jfc/tp is still in use."); + if (queue->jfc || queue->jfs || queue->tp) { + dev_err(cdev->dev, "jfc/jfs/tp is still in use."); return -EBUSY; } @@ -479,6 +530,7 @@ static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { [CDMA_CMD_DELETE_CTX] = cdma_delete_ucontext, [CDMA_CMD_CREATE_CTP] = cdma_cmd_create_ctp, [CDMA_CMD_DELETE_CTP] = cdma_cmd_delete_ctp, + [CDMA_CMD_DELETE_JFS] = cdma_cmd_delete_jfs, [CDMA_CMD_CREATE_QUEUE] = cdma_cmd_create_queue, [CDMA_CMD_DELETE_QUEUE] = cdma_cmd_delete_queue, [CDMA_CMD_CREATE_JFC] = cdma_cmd_create_jfc, diff --git a/drivers/ub/cdma/cdma_jfs.c b/drivers/ub/cdma/cdma_jfs.c new file mode 100644 index 000000000000..62846e395ba8 --- /dev/null +++ b/drivers/ub/cdma/cdma_jfs.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define pr_fmt(fmt) "CDMA: " fmt +#define dev_fmt pr_fmt + +#include +#include +#include +#include +#include +#include "cdma_cmd.h" +#include "cdma_common.h" +#include "cdma_mbox.h" +#include "cdma_context.h" +#include "cdma_jfs.h" + +static void cdma_free_sq_buf(struct cdma_dev *cdev, struct cdma_jetty_queue *sq) +{ + u32 size; + + if (sq->buf.kva) { + size = sq->buf.entry_cnt * sq->buf.entry_size; + cdma_k_free_buf(cdev, size, &sq->buf); + } else { + cdma_unpin_queue_addr(sq->buf.umem); + sq->buf.umem = NULL; + } +} + +static inline void cdma_free_jfs_id(struct cdma_dev *cdev, u32 id) +{ + spin_lock(&cdev->jfs_table.lock); + idr_remove(&cdev->jfs_table.idr_tbl.idr, id); + spin_unlock(&cdev->jfs_table.lock); +} + +static int cdma_set_jfs_state(struct cdma_dev *cdev, u32 jfs_id, + enum cdma_jetty_state state) +{ + struct cdma_jfs_ctx ctx[SZ_2] = { 0 }; + struct ubase_mbx_attr attr = { 0 }; + struct cdma_jfs_ctx *ctx_mask; + + ctx_mask = (struct cdma_jfs_ctx *)((char *)ctx + SZ_128); + memset(ctx_mask, 0xff, sizeof(*ctx_mask)); + ctx->state = state; + ctx_mask->state = 0; + + cdma_fill_mbx_attr(&attr, jfs_id, CDMA_CMD_MODIFY_JFS_CONTEXT, 0); + + return cdma_post_mailbox_ctx(cdev, (void *)ctx, sizeof(ctx), &attr); +} + +static int cdma_query_jfs_ctx(struct cdma_dev *cdev, + struct cdma_jfs_ctx *jfs_ctx, + u32 jfs_id) +{ + struct ubase_mbx_attr attr = { 0 }; + struct ubase_cmd_mailbox *mailbox; + + cdma_fill_mbx_attr(&attr, jfs_id, CDMA_CMD_QUERY_JFS_CONTEXT, 0); + mailbox = cdma_mailbox_query_ctx(cdev, &attr); + if (!mailbox) + return -ENOMEM; + memcpy((void *)jfs_ctx, mailbox->buf, sizeof(*jfs_ctx)); + + cdma_free_cmd_mailbox(cdev, mailbox); + + return 0; +} + +static int cdma_destroy_hw_jfs_ctx(struct cdma_dev *cdev, u32 jfs_id) +{ + struct ubase_mbx_attr attr = { 0 }; + int ret; + + cdma_fill_mbx_attr(&attr, jfs_id, CDMA_CMD_DESTROY_JFS_CONTEXT, 0); + ret = cdma_post_mailbox_ctx(cdev, NULL, 0, &attr); + if (ret) + dev_err(cdev->dev, + "post mailbox destroy jfs ctx failed, ret = %d.\n", ret); + + return ret; +} + +static bool cdma_wait_timeout(u32 *sum_times, u32 times, u32 ta_timeout) +{ + u32 wait_time; + + if (*sum_times > ta_timeout) + return true; + + wait_time = 1 << times; + msleep(wait_time); + *sum_times += wait_time; + + return false; +} + +static bool cdma_query_jfs_fd(struct cdma_dev *cdev, + struct cdma_jetty_queue *sq) +{ + struct cdma_jfs_ctx ctx = { 0 }; + u16 rcv_send_diff = 0; + u32 sum_times = 0; + u32 times = 0; + + while (true) { + if (cdma_query_jfs_ctx(cdev, &ctx, sq->id)) + return false; + + if (ctx.flush_cqe_done) + return true; + + if (cdma_wait_timeout(&sum_times, times, sq->ta_tmo)) { + dev_warn(cdev->dev, + "ta timeout, id = %u. PI = %u, CI = %u, next_send_ssn = %u next_rcv_ssn = %u state = %u.\n", + sq->id, ctx.pi, ctx.ci, ctx.next_send_ssn, + ctx.next_rcv_ssn, ctx.state); + break; + } + + times++; + } + + /* In the flip scenario, ctx.next_rcv_ssn - ctx.next_send_ssn value is less than 512. */ + rcv_send_diff = ctx.next_rcv_ssn - ctx.next_send_ssn; + if (ctx.flush_ssn_vld && rcv_send_diff < CDMA_RCV_SEND_MAX_DIFF) + return true; + + dev_err(cdev->dev, "query jfs flush ssn error, id = %u", sq->id); + + return false; +} + +int cdma_modify_jfs_precondition(struct cdma_dev *cdev, + struct cdma_jetty_queue *sq) +{ + struct cdma_jfs_ctx ctx = { 0 }; + u16 rcv_send_diff = 0; + u32 sum_times = 0; + u32 times = 0; + + while (true) { + if (cdma_query_jfs_ctx(cdev, &ctx, sq->id)) { + dev_err(cdev->dev, "query jfs ctx failed, id = %u.\n", + sq->id); + return -ENOMEM; + } + + rcv_send_diff = ctx.next_rcv_ssn - ctx.next_send_ssn; + if ((ctx.pi == ctx.ci) && (rcv_send_diff < CDMA_RCV_SEND_MAX_DIFF) && + (ctx.state == CDMA_JETTY_READY)) + break; + + if ((rcv_send_diff < CDMA_RCV_SEND_MAX_DIFF) && + (ctx.state == CDMA_JETTY_ERROR)) + break; + + if (cdma_wait_timeout(&sum_times, times, sq->ta_tmo)) { + dev_warn(cdev->dev, + "ta timeout, id = %u. PI = %u, CI = %u, next_send_ssn = %u next_rcv_ssn = %u state = %u.\n", + sq->id, ctx.pi, ctx.ci, ctx.next_send_ssn, + ctx.next_rcv_ssn, ctx.state); + break; + } + times++; + } + + return 0; +} + +static bool cdma_destroy_jfs_precondition(struct cdma_dev *cdev, + struct cdma_jetty_queue *sq) +{ +#define CDMA_DESTROY_JETTY_DELAY_TIME 100U + + if ((sq->state == CDMA_JETTY_READY) || + (sq->state == CDMA_JETTY_SUSPENDED)) { + if (cdma_modify_jfs_precondition(cdev, sq)) + return false; + + if (cdma_set_jfs_state(cdev, sq->id, CDMA_JETTY_ERROR)) { + dev_err(cdev->dev, "modify jfs state to error failed, id = %u.\n", + sq->id); + return false; + } + + sq->state = CDMA_JETTY_ERROR; + dev_dbg(cdev->dev, "set jfs %u status finished.\n", sq->id); + } + + if (!cdma_query_jfs_fd(cdev, sq)) + return false; + + udelay(CDMA_DESTROY_JETTY_DELAY_TIME); + + return true; +} + +static int cdma_modify_and_destroy_jfs(struct cdma_dev *cdev, + struct cdma_jetty_queue *sq) +{ + int ret = 0; + + if (!cdma_destroy_jfs_precondition(cdev, sq)) + return -EINVAL; + + if (sq->state != CDMA_JETTY_RESET) + ret = cdma_destroy_hw_jfs_ctx(cdev, sq->id); + + return ret; +} + +int cdma_delete_jfs(struct cdma_dev *cdev, u32 jfs_id) +{ + struct cdma_jfs *jfs; + int ret; + + if (jfs_id >= cdev->caps.jfs.start_idx + cdev->caps.jfs.max_cnt) { + dev_info(cdev->dev, + "jfs id invalid, jfs_id = %u, start_idx = %u, max_cnt = %u.\n", + jfs_id, cdev->caps.jfs.start_idx, + cdev->caps.jfs.max_cnt); + return -EINVAL; + } + + spin_lock(&cdev->jfs_table.lock); + jfs = idr_find(&cdev->jfs_table.idr_tbl.idr, jfs_id); + spin_unlock(&cdev->jfs_table.lock); + if (!jfs) { + dev_err(cdev->dev, "get jfs from table failed, id = %u.\n", jfs_id); + return -EINVAL; + } + + ret = cdma_modify_and_destroy_jfs(cdev, &jfs->sq); + if (ret) + dev_err(cdev->dev, "jfs delete failed, id = %u.\n", jfs->id); + + cdma_free_sq_buf(cdev, &jfs->sq); + + cdma_free_jfs_id(cdev, jfs_id); + + pr_debug("Leave %s, jfsn: %u.\n", __func__, jfs_id); + + kfree(jfs); + + return 0; +} diff --git a/drivers/ub/cdma/cdma_jfs.h b/drivers/ub/cdma/cdma_jfs.h new file mode 100644 index 000000000000..414f18647d8f --- /dev/null +++ b/drivers/ub/cdma/cdma_jfs.h @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_JFS_H__ +#define __CDMA_JFS_H__ + +#include "cdma_common.h" +#include "cdma_types.h" + +#define CDMA_RCV_SEND_MAX_DIFF 512U + +struct cdma_jfs { + struct cdma_base_jfs base_jfs; + struct cdma_dev *dev; + struct cdma_jetty_queue sq; + struct cdma_jfs_cfg cfg; + u64 jfs_addr; + u32 id; + u32 queue_id; + bool is_kernel; + refcount_t ae_ref_cnt; + struct completion ae_comp; +}; + +struct cdma_jfs_ctx { + /* DW0 */ + u32 ta_timeout : 2; + u32 rnr_retry_num : 3; + u32 type : 3; + u32 sqe_bb_shift : 4; + u32 sl : 4; + u32 state : 3; + u32 jfs_mode : 1; + u32 sqe_token_id_l : 12; + /* DW1 */ + u32 sqe_token_id_h : 8; + u32 err_mode : 1; + u32 rsv0 : 1; + u32 cmp_odr : 1; + u32 rsv1 : 1; + u32 sqe_base_addr_l : 20; + /* DW2 */ + u32 sqe_base_addr_h; + /* DW3 */ + u32 rsv2; + /* DW4 */ + u32 tx_jfcn : 20; + u32 jfrn_l : 12; + /* DW5 */ + u32 jfrn_h : 8; + u32 rsv3 : 4; + u32 rx_jfcn : 20; + /* DW6 */ + u32 seid_idx : 10; + u32 rsv4 : 22; + /* DW7 */ + u32 user_data_l; + /* DW8 */ + u32 user_data_h; + /* DW9 */ + u32 sqe_pos : 1; + u32 sqe_pld_pos : 1; + u32 sqe_pld_tokenid : 20; + u32 rsv5 : 10; + /* DW10 */ + u32 tpn : 24; + u32 rsv6 : 8; + /* DW11 */ + u32 rmt_eid : 20; + u32 rsv7 : 12; + /* DW12 */ + u32 rmt_tokenid : 20; + u64 rsv9 : 12; + /* DW13-DW15 */ + u32 rsv12[3]; + /* DW16 */ + u32 next_send_ssn : 16; + u32 src_order_wqe : 16; + /* DW17 */ + u32 src_order_ssn : 16; + u32 src_order_sgme_cnt : 16; + /* DW18 */ + u32 src_order_sgme_send_cnt : 16; + u32 ci : 16; + /* DW19 */ + u32 rsv13; + /* DW20 */ + u32 pi : 16; + u32 sq_db_doing : 1; + u32 ost_rce_credit : 15; + /* DW21 */ + u32 sq_db_retrying : 1; + u32 wmtp_rsv0 : 31; + /* DW22 */ + u32 wait_ack_timeout : 1; + u32 wait_rnr_timeout : 1; + u32 cqe_ie : 1; + u32 cqe_sz : 1; + u32 wmtp_rsv1 : 28; + /* DW23 */ + u32 wml_rsv1; + /* DW24 */ + u32 next_rcv_ssn : 16; + u32 next_cpl_bb_idx : 16; + /* DW25 */ + u32 next_cpl_sgmt_num : 20; + u32 we_rsv0 : 12; + /* DW26 */ + u32 next_cpl_bb_num : 4; + u32 next_cpl_cqe_en : 1; + u32 next_cpl_info_vld : 1; + u32 rpting_cqe : 1; + u32 not_rpt_cqe : 1; + u32 flush_ssn : 16; + u32 flush_ssn_vld : 1; + u32 flush_vld : 1; + u32 flush_cqe_done : 1; + u32 we_rsv1 : 5; + /* DW27 */ + u32 rcved_cont_ssn_num : 20; + u32 we_rsv2 : 12; + /* DW28 */ + u32 sq_timer; + /* DW29 */ + u32 rnr_cnt : 3; + u32 abt_ssn : 16; + u32 abt_ssn_vld : 1; + u32 taack_timeout_flag : 1; + u32 we_rsv3 : 9; + u32 err_type_l : 2; + /* DW30 */ + u32 err_type_h : 7; + u32 sq_flush_ssn : 16; + u32 we_rsv4 : 9; + /* DW31 */ + u32 avail_sgmt_ost : 10; + u32 read_op_cnt : 10; + u32 we_rsv5 : 12; + /* DW32 - DW63 */ + u32 taack_nack_bm[32]; +}; + +int cdma_delete_jfs(struct cdma_dev *cdev, u32 jfs_id); + +#endif diff --git a/drivers/ub/cdma/cdma_mbox.h b/drivers/ub/cdma/cdma_mbox.h index 584508b592aa..e8a00f5c9b97 100644 --- a/drivers/ub/cdma/cdma_mbox.h +++ b/drivers/ub/cdma/cdma_mbox.h @@ -8,6 +8,12 @@ #include enum { + /* JFS CMDS */ + CDMA_CMD_CREATE_JFS_CONTEXT = 0x04, + CDMA_CMD_MODIFY_JFS_CONTEXT = 0x05, + CDMA_CMD_QUERY_JFS_CONTEXT = 0x06, + CDMA_CMD_DESTROY_JFS_CONTEXT = 0x07, + /* JFC CMDS */ CDMA_CMD_CREATE_JFC_CONTEXT = 0x24, CDMA_CMD_QUERY_JFC_CONTEXT = 0x26, diff --git a/drivers/ub/cdma/cdma_queue.c b/drivers/ub/cdma/cdma_queue.c index 28fdedc258ad..20a11bfa5194 100644 --- a/drivers/ub/cdma/cdma_queue.c +++ b/drivers/ub/cdma/cdma_queue.c @@ -6,6 +6,7 @@ #include "cdma_common.h" #include "cdma_context.h" #include "cdma_jfc.h" +#include "cdma_jfs.h" #include "cdma_tp.h" #include "cdma_queue.h" #include "cdma.h" @@ -78,6 +79,8 @@ static int cdma_create_queue_res(struct cdma_dev *cdev, struct queue_cfg *cfg, static void cdma_delete_queue_res(struct cdma_dev *cdev, struct cdma_queue *queue) { + cdma_delete_jfs(cdev, queue->jfs->id); + queue->jfs = NULL; cdma_delete_ctp(cdev, queue->tp->tp_id); queue->tp = NULL; cdma_delete_jfc(cdev, queue->jfc->id, NULL); @@ -190,6 +193,11 @@ void cdma_set_queue_res(struct cdma_dev *cdev, struct cdma_queue *queue, case QUEUE_RES_TP: queue->tp = res; break; + case QUEUE_RES_JFS: + queue->jfs = res; + if (queue->jfs) + queue->jfs_id = queue->jfs->id; + break; case QUEUE_RES_JFC: queue->jfc = res; if (queue->jfc) diff --git a/drivers/ub/cdma/cdma_queue.h b/drivers/ub/cdma/cdma_queue.h index af1c54b771ba..5b434ae66bb9 100644 --- a/drivers/ub/cdma/cdma_queue.h +++ b/drivers/ub/cdma/cdma_queue.h @@ -10,17 +10,20 @@ struct queue_cfg; enum cdma_queue_res_type { QUEUE_RES_TP, + QUEUE_RES_JFS, QUEUE_RES_JFC }; struct cdma_queue { struct cdma_base_jfc *jfc; + struct cdma_base_jfs *jfs; struct cdma_base_tp *tp; struct cdma_context *ctx; u32 id; struct queue_cfg cfg; bool is_kernel; struct list_head list; + u32 jfs_id; u32 jfc_id; }; diff --git a/drivers/ub/cdma/cdma_types.h b/drivers/ub/cdma/cdma_types.h index 8458926b1605..689db795d0c9 100644 --- a/drivers/ub/cdma/cdma_types.h +++ b/drivers/ub/cdma/cdma_types.h @@ -23,6 +23,34 @@ struct cdma_udrv_priv { u32 out_len; }; +union cdma_jfs_flag { + struct { + u32 error_suspend : 1; + u32 outorder_comp : 1; + u32 reserved : 30; + } bs; + u32 value; +}; + +struct cdma_jfs_cfg { + u32 depth; + union cdma_jfs_flag flag; + u32 eid_index; + u8 priority; + u8 max_sge; + u8 max_rsge; + u8 rnr_retry; + u8 err_timeout; + u32 jfc_id; + u32 sqe_pos; + u32 rmt_eid; + u32 tpn; + u32 pld_pos; + u32 pld_token_id; + u32 queue_id; + u32 trans_mode; +}; + struct cdma_tp_cfg { u32 scna; u32 dcna; @@ -43,6 +71,15 @@ struct cdma_udata { struct cdma_udrv_priv *udrv_data; }; +struct cdma_base_jfs { + struct cdma_dev *dev; + struct cdma_context *ctx; + struct cdma_jfs_cfg cfg; + u64 usr_jfs; + u32 id; + atomic_t use_cnt; +}; + struct cdma_jfc_cfg { u32 depth; u32 ceqn; diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h index 1d34391de601..77d916e6d737 100644 --- a/include/uapi/ub/cdma/cdma_abi.h +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -23,6 +23,7 @@ enum cdma_cmd { CDMA_CMD_DELETE_CTX, CDMA_CMD_CREATE_CTP, CDMA_CMD_DELETE_CTP, + CDMA_CMD_DELETE_JFS, CDMA_CMD_CREATE_QUEUE, CDMA_CMD_DELETE_QUEUE, CDMA_CMD_CREATE_JFC, @@ -43,6 +44,16 @@ struct cdma_cmd_udrv_priv { __u32 out_len; }; +struct cdma_cmd_delete_jfs_args { + struct { + __u32 jfs_id; + __u64 handle; + __u32 queue_id; + } in; + struct { + } out; +}; + struct cdma_cmd_create_ctp_args { struct { __u32 scna; -- Gitee From 66389d10eb29ebb7d089a841325f7959980de76c Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 11:36:13 +0800 Subject: [PATCH 017/103] ub: cdma: support the creation of jfs commit 23359f7079fc7b585d1d5aa770680c3d9e347cfd openEuler This patch implements the creation functionality of jfs in the CDMA driver. The implementation involves creating the jfs corresponding to the queue during the queue creation process. Signed-off-by: Zhipeng Lu Signed-off-by: Sunyi Nan Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma_chardev.c | 50 ++++++ drivers/ub/cdma/cdma_common.h | 26 +++ drivers/ub/cdma/cdma_dev.c | 3 + drivers/ub/cdma/cdma_ioctl.c | 97 +++++++++++ drivers/ub/cdma/cdma_jfs.c | 286 ++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_jfs.h | 13 ++ drivers/ub/cdma/cdma_queue.c | 36 +++- include/uapi/ub/cdma/cdma_abi.h | 53 ++++++ 8 files changed, 562 insertions(+), 2 deletions(-) diff --git a/drivers/ub/cdma/cdma_chardev.c b/drivers/ub/cdma/cdma_chardev.c index b3a8b75b019e..124b5701b253 100644 --- a/drivers/ub/cdma/cdma_chardev.c +++ b/drivers/ub/cdma/cdma_chardev.c @@ -9,6 +9,7 @@ #include "cdma_ioctl.h" #include "cdma_context.h" #include "cdma_chardev.h" +#include "cdma_jfs.h" #include "cdma_types.h" #include "cdma_uobj.h" #include "cdma.h" @@ -32,6 +33,11 @@ static void cdma_num_free(struct cdma_dev *cdev) spin_unlock(&cdma_num_mg.lock); } +static inline u64 cdma_get_mmap_idx(struct vm_area_struct *vma) +{ + return (vma->vm_pgoff >> MAP_INDEX_SHIFT) & MAP_INDEX_MASK; +} + static inline int cdma_get_mmap_cmd(struct vm_area_struct *vma) { return (vma->vm_pgoff & MAP_COMMAND_MASK); @@ -74,11 +80,39 @@ static long cdma_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return -ENOIOCTLCMD; } +static int cdma_remap_check_jfs_id(struct cdma_file *cfile, u32 jfs_id) +{ + struct cdma_dev *cdev = cfile->cdev; + struct cdma_jfs *jfs; + int ret = -EINVAL; + + spin_lock(&cdev->jfs_table.lock); + jfs = idr_find(&cdev->jfs_table.idr_tbl.idr, jfs_id); + if (!jfs) { + spin_unlock(&cdev->jfs_table.lock); + dev_err(cdev->dev, + "check failed, jfs_id = %u not exist.\n", jfs_id); + return ret; + } + + if (cfile->uctx != jfs->base_jfs.ctx) { + dev_err(cdev->dev, + "check failed, jfs_id = %u, uctx invalid\n", jfs_id); + spin_unlock(&cdev->jfs_table.lock); + return -EINVAL; + } + spin_unlock(&cdev->jfs_table.lock); + + return 0; +} + static int cdma_remap_pfn_range(struct cdma_file *cfile, struct vm_area_struct *vma) { #define JFC_DB_UNMAP_BOUND 1 struct cdma_dev *cdev = cfile->cdev; resource_size_t db_addr; + u64 address; + u32 jfs_id; u32 cmd; db_addr = cdev->db_base; @@ -96,6 +130,22 @@ static int cdma_remap_pfn_range(struct cdma_file *cfile, struct vm_area_struct * return -EAGAIN; } break; + case CDMA_MMAP_JETTY_DSQE: + jfs_id = cdma_get_mmap_idx(vma); + if (cdma_remap_check_jfs_id(cfile, jfs_id)) { + dev_err(cdev->dev, + "mmap failed, invalid jfs_id = %u\n", jfs_id); + return -EINVAL; + } + + address = (uint64_t)db_addr + CDMA_JETTY_DSQE_OFFSET + jfs_id * PAGE_SIZE; + + if (io_remap_pfn_range(vma, vma->vm_start, address >> PAGE_SHIFT, + PAGE_SIZE, vma->vm_page_prot)) { + dev_err(cdev->dev, "remap jetty page failed.\n"); + return -EAGAIN; + } + break; default: dev_err(cdev->dev, "mmap failed, cmd(%u) is not supported.\n", cmd); diff --git a/drivers/ub/cdma/cdma_common.h b/drivers/ub/cdma/cdma_common.h index 5e2c84114e35..b5a149658847 100644 --- a/drivers/ub/cdma/cdma_common.h +++ b/drivers/ub/cdma/cdma_common.h @@ -7,10 +7,30 @@ #include #include "cdma.h" +#define JETTY_DSQE_OFFSET 0x1000 +#define CDMA_USER_DATA_H_OFFSET 32U + +#define SQE_TOKEN_ID_L_MASK GENMASK(11, 0) +#define SQE_TOKEN_ID_H_OFFSET 12U +#define SQE_TOKEN_ID_H_MASK GENMASK(7, 0) +#define SQE_VA_L_OFFSET 12U +#define SQE_VA_L_VALID_BIT GENMASK(19, 0) +#define SQE_VA_H_OFFSET 32U +#define SQE_VA_H_VALID_BIT GENMASK(31, 0) +#define WQE_BB_SIZE_SHIFT 6 +#define AVAIL_SGMT_OST_INIT 512 + #define CDMA_RANGE_INDEX_ENTRY_CNT 0x100000 #define CDMA_DB_SIZE 64 +#define SQE_PLD_TOKEN_ID_MASK GENMASK(19, 0) + +enum cdma_jfsc_mode { + CDMA_JFS_MODE, + CDMA_JETTY_MODE, +}; + enum cdma_jetty_state { CDMA_JETTY_RESET, CDMA_JETTY_READY, @@ -18,6 +38,12 @@ enum cdma_jetty_state { CDMA_JETTY_ERROR, }; +enum cdma_jetty_type { + CDMA_JETTY_ROL = 2, + CDMA_JETTY_ROI, + CDMA_JETTY_TYPE_RESERVED, +}; + struct cdma_jetty_queue { struct cdma_buf buf; void *kva_curr; diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index 3806b19f8d52..75c87176e868 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -105,12 +105,15 @@ static void cdma_tbl_destroy(struct cdma_dev *cdev, struct cdma_table *table, static void cdma_init_tables(struct cdma_dev *cdev) { struct cdma_res *queue = &cdev->caps.queue; + struct cdma_res *jfs = &cdev->caps.jfs; struct cdma_res *jfc = &cdev->caps.jfc; cdma_tbl_init(&cdev->queue_table, queue->start_idx + queue->max_cnt - 1, queue->start_idx); cdma_tbl_init(&cdev->jfc_table, jfc->start_idx + jfc->max_cnt - 1, jfc->start_idx); + cdma_tbl_init(&cdev->jfs_table, jfs->max_cnt + jfs->start_idx - 1, + jfs->start_idx); cdma_tbl_init(&cdev->ctp_table, CDMA_RANGE_INDEX_ENTRY_CNT, 0); } diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c index 28ca199eee3a..5f63cad58088 100644 --- a/drivers/ub/cdma/cdma_ioctl.c +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -246,6 +246,102 @@ static int cdma_cmd_delete_ctp(struct cdma_ioctl_hdr *hdr, return ret; } +static void cdma_config_jfs(struct cdma_jfs_cfg *cfg, + const struct cdma_cmd_create_jfs_args *arg) +{ + cfg->depth = arg->in.depth; + cfg->flag.value = arg->in.flag; + cfg->eid_index = arg->in.eid_idx; + cfg->max_sge = arg->in.max_sge; + cfg->max_rsge = arg->in.max_rsge; + cfg->rnr_retry = arg->in.rnr_retry; + cfg->err_timeout = arg->in.err_timeout; + cfg->priority = arg->in.priority; + cfg->jfc_id = arg->in.jfc_id; + cfg->rmt_eid = arg->in.rmt_eid; + cfg->pld_token_id = arg->in.pld_token_id; + cfg->tpn = arg->in.tpn; + cfg->queue_id = arg->in.queue_id; + cfg->trans_mode = arg->in.trans_mode; +} + +static int cdma_cmd_create_jfs(struct cdma_ioctl_hdr *hdr, + struct cdma_file *cfile) +{ + struct cdma_cmd_create_jfs_args arg = { 0 }; + struct cdma_dev *cdev = cfile->cdev; + struct cdma_jfs_cfg cfg = { 0 }; + struct cdma_udata udata = { 0 }; + struct cdma_base_jfs *jfs; + struct cdma_queue *queue; + struct cdma_uobj *uobj; + int ret; + + if (!hdr->args_addr || hdr->args_len != (u32)sizeof(arg) || !cfile->uctx) + return -EINVAL; + + ret = (int)copy_from_user(&arg, (void *)hdr->args_addr, + (u32)sizeof(arg)); + if (ret) { + dev_err(&cdev->adev->dev, + "create jfs get user data failed, ret = %d.\n", ret); + return -EFAULT; + } + + uobj = cdma_uobj_get(cfile, arg.in.queue_id, UOBJ_TYPE_QUEUE); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, + "create jfs, get queue uobj failed, queue id = %u.\n", + arg.in.queue_id); + return -EINVAL; + } + queue = (struct cdma_queue *)uobj->object; + + uobj = cdma_uobj_create(cfile, UOBJ_TYPE_JFS); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, "create jfs uobj failed.\n"); + return -ENOMEM; + } + + udata.uctx = cfile->uctx; + udata.udrv_data = (struct cdma_udrv_priv *)&arg.udata; + arg.in.queue_id = queue->id; + cdma_config_jfs(&cfg, &arg); + + jfs = cdma_create_jfs(cdev, &cfg, &udata); + if (!jfs) { + dev_err(&cdev->adev->dev, "create jfs failed.\n"); + ret = -EFAULT; + goto err_create_jfs; + } + + uobj->object = jfs; + + arg.out.id = jfs->id; + arg.out.handle = uobj->id; + arg.out.depth = jfs->cfg.depth; + arg.out.max_sge = jfs->cfg.max_sge; + arg.out.max_rsge = jfs->cfg.max_rsge; + + ret = (int)copy_to_user((void *)hdr->args_addr, &arg, (u32)sizeof(arg)); + if (ret) { + ret = -EFAULT; + dev_err(&cdev->adev->dev, + "create jfs copy to user data failed, ret = %d.\n", + ret); + goto err_copy_to_usr; + } + + cdma_set_queue_res(cdev, queue, QUEUE_RES_JFS, jfs); + + return 0; +err_copy_to_usr: + cdma_delete_jfs(cdev, jfs->id); +err_create_jfs: + cdma_uobj_delete(uobj); + return ret; +} + static int cdma_cmd_delete_jfs(struct cdma_ioctl_hdr *hdr, struct cdma_file *cfile) { @@ -530,6 +626,7 @@ static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { [CDMA_CMD_DELETE_CTX] = cdma_delete_ucontext, [CDMA_CMD_CREATE_CTP] = cdma_cmd_create_ctp, [CDMA_CMD_DELETE_CTP] = cdma_cmd_delete_ctp, + [CDMA_CMD_CREATE_JFS] = cdma_cmd_create_jfs, [CDMA_CMD_DELETE_JFS] = cdma_cmd_delete_jfs, [CDMA_CMD_CREATE_QUEUE] = cdma_cmd_create_queue, [CDMA_CMD_DELETE_QUEUE] = cdma_cmd_delete_queue, diff --git a/drivers/ub/cdma/cdma_jfs.c b/drivers/ub/cdma/cdma_jfs.c index 62846e395ba8..599068837a4b 100644 --- a/drivers/ub/cdma/cdma_jfs.c +++ b/drivers/ub/cdma/cdma_jfs.c @@ -15,6 +15,204 @@ #include "cdma_context.h" #include "cdma_jfs.h" +static int cdma_get_user_jfs_cmd(struct cdma_dev *cdev, struct cdma_jfs *jfs, + struct cdma_udata *udata, + struct cdma_create_jfs_ucmd *ucmd) +{ + struct cdma_context *ctx; + int ret; + + if (!udata) { + jfs->jfs_addr = (uintptr_t)&jfs->sq; + jfs->is_kernel = true; + return 0; + } + + if (!udata->udrv_data || !udata->udrv_data->in_addr || + udata->udrv_data->in_len != (u32)sizeof(*ucmd)) { + dev_err(cdev->dev, "invalid parameter.\n"); + return -EINVAL; + } + + ret = (int)copy_from_user(ucmd, (void *)udata->udrv_data->in_addr, + (u32)sizeof(*ucmd)); + if (ret) { + dev_err(cdev->dev, + "copy jfs udata failed, ret = %d.\n", ret); + return -EFAULT; + } + + if (!ucmd->jetty_addr || !ucmd->buf_len || !ucmd->buf_addr) { + dev_err(cdev->dev, "user cmd param is invalid.\n"); + return -EINVAL; + } + + ctx = udata->uctx; + jfs->base_jfs.ctx = ctx; + jfs->sq.tid = ctx->tid; + jfs->jfs_addr = ucmd->jetty_addr; + jfs->sq.id = ucmd->jfs_id; + jfs->queue_id = ucmd->queue_id; + jfs->sq.non_pin = ucmd->non_pin; + + return 0; +} + +static int cdma_alloc_jfs_id(struct cdma_dev *cdev, struct cdma_jfs *jfs) +{ + struct cdma_idr *idr_tbl = &cdev->jfs_table.idr_tbl; + u32 max = idr_tbl->max; + u32 min = idr_tbl->min; + int id; + + idr_preload(GFP_KERNEL); + spin_lock(&cdev->jfs_table.lock); + id = idr_alloc(&idr_tbl->idr, jfs, idr_tbl->next, max, GFP_NOWAIT); + if (id < 0) { + id = idr_alloc(&idr_tbl->idr, jfs, min, max, GFP_NOWAIT); + if (id < 0) + dev_err(cdev->dev, "alloc cdma jfs id failed.\n"); + } + + idr_tbl->next = (id >= 0 && id + 1 <= max) ? id + 1 : min; + spin_unlock(&cdev->jfs_table.lock); + idr_preload_end(); + + return id; +} + +static inline u32 cdma_sq_cal_wqebb_num(u32 sqe_ctl_len, u32 sge_num) +{ + return (sqe_ctl_len + (sge_num - 1) * CDMA_JFS_SGE_SIZE) / CDMA_JFS_WQEBB_SIZE + 1; +} + +static inline void cdma_set_kernel_db(struct cdma_dev *cdev, + struct cdma_jetty_queue *queue) +{ + queue->dwqe_addr = + cdev->k_db_base + JETTY_DSQE_OFFSET + PAGE_SIZE * queue->id; + queue->db_addr = queue->dwqe_addr + CDMA_DOORBELL_OFFSET; +} + +static int cdma_get_sq_buf(struct cdma_dev *cdev, struct cdma_jetty_queue *sq, + struct cdma_jfs_cfg *jfs_cfg, + struct cdma_create_jfs_ucmd *ucmd, bool is_kernel) +{ + u32 wqe_bb_depth; + u32 sqe_bb_cnt; + int ret = 0; + u32 size; + + if (!is_kernel) { + ret = cdma_pin_queue_addr(cdev, ucmd->buf_addr, + ucmd->buf_len, &sq->buf); + if (ret) { + dev_err(cdev->dev, + "pin jfs queue addr failed, ret = %d.\n", + ret); + return ret; + } + + sq->buf.entry_cnt = ucmd->buf_len >> WQE_BB_SIZE_SHIFT; + sq->sqe_bb_cnt = ucmd->sqe_bb_cnt; + if (sq->sqe_bb_cnt > MAX_WQEBB_NUM) + sq->sqe_bb_cnt = MAX_WQEBB_NUM; + } else { + spin_lock_init(&sq->lock); + sq->tid = cdev->tid; + sq->max_sge_num = jfs_cfg->max_sge; + sqe_bb_cnt = + cdma_sq_cal_wqebb_num(SQE_WRITE_NOTIFY_CTL_LEN, + jfs_cfg->max_sge); + if (sqe_bb_cnt > MAX_WQEBB_NUM) + sqe_bb_cnt = MAX_WQEBB_NUM; + sq->sqe_bb_cnt = sqe_bb_cnt; + + wqe_bb_depth = roundup_pow_of_two(sqe_bb_cnt * jfs_cfg->depth); + sq->buf.entry_size = CDMA_JFS_WQEBB_SIZE; + size = ALIGN(wqe_bb_depth * sq->buf.entry_size, CDMA_HW_PAGE_SIZE); + sq->buf.entry_cnt = size >> WQE_BB_SIZE_SHIFT; + + ret = cdma_k_alloc_buf(cdev, size, &sq->buf); + if (ret) { + dev_err(cdev->dev, + "alloc jfs (%u) sq buf failed, size = %u.\n", + sq->id, size); + return ret; + } + + cdma_set_kernel_db(cdev, sq); + sq->kva_curr = sq->buf.kva; + } + + return ret; +} + +static void cdma_init_jfsc(struct cdma_dev *cdev, struct cdma_jfs_cfg *cfg, + struct cdma_jfs *jfs, void *mb_buf) +{ + struct cdma_jfs_ctx *ctx = mb_buf; + + ctx->state = CDMA_JETTY_READY; + ctx->sl = cdev->sl[cfg->priority % cdev->sl_num]; + ctx->jfs_mode = CDMA_JFS_MODE; + ctx->type = (cfg->trans_mode == CDMA_JETTY_ROL) ? CDMA_JETTY_ROL : CDMA_JETTY_ROI; + ctx->sqe_base_addr_l = (jfs->sq.buf.addr >> SQE_VA_L_OFFSET) & + (u32)SQE_VA_L_VALID_BIT; + ctx->sqe_base_addr_h = (jfs->sq.buf.addr >> SQE_VA_H_OFFSET) & + (u32)SQE_VA_H_VALID_BIT; + ctx->sqe_token_id_l = jfs->sq.tid & (u32)SQE_TOKEN_ID_L_MASK; + ctx->sqe_token_id_h = (jfs->sq.tid >> SQE_TOKEN_ID_H_OFFSET) & + (u32)SQE_TOKEN_ID_H_MASK; + ctx->sqe_bb_shift = ilog2(roundup_pow_of_two(jfs->sq.buf.entry_cnt)); + ctx->tx_jfcn = cfg->jfc_id; + ctx->ta_timeout = cfg->err_timeout; + ctx->rnr_retry_num = cfg->rnr_retry; + ctx->user_data_l = jfs->jfs_addr; + ctx->user_data_h = jfs->jfs_addr >> CDMA_USER_DATA_H_OFFSET; + ctx->seid_idx = cfg->eid_index; + ctx->err_mode = cfg->flag.bs.error_suspend; + ctx->cmp_odr = cfg->flag.bs.outorder_comp; + ctx->avail_sgmt_ost = AVAIL_SGMT_OST_INIT; + ctx->sqe_pld_tokenid = jfs->sq.tid & (u32)SQE_PLD_TOKEN_ID_MASK; + ctx->next_send_ssn = get_random_u16(); + ctx->next_rcv_ssn = ctx->next_send_ssn; + + ctx->sqe_pos = cfg->sqe_pos; + ctx->sqe_pld_pos = cfg->pld_pos; + ctx->rmt_eid = cfg->rmt_eid; + ctx->rmt_tokenid = cfg->pld_token_id; + ctx->tpn = cfg->tpn; +} + +static inline void cdma_reset_jfs_queue(struct cdma_jetty_queue *sq) +{ + sq->kva_curr = sq->buf.kva; + sq->pi = 0; + sq->ci = 0; + sq->flush_flag = false; +} + +static int cdma_create_hw_jfs_ctx(struct cdma_dev *cdev, struct cdma_jfs *jfs, + struct cdma_jfs_cfg *cfg) +{ + struct ubase_mbx_attr attr = { 0 }; + struct cdma_jfs_ctx ctx = { 0 }; + int ret; + + cdma_init_jfsc(cdev, cfg, jfs, &ctx); + cdma_fill_mbx_attr(&attr, jfs->sq.id, CDMA_CMD_CREATE_JFS_CONTEXT, 0); + ret = cdma_post_mailbox_ctx(cdev, &ctx, sizeof(ctx), &attr); + if (ret) { + dev_err(cdev->dev, "upgrade jfs ctx failed, ret = %d.\n", ret); + return ret; + } + + cdma_reset_jfs_queue(&jfs->sq); + + return 0; +} + static void cdma_free_sq_buf(struct cdma_dev *cdev, struct cdma_jetty_queue *sq) { u32 size; @@ -28,6 +226,23 @@ static void cdma_free_sq_buf(struct cdma_dev *cdev, struct cdma_jetty_queue *sq) } } +static void cdma_set_query_flush_time(struct cdma_jetty_queue *sq, + u8 err_timeout) +{ + static u32 time[] = { + CDMA_TA_TIMEOUT_128MS, + CDMA_TA_TIMEOUT_1000MS, + CDMA_TA_TIMEOUT_8000MS, + CDMA_TA_TIMEOUT_64000MS, + }; + static u8 time_index_max = ARRAY_SIZE(time) - 1; + + if (err_timeout > time_index_max) + err_timeout = time_index_max; + + sq->ta_tmo = time[err_timeout]; +} + static inline void cdma_free_jfs_id(struct cdma_dev *cdev, u32 id) { spin_lock(&cdev->jfs_table.lock); @@ -35,6 +250,77 @@ static inline void cdma_free_jfs_id(struct cdma_dev *cdev, u32 id) spin_unlock(&cdev->jfs_table.lock); } +static int cdma_verify_jfs_cfg(struct cdma_dev *cdev, struct cdma_jfs_cfg *cfg) +{ + if (!cfg->depth || cfg->depth > cdev->caps.jfs.depth) { + dev_err(cdev->dev, + "jfs param is invalid, depth = %u, max_depth = %u.\n", + cfg->depth, cdev->caps.jfs.depth); + return -EINVAL; + } + + return 0; +} + +struct cdma_base_jfs *cdma_create_jfs(struct cdma_dev *cdev, + struct cdma_jfs_cfg *cfg, + struct cdma_udata *udata) +{ + struct cdma_create_jfs_ucmd ucmd = { 0 }; + struct cdma_jfs *jfs; + int ret; + + if (cdma_verify_jfs_cfg(cdev, cfg)) + return NULL; + + jfs = kzalloc(sizeof(*jfs), GFP_KERNEL); + if (!jfs) + return NULL; + + ret = cdma_get_user_jfs_cmd(cdev, jfs, udata, &ucmd); + if (ret) + goto err_alloc_jfsn; + + ret = cdma_alloc_jfs_id(cdev, jfs); + if (ret < 0) + goto err_alloc_jfsn; + + jfs->id = ret; + jfs->sq.id = ret; + jfs->base_jfs.id = jfs->sq.id; + jfs->base_jfs.cfg = *cfg; + jfs->dev = cdev; + jfs->queue_id = cfg->queue_id; + + ret = cdma_get_sq_buf(cdev, &jfs->sq, cfg, &ucmd, jfs->is_kernel); + if (ret) + goto err_get_jfs_buf; + + ret = cdma_create_hw_jfs_ctx(cdev, jfs, cfg); + if (ret) + goto err_create_hw_jfsc; + + cdma_set_query_flush_time(&jfs->sq, cfg->err_timeout); + + jfs->sq.state = CDMA_JETTY_READY; + jfs->base_jfs.dev = cdev; + + dev_dbg(cdev->dev, + "create jfs id = %u, queue id = %u, depth = %u, priority = %u, jfc id = %u.\n", + jfs->id, jfs->queue_id, cfg->depth, cfg->priority, cfg->jfc_id); + + return &jfs->base_jfs; + +err_create_hw_jfsc: + cdma_free_sq_buf(cdev, &jfs->sq); +err_get_jfs_buf: + cdma_free_jfs_id(cdev, jfs->sq.id); +err_alloc_jfsn: + kfree(jfs); + + return NULL; +} + static int cdma_set_jfs_state(struct cdma_dev *cdev, u32 jfs_id, enum cdma_jetty_state state) { diff --git a/drivers/ub/cdma/cdma_jfs.h b/drivers/ub/cdma/cdma_jfs.h index 414f18647d8f..7625ace4b5c7 100644 --- a/drivers/ub/cdma/cdma_jfs.h +++ b/drivers/ub/cdma/cdma_jfs.h @@ -7,6 +7,16 @@ #include "cdma_common.h" #include "cdma_types.h" +#define MAX_WQEBB_NUM 4 +#define CDMA_JFS_WQEBB_SIZE 64 +#define CDMA_JFS_SGE_SIZE 16 +#define SQE_WRITE_NOTIFY_CTL_LEN 80 + +#define CDMA_TA_TIMEOUT_128MS 128 +#define CDMA_TA_TIMEOUT_1000MS 1000 +#define CDMA_TA_TIMEOUT_8000MS 8000 +#define CDMA_TA_TIMEOUT_64000MS 64000 + #define CDMA_RCV_SEND_MAX_DIFF 512U struct cdma_jfs { @@ -140,6 +150,9 @@ struct cdma_jfs_ctx { u32 taack_nack_bm[32]; }; +struct cdma_base_jfs *cdma_create_jfs(struct cdma_dev *cdev, + struct cdma_jfs_cfg *cfg, + struct cdma_udata *udata); int cdma_delete_jfs(struct cdma_dev *cdev, u32 jfs_id); #endif diff --git a/drivers/ub/cdma/cdma_queue.c b/drivers/ub/cdma/cdma_queue.c index 20a11bfa5194..9b03baef162c 100644 --- a/drivers/ub/cdma/cdma_queue.c +++ b/drivers/ub/cdma/cdma_queue.c @@ -23,6 +23,24 @@ struct cdma_queue *cdma_find_queue(struct cdma_dev *cdev, u32 queue_id) return queue; } +static void cdma_k_assemble_jfs_cfg(struct cdma_jfs_cfg *jfs_cfg, + struct cdma_dev *cdev, + u32 eid_index, + struct queue_cfg *cfg, + struct cdma_queue *queue) +{ + jfs_cfg->eid_index = eid_index; + jfs_cfg->max_rsge = cdev->base.attr.dev_cap.max_jfs_rsge; + jfs_cfg->max_sge = cdev->base.attr.dev_cap.max_jfs_sge; + jfs_cfg->depth = cfg->queue_depth; + jfs_cfg->err_timeout = CDMA_TYPICAL_ERR_TIMEOUT; + jfs_cfg->priority = cfg->priority; + jfs_cfg->rnr_retry = CDMA_TYPICAL_RNR_RETRY; + jfs_cfg->rmt_eid = cfg->rmt_eid.dw0; + jfs_cfg->queue_id = queue->id; + jfs_cfg->trans_mode = cfg->trans_mode; +} + static void cdma_k_assemble_jfc_cfg(struct cdma_jfc_cfg *jfc_cfg, struct queue_cfg *cfg, struct cdma_queue *queue) @@ -44,9 +62,11 @@ static int cdma_create_queue_res(struct cdma_dev *cdev, struct queue_cfg *cfg, struct cdma_queue *queue, u32 eid_index) { struct cdma_jfc_cfg jfc_cfg = { 0 }; + struct cdma_jfs_cfg jfs_cfg = { 0 }; struct cdma_tp_cfg tp_cfg = { 0 }; int ret; + cdma_k_assemble_jfs_cfg(&jfs_cfg, cdev, eid_index, cfg, queue); cdma_k_assemble_jfc_cfg(&jfc_cfg, cfg, queue); cdma_k_assemble_tp_cfg(&tp_cfg, cdev, cfg); @@ -63,13 +83,25 @@ static int cdma_create_queue_res(struct cdma_dev *cdev, struct queue_cfg *cfg, goto delete_jfc; } + jfs_cfg.tpn = queue->tp->tpn; + jfs_cfg.jfc_id = queue->jfc->id; + queue->jfs = cdma_create_jfs(cdev, &jfs_cfg, NULL); + if (!queue->jfs) { + dev_err(cdev->dev, "create jfs failed.\n"); + ret = -EFAULT; + goto delete_tp; + } + + queue->jfs_id = queue->jfs->id; queue->jfc_id = queue->jfc->id; - dev_dbg(cdev->dev, "set queue %u jfc id: %u.\n", - queue->id, queue->jfc_id); + dev_dbg(cdev->dev, "set queue %u jfs id: %u, jfc id: %u.\n", + queue->id, queue->jfs_id, queue->jfc_id); return 0; +delete_tp: + cdma_delete_ctp(cdev, queue->tp->tp_id); delete_jfc: cdma_delete_jfc(cdev, queue->jfc->id, NULL); diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h index 77d916e6d737..59367df04865 100644 --- a/include/uapi/ub/cdma/cdma_abi.h +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -10,7 +10,15 @@ #define CDMA_IOC_MAGIC 'C' #define CDMA_SYNC _IOWR(CDMA_IOC_MAGIC, 0, struct cdma_ioctl_hdr) +#define CDMA_DOORBELL_OFFSET 0x80 + #define MAP_COMMAND_MASK 0xff +#define MAP_INDEX_MASK 0xffffff +#define MAP_INDEX_SHIFT 8 + +/* cdma queue cfg deault value */ +#define CDMA_TYPICAL_RNR_RETRY 7 +#define CDMA_TYPICAL_ERR_TIMEOUT 2 /* 0:128ms 1:1s 2:8s 3:64s */ enum db_mmap_type { CDMA_MMAP_JFC_PAGE, @@ -23,6 +31,7 @@ enum cdma_cmd { CDMA_CMD_DELETE_CTX, CDMA_CMD_CREATE_CTP, CDMA_CMD_DELETE_CTP, + CDMA_CMD_CREATE_JFS, CDMA_CMD_DELETE_JFS, CDMA_CMD_CREATE_QUEUE, CDMA_CMD_DELETE_QUEUE, @@ -37,6 +46,21 @@ struct cdma_ioctl_hdr { __u64 args_addr; }; +struct cdma_create_jfs_ucmd { + __u64 buf_addr; + __u32 buf_len; + __u64 db_addr; + __u64 idx_addr; + __u32 idx_len; + __u64 jetty_addr; + __u32 sqe_bb_cnt; + __u32 jetty_type; + __u32 non_pin; + __u32 jfs_id; + __u32 queue_id; + __u32 tid; +}; + struct cdma_cmd_udrv_priv { __u64 in_addr; __u32 in_len; @@ -44,6 +68,35 @@ struct cdma_cmd_udrv_priv { __u32 out_len; }; +struct cdma_cmd_create_jfs_args { + struct { + __u32 depth; + __u32 flag; + __u32 eid_idx; + __u8 priority; + __u8 max_sge; + __u8 max_rsge; + __u8 retry_cnt; + __u8 rnr_retry; + __u8 err_timeout; + __u32 jfc_id; + __u32 queue_id; + __u32 rmt_eid; + __u32 pld_token_id; + __u32 tpn; + __u64 dma_jfs; /* dma jfs pointer */ + __u32 trans_mode; + } in; + struct { + __u32 id; + __u32 depth; + __u8 max_sge; + __u8 max_rsge; + __u64 handle; + } out; + struct cdma_cmd_udrv_priv udata; +}; + struct cdma_cmd_delete_jfs_args { struct { __u32 jfs_id; -- Gitee From 778334d30f4a5ed2a0806995cf8af42986c19500 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 11:47:02 +0800 Subject: [PATCH 018/103] ub: cdma: support reporting asynchronous events commit 35203448b9d150f435ec8bfa8072b5dc748127a0 openEuler This patch implements the handling and reporting of asynchronous events in the CDMA driver. The implementation includes writing the corresponding asynchronous events to the device's asynchronous event queue when exceptions occur in jfs or jfc. Signed-off-by: Zhipeng Lu Signed-off-by: Jingjing Ku Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/Makefile | 2 +- drivers/ub/cdma/cdma.h | 19 +- drivers/ub/cdma/cdma_context.h | 1 + drivers/ub/cdma/cdma_eq.c | 194 ++++++++++++++ drivers/ub/cdma/cdma_eq.h | 16 ++ drivers/ub/cdma/cdma_event.c | 431 ++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_event.h | 58 +++++ drivers/ub/cdma/cdma_ioctl.c | 25 +- drivers/ub/cdma/cdma_jfc.c | 29 +++ drivers/ub/cdma/cdma_jfs.c | 26 +- drivers/ub/cdma/cdma_main.c | 22 ++ drivers/ub/cdma/cdma_types.h | 23 +- include/uapi/ub/cdma/cdma_abi.h | 15 ++ 13 files changed, 855 insertions(+), 6 deletions(-) create mode 100644 drivers/ub/cdma/cdma_eq.c create mode 100644 drivers/ub/cdma/cdma_eq.h create mode 100644 drivers/ub/cdma/cdma_event.c create mode 100644 drivers/ub/cdma/cdma_event.h diff --git a/drivers/ub/cdma/Makefile b/drivers/ub/cdma/Makefile index 92cd9c3b9f58..58a355df4c33 100644 --- a/drivers/ub/cdma/Makefile +++ b/drivers/ub/cdma/Makefile @@ -2,6 +2,6 @@ cdma-$(CONFIG_UB_CDMA) := cdma_main.o cdma_dev.o cdma_chardev.o cdma_cmd.o cdma_tid.o cdma_ioctl.o \ cdma_api.o cdma_context.o cdma_queue.o cdma_uobj.o cdma_jfc.o cdma_common.o \ - cdma_db.o cdma_mbox.o cdma_tp.o cdma_jfs.o + cdma_db.o cdma_mbox.o cdma_tp.o cdma_jfs.o cdma_eq.o cdma_event.o obj-m += cdma.o diff --git a/drivers/ub/cdma/cdma.h b/drivers/ub/cdma/cdma.h index 20835ae6429d..995f28def668 100644 --- a/drivers/ub/cdma/cdma.h +++ b/drivers/ub/cdma/cdma.h @@ -8,7 +8,7 @@ #include #include #include - +#include #include extern u32 jfc_arm_mode; @@ -187,9 +187,26 @@ struct cdma_dev { struct cdma_table ctp_table; struct cdma_table jfs_table; struct cdma_table jfc_table; + struct ubase_event_nb *ae_event_addr[UBASE_EVENT_TYPE_MAX]; struct mutex file_mutex; struct list_head file_list; struct page *arm_db_page; }; +struct cdma_jfs_event { + struct list_head async_event_list; + u32 async_events_reported; +}; + +struct cdma_jfc_event { + struct cdma_base_jfc *jfc; + struct list_head async_event_list; + u32 async_events_reported; +}; + +static inline struct cdma_dev *get_cdma_dev(struct auxiliary_device *adev) +{ + return (struct cdma_dev *)dev_get_drvdata(&adev->dev); +} + #endif /* _CDMA_H_ */ diff --git a/drivers/ub/cdma/cdma_context.h b/drivers/ub/cdma/cdma_context.h index 8cbc980dc726..c48ac55631bf 100644 --- a/drivers/ub/cdma/cdma_context.h +++ b/drivers/ub/cdma/cdma_context.h @@ -19,6 +19,7 @@ struct cdma_context { spinlock_t lock; int handle; u32 tid; + void *jfae; bool is_kernel; atomic_t ref_cnt; struct list_head queue_list; diff --git a/drivers/ub/cdma/cdma_eq.c b/drivers/ub/cdma/cdma_eq.c new file mode 100644 index 000000000000..51c84ebaf7b6 --- /dev/null +++ b/drivers/ub/cdma/cdma_eq.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include +#include +#include +#include +#include "cdma_jfs.h" +#include "cdma_jfc.h" +#include "cdma.h" +#include "cdma_eq.h" + +static int cdma_ae_jfs_check_error(struct auxiliary_device *adev, + u32 jetty_id) +{ + struct cdma_dev *cdev = get_cdma_dev(adev); + struct cdma_base_jfs *base_jfs; + struct cdma_event ae; + struct cdma_jfs *jfs; + + spin_lock(&cdev->jfs_table.lock); + jfs = idr_find(&cdev->jfs_table.idr_tbl.idr, jetty_id); + if (!jfs) { + dev_err(cdev->dev, "ae get jfs from table failed, id = %u.\n", + jetty_id); + spin_unlock(&cdev->jfs_table.lock); + return -EINVAL; + } + + base_jfs = &jfs->base_jfs; + + if (base_jfs->jfae_handler && base_jfs->ctx) { + refcount_inc(&jfs->ae_ref_cnt); + spin_unlock(&cdev->jfs_table.lock); + ae.dev = base_jfs->dev; + ae.element.jfs = base_jfs; + ae.event_type = CDMA_EVENT_JFS_ERR; + base_jfs->jfae_handler(&ae, base_jfs->ctx); + if (refcount_dec_and_test(&jfs->ae_ref_cnt)) { + complete(&jfs->ae_comp); + dev_dbg(cdev->dev, "jfs ae handler done.\n"); + } + } else { + spin_unlock(&cdev->jfs_table.lock); + } + + return 0; +} + +static int cdma_ae_jfc_check_error(struct auxiliary_device *adev, + u32 jetty_id) +{ + struct cdma_dev *cdev = get_cdma_dev(adev); + struct cdma_base_jfc *base_jfc; + struct cdma_event ae; + struct cdma_jfc *jfc; + unsigned long flags; + + spin_lock_irqsave(&cdev->jfc_table.lock, flags); + jfc = idr_find(&cdev->jfc_table.idr_tbl.idr, jetty_id); + if (!jfc) { + dev_err(cdev->dev, "get jfc from table failed, id = %u.\n", + jetty_id); + spin_unlock_irqrestore(&cdev->jfc_table.lock, flags); + return -EINVAL; + } + base_jfc = &jfc->base; + + if (base_jfc->jfae_handler && base_jfc->ctx) { + refcount_inc(&jfc->event_refcount); + spin_unlock_irqrestore(&cdev->jfc_table.lock, flags); + ae.dev = base_jfc->dev; + ae.element.jfc = base_jfc; + ae.event_type = CDMA_EVENT_JFC_ERR; + base_jfc->jfae_handler(&ae, base_jfc->ctx); + if (refcount_dec_and_test(&jfc->event_refcount)) { + complete(&jfc->event_comp); + dev_dbg(cdev->dev, "jfc ae handler done.\n"); + } + } else { + spin_unlock_irqrestore(&cdev->jfc_table.lock, flags); + } + + return 0; +} + +static int cdma_ae_jetty_level_error(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct ubase_event_nb *ev_nb = container_of(nb, struct ubase_event_nb, nb); + struct auxiliary_device *adev = ev_nb->back; + struct ubase_aeq_notify_info *info = data; + u32 jetty_id; + + jetty_id = info->aeqe->event.queue_event.num; + + switch (info->sub_type) { + case UBASE_SUBEVENT_TYPE_JFS_CHECK_ERROR: + return cdma_ae_jfs_check_error(adev, jetty_id); + case UBASE_SUBEVENT_TYPE_JFC_CHECK_ERROR: + return cdma_ae_jfc_check_error(adev, jetty_id); + default: + dev_warn(&adev->dev, "cdma get unsupported async event type %u.\n", + info->sub_type); + return -EINVAL; + } +} + +static struct cdma_ae_operation cdma_ae_opts[] = { + {UBASE_EVENT_TYPE_JETTY_LEVEL_ERROR, cdma_ae_jetty_level_error} +}; + +static int cdma_event_register(struct auxiliary_device *adev, + enum ubase_event_type event_type, notifier_fn_t call) +{ + struct cdma_dev *cdma_dev = get_cdma_dev(adev); + struct ubase_event_nb *event_cb; + int ret; + + event_cb = kzalloc(sizeof(*event_cb), GFP_KERNEL); + if (!event_cb) + return -ENOMEM; + + event_cb->drv_type = UBASE_DRV_CDMA; + event_cb->event_type = event_type; + event_cb->back = (void *)adev; + event_cb->nb.notifier_call = call; + + ret = ubase_event_register(adev, event_cb); + if (ret) { + dev_err(cdma_dev->dev, + "register async event failed, event type = %u, ret = %d.\n", + event_cb->event_type, ret); + kfree(event_cb); + return ret; + } + cdma_dev->ae_event_addr[event_type] = event_cb; + + return 0; +} + +/* thanks to drivers/infiniband/hw/erdma/erdma_eq.c */ +int cdma_reg_ae_event(struct auxiliary_device *adev) +{ + struct cdma_dev *cdma_dev; + u32 opt_num; + int ret = 0; + int i; + + if (!adev) + return -EINVAL; + + cdma_dev = get_cdma_dev(adev); + if (!cdma_dev) + return -EINVAL; + + opt_num = sizeof(cdma_ae_opts) / sizeof(struct cdma_ae_operation); + for (i = 0; i < opt_num; ++i) { + ret = cdma_event_register(adev, + (enum ubase_event_type)cdma_ae_opts[i].op_code, + cdma_ae_opts[i].call); + if (ret) { + cdma_unreg_ae_event(adev); + return -EINVAL; + } + } + + dev_dbg(cdma_dev->dev, "cdma register ae event, ret = %d.\n", ret); + + return ret; +} + +void cdma_unreg_ae_event(struct auxiliary_device *adev) +{ + struct cdma_dev *cdma_dev; + int i; + + if (!adev) + return; + + cdma_dev = get_cdma_dev(adev); + if (!cdma_dev) + return; + + for (i = 0; i < UBASE_EVENT_TYPE_MAX; i++) { + if (cdma_dev->ae_event_addr[i]) { + ubase_event_unregister(adev, cdma_dev->ae_event_addr[i]); + kfree(cdma_dev->ae_event_addr[i]); + cdma_dev->ae_event_addr[i] = NULL; + } + } +} diff --git a/drivers/ub/cdma/cdma_eq.h b/drivers/ub/cdma/cdma_eq.h new file mode 100644 index 000000000000..51417e3eea50 --- /dev/null +++ b/drivers/ub/cdma/cdma_eq.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_EQ_H__ +#define __CDMA_EQ_H__ +#include + +struct cdma_ae_operation { + u32 op_code; + notifier_fn_t call; +}; + +int cdma_reg_ae_event(struct auxiliary_device *adev); +void cdma_unreg_ae_event(struct auxiliary_device *adev); + +#endif diff --git a/drivers/ub/cdma/cdma_event.c b/drivers/ub/cdma/cdma_event.c new file mode 100644 index 000000000000..5d81363c88ff --- /dev/null +++ b/drivers/ub/cdma/cdma_event.c @@ -0,0 +1,431 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define pr_fmt(fmt) "CDMA: " fmt +#define dev_fmt pr_fmt + +#include +#include +#include +#include +#include +#include +#include +#include "cdma_uobj.h" +#include "cdma_event.h" + +static __poll_t cdma_jfe_poll(struct cdma_jfe *jfe, struct file *filp, + struct poll_table_struct *wait) +{ + __poll_t flag = 0; + + poll_wait(filp, &jfe->poll_wait, wait); + + spin_lock_irq(&jfe->lock); + if (!list_empty(&jfe->event_list)) + flag = EPOLLIN | EPOLLRDNORM; + + spin_unlock_irq(&jfe->lock); + + return flag; +} + +static u32 cdma_read_jfe_event(struct cdma_jfe *jfe, u32 max_event_cnt, + struct list_head *event_list) +{ + struct cdma_jfe_event *event; + struct list_head *next; + struct list_head *p; + u32 cnt = 0; + + if (!max_event_cnt) + return 0; + + spin_lock_irq(&jfe->lock); + + list_for_each_safe(p, next, &jfe->event_list) { + event = list_entry(p, struct cdma_jfe_event, node); + if (event->counter) { + ++(*event->counter); + list_del(&event->obj_node); + } + list_del(p); + if (jfe->event_list_count > 0) + jfe->event_list_count--; + list_add_tail(p, event_list); + cnt++; + if (cnt == max_event_cnt) + break; + } + spin_unlock_irq(&jfe->lock); + + return cnt; +} + +static int cdma_wait_event(struct cdma_jfe *jfe, bool nonblock, + u32 max_event_cnt, u32 *event_cnt, + struct list_head *event_list) +{ + int ret; + + *event_cnt = 0; + spin_lock_irq(&jfe->lock); + while (list_empty(&jfe->event_list)) { + spin_unlock_irq(&jfe->lock); + if (nonblock) + return -EAGAIN; + + ret = wait_event_interruptible(jfe->poll_wait, + !list_empty(&jfe->event_list)); + if (ret) + return ret; + + spin_lock_irq(&jfe->lock); + if (list_empty(&jfe->event_list)) { + spin_unlock_irq(&jfe->lock); + return -EIO; + } + } + spin_unlock_irq(&jfe->lock); + *event_cnt = cdma_read_jfe_event(jfe, max_event_cnt, event_list); + + return 0; +} + +static void cdma_write_event(struct cdma_jfe *jfe, u64 event_data, + u32 event_type, struct list_head *obj_event_list, + u32 *counter) +{ + struct cdma_jfe_event *event; + unsigned long flags; + + event = kzalloc(sizeof(*event), GFP_ATOMIC); + if (event == NULL) + return; + + spin_lock_irqsave(&jfe->lock, flags); + INIT_LIST_HEAD(&event->obj_node); + event->event_type = event_type; + event->event_data = event_data; + event->counter = counter; + list_add_tail(&event->node, &jfe->event_list); + if (obj_event_list) + list_add_tail(&event->obj_node, obj_event_list); + if (jfe->async_queue) + kill_fasync(&jfe->async_queue, SIGIO, POLL_IN); + jfe->event_list_count++; + spin_unlock_irqrestore(&jfe->lock, flags); + wake_up_interruptible(&jfe->poll_wait); +} + +static void cdma_init_jfe(struct cdma_jfe *jfe) +{ + spin_lock_init(&jfe->lock); + INIT_LIST_HEAD(&jfe->event_list); + init_waitqueue_head(&jfe->poll_wait); + jfe->async_queue = NULL; + jfe->event_list_count = 0; +} + +static void cdma_uninit_jfe(struct cdma_jfe *jfe) +{ + struct cdma_jfe_event *event; + struct list_head *p, *next; + + spin_lock_irq(&jfe->lock); + list_for_each_safe(p, next, &jfe->event_list) { + event = list_entry(p, struct cdma_jfe_event, node); + if (event->counter) + list_del(&event->obj_node); + kfree(event); + } + spin_unlock_irq(&jfe->lock); +} + +static void cdma_write_async_event(struct cdma_context *ctx, u64 event_data, + u32 type, struct list_head *obj_event_list, + u32 *counter) +{ + struct cdma_jfae *jfae; + + rcu_read_lock(); + jfae = (struct cdma_jfae *)(rcu_dereference(ctx->jfae)); + if (!jfae) + goto err_free_rcu; + + if (jfae->jfe.event_list_count >= MAX_EVENT_LIST_SIZE) { + pr_debug("event list overflow, and this write will be discarded.\n"); + goto err_free_rcu; + } + + cdma_write_event(&jfae->jfe, event_data, type, obj_event_list, counter); + +err_free_rcu: + rcu_read_unlock(); +} + +void cdma_jfs_async_event_cb(struct cdma_event *event, struct cdma_context *ctx) +{ + struct cdma_jfs_event *jfs_event; + + jfs_event = &event->element.jfs->jfs_event; + cdma_write_async_event(ctx, event->element.jfs->cfg.queue_id, + event->event_type, &jfs_event->async_event_list, + &jfs_event->async_events_reported); +} + +void cdma_jfc_async_event_cb(struct cdma_event *event, struct cdma_context *ctx) +{ + struct cdma_jfc_event *jfc_event; + + jfc_event = &event->element.jfc->jfc_event; + cdma_write_async_event(ctx, event->element.jfc->jfc_cfg.queue_id, + event->event_type, &jfc_event->async_event_list, + &jfc_event->async_events_reported); +} + +static inline void cdma_set_async_event(struct cdma_cmd_async_event *async_event, + const struct cdma_jfe_event *event) +{ + async_event->event_data = event->event_data; + async_event->event_type = event->event_type; +} + +static int cdma_get_async_event(struct cdma_jfae *jfae, struct file *filp, + unsigned long arg) +{ + struct cdma_cmd_async_event async_event = { 0 }; + struct cdma_jfe_event *event; + struct list_head event_list; + u32 event_cnt; + int ret; + + if (!arg) { + pr_err("invalid jfae arg.\n"); + return -EINVAL; + } + + INIT_LIST_HEAD(&event_list); + ret = cdma_wait_event(&jfae->jfe, filp->f_flags & O_NONBLOCK, 1, + &event_cnt, &event_list); + if (ret < 0) { + pr_err("wait event failed, ret = %d.\n", ret); + return ret; + } + event = list_first_entry(&event_list, struct cdma_jfe_event, node); + if (event == NULL) + return -EIO; + + cdma_set_async_event(&async_event, event); + list_del(&event->node); + kfree(event); + + if (event_cnt > 0) { + ret = (int)copy_to_user((void *)arg, &async_event, + sizeof(async_event)); + if (ret) { + pr_err("dev copy to user failed, ret = %d\n", ret); + return -EFAULT; + } + } + + return 0; +} + +static __poll_t cdma_jfae_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct cdma_jfae *jfae = (struct cdma_jfae *)filp->private_data; + + if (!jfae || !jfae->cfile || !jfae->cfile->cdev) + return POLLERR; + + return cdma_jfe_poll(&jfae->jfe, filp, wait); +} + +static long cdma_jfae_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct cdma_jfae *jfae = (struct cdma_jfae *)filp->private_data; + unsigned int nr; + int ret; + + if (!jfae) + return -EINVAL; + + nr = (unsigned int)_IOC_NR(cmd); + + switch (nr) { + case JFAE_CMD_GET_ASYNC_EVENT: + ret = cdma_get_async_event(jfae, filp, arg); + break; + default: + dev_err(jfae->cfile->cdev->dev, "nr = %u.\n", nr); + ret = -ENOIOCTLCMD; + break; + } + + return (long)ret; +} + +static int cdma_delete_jfae(struct inode *inode, struct file *filp) +{ + struct cdma_file *cfile; + struct cdma_jfae *jfae; + + if (!filp || !filp->private_data) + return 0; + + jfae = (struct cdma_jfae *)filp->private_data; + cfile = jfae->cfile; + if (!cfile) + return 0; + + if (!mutex_trylock(&cfile->ctx_mutex)) + return -ENOLCK; + jfae->ctx->jfae = NULL; + cdma_uninit_jfe(&jfae->jfe); + kfree(jfae); + filp->private_data = NULL; + mutex_unlock(&cfile->ctx_mutex); + cdma_close_uobj_fd(cfile); + + pr_debug("jfae is release.\n"); + return 0; +} + +static int cdma_jfae_fasync(int fd, struct file *filp, int on) +{ + struct cdma_jfae *jfae = (struct cdma_jfae *)filp->private_data; + int ret; + + if (!jfae) + return -EINVAL; + + spin_lock_irq(&jfae->jfe.lock); + ret = fasync_helper(fd, filp, on, &jfae->jfe.async_queue); + spin_unlock_irq(&jfae->jfe.lock); + + return ret; +} + +const struct file_operations cdma_jfae_fops = { + .owner = THIS_MODULE, + .poll = cdma_jfae_poll, + .unlocked_ioctl = cdma_jfae_ioctl, + .release = cdma_delete_jfae, + .fasync = cdma_jfae_fasync, +}; + +struct cdma_jfae *cdma_alloc_jfae(struct cdma_file *cfile) +{ + struct cdma_jfae *jfae; + struct file *file; + int fd; + + if (!cfile) + return NULL; + + fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC); + if (fd < 0) + return NULL; + + jfae = kzalloc(sizeof(*jfae), GFP_KERNEL); + if (!jfae) + goto err_put_unused_fd; + + file = anon_inode_getfile("[jfae]", &cdma_jfae_fops, jfae, + O_RDWR | O_CLOEXEC); + if (IS_ERR(file)) + goto err_free_jfae; + + cdma_init_jfe(&jfae->jfe); + jfae->fd = fd; + jfae->file = file; + jfae->cfile = cfile; + fd_install(fd, file); + + return jfae; + +err_free_jfae: + kfree(jfae); +err_put_unused_fd: + put_unused_fd(fd); + + return NULL; +} + +void cdma_free_jfae(struct cdma_jfae *jfae) +{ + if (!jfae) + return; + + fput(jfae->file); + put_unused_fd(jfae->fd); +} + +int cdma_get_jfae(struct cdma_context *ctx) +{ + struct cdma_jfae *jfae; + struct file *file; + + if (!ctx) + return -EINVAL; + + jfae = (struct cdma_jfae *)ctx->jfae; + if (!jfae) + return -EINVAL; + + file = fget(jfae->fd); + if (!file) + return -ENOENT; + + if (file->private_data != jfae) { + fput(file); + return -EBADF; + } + + return 0; +} + +void cdma_init_jfc_event(struct cdma_jfc_event *event, struct cdma_base_jfc *jfc) +{ + event->async_events_reported = 0; + INIT_LIST_HEAD(&event->async_event_list); + event->jfc = jfc; +} + +void cdma_release_async_event(struct cdma_context *ctx, struct list_head *event_list) +{ + struct cdma_jfe_event *event, *tmp; + struct cdma_jfae *jfae; + struct cdma_jfe *jfe; + + if (!ctx || !ctx->jfae) + return; + + jfae = (struct cdma_jfae *)ctx->jfae; + jfe = &jfae->jfe; + spin_lock_irq(&jfe->lock); + list_for_each_entry_safe(event, tmp, event_list, obj_node) { + list_del(&event->node); + kfree(event); + } + spin_unlock_irq(&jfe->lock); + fput(jfae->file); +} + +void cdma_put_jfae(struct cdma_context *ctx) +{ + struct cdma_jfae *jfae; + + if (!ctx) + return; + + jfae = (struct cdma_jfae *)ctx->jfae; + if (!jfae) + return; + + if (!jfae->file) + return; + + fput(jfae->file); +} diff --git a/drivers/ub/cdma/cdma_event.h b/drivers/ub/cdma/cdma_event.h new file mode 100644 index 000000000000..9154ed10658a --- /dev/null +++ b/drivers/ub/cdma/cdma_event.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_EVENT_H__ +#define __CDMA_EVENT_H__ + +#include +#include +#include +#include +#include +#include +#include "cdma.h" +#include "cdma_context.h" +#include "cdma_types.h" + +#define MAX_EVENT_LIST_SIZE 65535 + +struct cdma_jfe { + spinlock_t lock; + struct list_head event_list; + wait_queue_head_t poll_wait; + struct fasync_struct *async_queue; + uint32_t event_list_count; +}; + +struct cdma_jfae { + int fd; + struct cdma_context *ctx; + struct cdma_file *cfile; + struct file *file; + struct cdma_jfe jfe; +}; + +struct cdma_jfe_event { + struct list_head node; + u32 event_type; + u64 event_data; + struct list_head obj_node; + u32 *counter; +}; + +void cdma_jfs_async_event_cb(struct cdma_event *event, struct cdma_context *ctx); + +void cdma_jfc_async_event_cb(struct cdma_event *event, struct cdma_context *ctx); + +struct cdma_jfae *cdma_alloc_jfae(struct cdma_file *cfile); + +void cdma_free_jfae(struct cdma_jfae *jfae); + +int cdma_get_jfae(struct cdma_context *ctx); + +void cdma_init_jfc_event(struct cdma_jfc_event *event, struct cdma_base_jfc *jfc); + +void cdma_release_async_event(struct cdma_context *ctx, struct list_head *event_list); + +void cdma_put_jfae(struct cdma_context *ctx); +#endif /* CDMA_EVENT_H */ diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c index 5f63cad58088..98286749ceb2 100644 --- a/drivers/ub/cdma/cdma_ioctl.c +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -12,6 +12,7 @@ #include "cdma_tp.h" #include "cdma_jfs.h" #include "cdma_queue.h" +#include "cdma_event.h" #include "cdma_jfc.h" #include "cdma_uobj.h" #include "cdma_ioctl.h" @@ -65,6 +66,7 @@ static int cdma_create_ucontext(struct cdma_ioctl_hdr *hdr, struct cdma_create_context_args args = { 0 }; struct cdma_dev *cdev = cfile->cdev; struct cdma_context *ctx; + struct cdma_jfae *jfae; int ret; if (cfile->uctx) { @@ -87,22 +89,34 @@ static int cdma_create_ucontext(struct cdma_ioctl_hdr *hdr, if (IS_ERR(ctx)) return PTR_ERR(ctx); + ctx->jfae = cdma_alloc_jfae(cfile); + if (!ctx->jfae) { + dev_err(cdev->dev, "create jfae failed.\n"); + ret = -EFAULT; + goto free_context; + } + + jfae = (struct cdma_jfae *)ctx->jfae; + jfae->ctx = ctx; args.out.cqe_size = cdev->caps.cqe_size; args.out.dwqe_enable = !!(cdev->caps.feature & CDMA_CAP_FEATURE_DIRECT_WQE); + args.out.async_fd = jfae->fd; cfile->uctx = ctx; ret = (int)copy_to_user((void *)hdr->args_addr, &args, (u32)sizeof(args)); if (ret) { dev_err(cdev->dev, "copy ctx to user failed, ret = %d.\n", ret); - goto free_context; + goto free_jfae; } return ret; -free_context: +free_jfae: cfile->uctx = NULL; + cdma_free_jfae((struct cdma_jfae *)ctx->jfae); +free_context: cdma_free_context(cdev, ctx); return ret; @@ -270,6 +284,7 @@ static int cdma_cmd_create_jfs(struct cdma_ioctl_hdr *hdr, { struct cdma_cmd_create_jfs_args arg = { 0 }; struct cdma_dev *cdev = cfile->cdev; + struct cdma_jfs_event *jfs_event; struct cdma_jfs_cfg cfg = { 0 }; struct cdma_udata udata = { 0 }; struct cdma_base_jfs *jfs; @@ -316,6 +331,9 @@ static int cdma_cmd_create_jfs(struct cdma_ioctl_hdr *hdr, } uobj->object = jfs; + jfs_event = &jfs->jfs_event; + jfs_event->async_events_reported = 0; + INIT_LIST_HEAD(&jfs_event->async_event_list); arg.out.id = jfs->id; arg.out.handle = uobj->id; @@ -497,6 +515,7 @@ static int cdma_cmd_create_jfc(struct cdma_ioctl_hdr *hdr, { struct cdma_cmd_create_jfc_args arg = { 0 }; struct cdma_dev *cdev = cfile->cdev; + struct cdma_jfc_event *jfc_event; struct cdma_jfc_cfg cfg = { 0 }; struct cdma_udata udata = { 0 }; struct cdma_base_jfc *jfc; @@ -541,7 +560,9 @@ static int cdma_cmd_create_jfc(struct cdma_ioctl_hdr *hdr, goto err_create_jfc; } + jfc_event = &jfc->jfc_event; uobj->object = jfc; + cdma_init_jfc_event(jfc_event, jfc); arg.out.id = jfc->id; arg.out.depth = jfc->jfc_cfg.depth; diff --git a/drivers/ub/cdma/cdma_jfc.c b/drivers/ub/cdma/cdma_jfc.c index 4609fd22382a..80becf8753d9 100644 --- a/drivers/ub/cdma/cdma_jfc.c +++ b/drivers/ub/cdma/cdma_jfc.c @@ -8,6 +8,7 @@ #include "cdma_context.h" #include "cdma_mbox.h" #include "cdma_common.h" +#include "cdma_event.h" #include "cdma_db.h" #include "cdma_jfc.h" @@ -271,6 +272,12 @@ static int cdma_destroy_and_flush_jfc(struct cdma_dev *cdev, u32 jfcn) return -ETIMEDOUT; } +static void cdma_release_jfc_event(struct cdma_jfc *jfc) +{ + cdma_release_async_event(jfc->base.ctx, + &jfc->base.jfc_event.async_event_list); +} + static int cdma_post_create_jfc_mbox(struct cdma_dev *cdev, struct cdma_jfc *jfc) { struct ubase_mbx_attr attr = { 0 }; @@ -323,10 +330,19 @@ struct cdma_base_jfc *cdma_create_jfc(struct cdma_dev *cdev, if (ret) goto err_get_jfc_buf; + if (udata) { + ret = cdma_get_jfae(jfc->base.ctx); + if (ret) + goto err_get_jfae; + } + ret = cdma_post_create_jfc_mbox(cdev, jfc); if (ret) goto err_alloc_cqc; + refcount_set(&jfc->event_refcount, 1); + init_completion(&jfc->event_comp); + jfc->base.jfae_handler = cdma_jfc_async_event_cb; jfc->base.dev = cdev; dev_dbg(cdev->dev, "create jfc id = %u, queue id = %u.\n", @@ -335,6 +351,9 @@ struct cdma_base_jfc *cdma_create_jfc(struct cdma_dev *cdev, return &jfc->base; err_alloc_cqc: + if (udata) + cdma_put_jfae(jfc->base.ctx); +err_get_jfae: cdma_free_jfc_buf(cdev, jfc); err_get_jfc_buf: cdma_jfc_id_free(cdev, jfc->jfcn); @@ -348,6 +367,7 @@ struct cdma_base_jfc *cdma_create_jfc(struct cdma_dev *cdev, int cdma_delete_jfc(struct cdma_dev *cdev, u32 jfcn, struct cdma_cmd_delete_jfc_args *arg) { + struct cdma_jfc_event *jfc_event; struct cdma_jfc *jfc; int ret; @@ -373,11 +393,20 @@ int cdma_delete_jfc(struct cdma_dev *cdev, u32 jfcn, if (ret) dev_err(cdev->dev, "jfc delete failed, jfcn = %u.\n", jfcn); + if (refcount_dec_and_test(&jfc->event_refcount)) + complete(&jfc->event_comp); + wait_for_completion(&jfc->event_comp); + cdma_free_jfc_buf(cdev, jfc); cdma_jfc_id_free(cdev, jfc->jfcn); + if (arg) { + jfc_event = &jfc->base.jfc_event; + arg->out.async_events_reported = jfc_event->async_events_reported; + } pr_debug("Leave %s, jfcn: %u.\n", __func__, jfc->jfcn); + cdma_release_jfc_event(jfc); kfree(jfc); return 0; diff --git a/drivers/ub/cdma/cdma_jfs.c b/drivers/ub/cdma/cdma_jfs.c index 599068837a4b..abc05c44432b 100644 --- a/drivers/ub/cdma/cdma_jfs.c +++ b/drivers/ub/cdma/cdma_jfs.c @@ -12,6 +12,7 @@ #include "cdma_cmd.h" #include "cdma_common.h" #include "cdma_mbox.h" +#include "cdma_event.h" #include "cdma_context.h" #include "cdma_jfs.h" @@ -296,13 +297,21 @@ struct cdma_base_jfs *cdma_create_jfs(struct cdma_dev *cdev, if (ret) goto err_get_jfs_buf; + if (udata) { + ret = cdma_get_jfae(jfs->base_jfs.ctx); + if (ret) + goto err_get_jfae; + } + ret = cdma_create_hw_jfs_ctx(cdev, jfs, cfg); if (ret) goto err_create_hw_jfsc; cdma_set_query_flush_time(&jfs->sq, cfg->err_timeout); - + refcount_set(&jfs->ae_ref_cnt, 1); + init_completion(&jfs->ae_comp); jfs->sq.state = CDMA_JETTY_READY; + jfs->base_jfs.jfae_handler = cdma_jfs_async_event_cb; jfs->base_jfs.dev = cdev; dev_dbg(cdev->dev, @@ -312,6 +321,9 @@ struct cdma_base_jfs *cdma_create_jfs(struct cdma_dev *cdev, return &jfs->base_jfs; err_create_hw_jfsc: + if (udata) + cdma_put_jfae(jfs->base_jfs.ctx); +err_get_jfae: cdma_free_sq_buf(cdev, &jfs->sq); err_get_jfs_buf: cdma_free_jfs_id(cdev, jfs->sq.id); @@ -499,6 +511,12 @@ static int cdma_modify_and_destroy_jfs(struct cdma_dev *cdev, return ret; } +static inline void cdma_release_jfs_event(struct cdma_jfs *jfs) +{ + cdma_release_async_event(jfs->base_jfs.ctx, + &jfs->base_jfs.jfs_event.async_event_list); +} + int cdma_delete_jfs(struct cdma_dev *cdev, u32 jfs_id) { struct cdma_jfs *jfs; @@ -524,12 +542,18 @@ int cdma_delete_jfs(struct cdma_dev *cdev, u32 jfs_id) if (ret) dev_err(cdev->dev, "jfs delete failed, id = %u.\n", jfs->id); + if (refcount_dec_and_test(&jfs->ae_ref_cnt)) + complete(&jfs->ae_comp); + wait_for_completion(&jfs->ae_comp); + cdma_free_sq_buf(cdev, &jfs->sq); cdma_free_jfs_id(cdev, jfs_id); pr_debug("Leave %s, jfsn: %u.\n", __func__, jfs_id); + cdma_release_jfs_event(jfs); + kfree(jfs); return 0; diff --git a/drivers/ub/cdma/cdma_main.c b/drivers/ub/cdma/cdma_main.c index 8519d972c48f..62c475e31a1c 100644 --- a/drivers/ub/cdma/cdma_main.c +++ b/drivers/ub/cdma/cdma_main.c @@ -10,6 +10,7 @@ #include "cdma_dev.h" #include "cdma_chardev.h" #include +#include "cdma_eq.h" #include "cdma_cmd.h" /* Enabling jfc_arm_mode will cause jfc to report cqe; otherwise, it will not. */ @@ -24,10 +25,30 @@ MODULE_PARM_DESC(cqe_mode, "Set cqe reporting mode, default: 1 (0:BY_COUNT, 1:BY struct class *cdma_cdev_class; +static int cdma_register_event(struct auxiliary_device *adev) +{ + int ret; + + ret = cdma_reg_ae_event(adev); + if (ret) + return ret; + + return 0; +} + +static inline void cdma_unregister_event(struct auxiliary_device *adev) +{ + cdma_unreg_ae_event(adev); +} + static int cdma_init_dev_info(struct auxiliary_device *auxdev, struct cdma_dev *cdev) { int ret; + ret = cdma_register_event(auxdev); + if (ret) + return ret; + /* query eu failure does not affect driver loading, as eu can be updated. */ ret = cdma_ctrlq_query_eu(cdev); if (ret) @@ -77,6 +98,7 @@ static void cdma_uninit_dev(struct auxiliary_device *auxdev) return; } + cdma_unregister_event(auxdev); cdma_destroy_chardev(cdev); cdma_destroy_dev(cdev); } diff --git a/drivers/ub/cdma/cdma_types.h b/drivers/ub/cdma/cdma_types.h index 689db795d0c9..c7af05e282f2 100644 --- a/drivers/ub/cdma/cdma_types.h +++ b/drivers/ub/cdma/cdma_types.h @@ -7,8 +7,12 @@ #include #include #include +#include "cdma.h" -struct cdma_dev; +enum cdma_event_type { + CDMA_EVENT_JFC_ERR, + CDMA_EVENT_JFS_ERR, +}; struct cdma_ucontext { struct cdma_dev *dev; @@ -71,13 +75,28 @@ struct cdma_udata { struct cdma_udrv_priv *udrv_data; }; +struct cdma_event { + struct cdma_dev *dev; + union { + struct cdma_base_jfc *jfc; + struct cdma_base_jfs *jfs; + u32 eid_idx; + } element; + enum cdma_event_type event_type; +}; + +typedef void (*cdma_event_callback_t)(struct cdma_event *event, + struct cdma_context *ctx); + struct cdma_base_jfs { struct cdma_dev *dev; struct cdma_context *ctx; struct cdma_jfs_cfg cfg; + cdma_event_callback_t jfae_handler; u64 usr_jfs; u32 id; atomic_t use_cnt; + struct cdma_jfs_event jfs_event; }; struct cdma_jfc_cfg { @@ -91,8 +110,10 @@ struct cdma_base_jfc { struct cdma_context *ctx; struct cdma_jfc_cfg jfc_cfg; u32 id; + cdma_event_callback_t jfae_handler; struct hlist_node hnode; atomic_t use_cnt; + struct cdma_jfc_event jfc_event; }; struct cdma_file { diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h index 59367df04865..0af30a39534e 100644 --- a/include/uapi/ub/cdma/cdma_abi.h +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -10,6 +10,13 @@ #define CDMA_IOC_MAGIC 'C' #define CDMA_SYNC _IOWR(CDMA_IOC_MAGIC, 0, struct cdma_ioctl_hdr) +/* cdma event ioctl cmd */ +#define CDMA_EVENT_CMD_MAGIC 'F' +#define JFAE_CMD_GET_ASYNC_EVENT 0 + +#define CDMA_CMD_GET_ASYNC_EVENT \ + _IOWR(CDMA_EVENT_CMD_MAGIC, JFAE_CMD_GET_ASYNC_EVENT, struct cdma_cmd_async_event) + #define CDMA_DOORBELL_OFFSET 0x80 #define MAP_COMMAND_MASK 0xff @@ -97,6 +104,11 @@ struct cdma_cmd_create_jfs_args { struct cdma_cmd_udrv_priv udata; }; +struct cdma_cmd_async_event { + __u64 event_data; + __u32 event_type; +}; + struct cdma_cmd_delete_jfs_args { struct { __u32 jfs_id; @@ -156,6 +168,9 @@ struct cdma_cmd_delete_jfc_args { __u64 handle; /* handle of jfc */ __u32 queue_id; } in; + struct { + __u32 async_events_reported; + } out; }; struct dev_eid { -- Gitee From 6a0237efa8bb5812b70fb63cddf7771ad6779e50 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 14:32:04 +0800 Subject: [PATCH 019/103] ub: cdma: support reporting completed events commit 3aa7aa335383c20b18a2b0f9fbe3841d83efa77a openEuler This patch implements the handling and reporting of completion events in the CDMA driver. The implementation includes writing the corresponding completion event to the completion event queue of the respective jfc when read/write semantics are completed. Signed-off-by: Zhipeng Lu Signed-off-by: Jingjing Ku Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma.h | 4 + drivers/ub/cdma/cdma_api.c | 36 ++++ drivers/ub/cdma/cdma_dev.c | 4 + drivers/ub/cdma/cdma_eq.c | 29 +++ drivers/ub/cdma/cdma_eq.h | 2 + drivers/ub/cdma/cdma_event.c | 334 ++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_event.h | 21 ++ drivers/ub/cdma/cdma_ioctl.c | 43 +++- drivers/ub/cdma/cdma_jfc.c | 232 ++++++++++++++++++++++ drivers/ub/cdma/cdma_jfc.h | 48 +++++ drivers/ub/cdma/cdma_main.c | 10 + drivers/ub/cdma/cdma_types.h | 5 + include/uapi/ub/cdma/cdma_abi.h | 72 +++++++ include/ub/cdma/cdma_api.h | 32 +++ 14 files changed, 871 insertions(+), 1 deletion(-) diff --git a/drivers/ub/cdma/cdma.h b/drivers/ub/cdma/cdma.h index 995f28def668..78ac66be6526 100644 --- a/drivers/ub/cdma/cdma.h +++ b/drivers/ub/cdma/cdma.h @@ -187,6 +187,7 @@ struct cdma_dev { struct cdma_table ctp_table; struct cdma_table jfs_table; struct cdma_table jfc_table; + struct cdma_table jfce_table; struct ubase_event_nb *ae_event_addr[UBASE_EVENT_TYPE_MAX]; struct mutex file_mutex; struct list_head file_list; @@ -200,7 +201,10 @@ struct cdma_jfs_event { struct cdma_jfc_event { struct cdma_base_jfc *jfc; + struct cdma_jfce *jfce; + struct list_head comp_event_list; struct list_head async_event_list; + u32 comp_events_reported; u32 async_events_reported; }; diff --git a/drivers/ub/cdma/cdma_api.c b/drivers/ub/cdma/cdma_api.c index 34a2d96f7c3c..8043b0238cb4 100644 --- a/drivers/ub/cdma/cdma_api.c +++ b/drivers/ub/cdma/cdma_api.c @@ -8,6 +8,7 @@ #include "cdma_cmd.h" #include "cdma_context.h" #include "cdma_queue.h" +#include "cdma_jfc.h" #include "cdma.h" #include @@ -308,3 +309,38 @@ void dma_free_queue(struct dma_device *dma_dev, int queue_id) atomic_dec(&ctx->ref_cnt); } EXPORT_SYMBOL_GPL(dma_free_queue); + +int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, + struct dma_cr *cr) +{ + struct cdma_queue *cdma_queue; + struct cdma_dev *cdev; + u32 eid; + + if (!dma_dev || !cr_cnt || !cr) { + pr_err("the poll queue input parameter is invalid.\n"); + return -EINVAL; + } + + eid = dma_dev->attr.eid.dw0; + cdev = get_cdma_dev_by_eid(eid); + if (!cdev) { + pr_err("get cdma dev failed, eid = 0x%x.\n", eid); + return -EINVAL; + } + + if (cdev->status == CDMA_SUSPEND) { + pr_warn("cdma device is not prepared, eid = 0x%x.\n", eid); + return -EINVAL; + } + + cdma_queue = cdma_find_queue(cdev, queue_id); + if (!cdma_queue || !cdma_queue->jfc) { + dev_err(cdev->dev, "get cdma queue failed, queue_id = %d.\n", + queue_id); + return -EINVAL; + } + + return cdma_poll_jfc(cdma_queue->jfc, cr_cnt, cr); +} +EXPORT_SYMBOL_GPL(dma_poll_queue); diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index 75c87176e868..96f33a55ebdf 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -105,11 +105,14 @@ static void cdma_tbl_destroy(struct cdma_dev *cdev, struct cdma_table *table, static void cdma_init_tables(struct cdma_dev *cdev) { struct cdma_res *queue = &cdev->caps.queue; + struct cdma_res *jfce = &cdev->caps.jfce; struct cdma_res *jfs = &cdev->caps.jfs; struct cdma_res *jfc = &cdev->caps.jfc; cdma_tbl_init(&cdev->queue_table, queue->start_idx + queue->max_cnt - 1, queue->start_idx); + cdma_tbl_init(&cdev->jfce_table, jfce->start_idx + jfce->max_cnt - 1, + jfce->start_idx); cdma_tbl_init(&cdev->jfc_table, jfc->start_idx + jfc->max_cnt - 1, jfc->start_idx); cdma_tbl_init(&cdev->jfs_table, jfs->max_cnt + jfs->start_idx - 1, @@ -122,6 +125,7 @@ static void cdma_destroy_tables(struct cdma_dev *cdev) cdma_tbl_destroy(cdev, &cdev->ctp_table, "CTP"); cdma_tbl_destroy(cdev, &cdev->jfs_table, "JFS"); cdma_tbl_destroy(cdev, &cdev->jfc_table, "JFC"); + cdma_tbl_destroy(cdev, &cdev->jfce_table, "JFCE"); cdma_tbl_destroy(cdev, &cdev->queue_table, "QUEUE"); } diff --git a/drivers/ub/cdma/cdma_eq.c b/drivers/ub/cdma/cdma_eq.c index 51c84ebaf7b6..6bc6048e3127 100644 --- a/drivers/ub/cdma/cdma_eq.c +++ b/drivers/ub/cdma/cdma_eq.c @@ -192,3 +192,32 @@ void cdma_unreg_ae_event(struct auxiliary_device *adev) } } } + +/* thanks to drivers/infiniband/hw/erdma/erdma_eq.c */ +int cdma_reg_ce_event(struct auxiliary_device *adev) +{ + struct cdma_dev *cdma_dev; + int ret; + + if (!adev) + return -EINVAL; + + cdma_dev = get_cdma_dev(adev); + if (!cdma_dev) + return -EINVAL; + + ret = ubase_comp_register(adev, cdma_jfc_completion); + if (ret) + dev_err(cdma_dev->dev, + "register ce event failed, ret = %d.\n", ret); + + return ret; +} + +void cdma_unreg_ce_event(struct auxiliary_device *adev) +{ + if (!adev) + return; + + ubase_comp_unregister(adev); +} diff --git a/drivers/ub/cdma/cdma_eq.h b/drivers/ub/cdma/cdma_eq.h index 51417e3eea50..70e9edcccad4 100644 --- a/drivers/ub/cdma/cdma_eq.h +++ b/drivers/ub/cdma/cdma_eq.h @@ -12,5 +12,7 @@ struct cdma_ae_operation { int cdma_reg_ae_event(struct auxiliary_device *adev); void cdma_unreg_ae_event(struct auxiliary_device *adev); +int cdma_reg_ce_event(struct auxiliary_device *adev); +void cdma_unreg_ce_event(struct auxiliary_device *adev); #endif diff --git a/drivers/ub/cdma/cdma_event.c b/drivers/ub/cdma/cdma_event.c index 5d81363c88ff..f887c52a0479 100644 --- a/drivers/ub/cdma/cdma_event.c +++ b/drivers/ub/cdma/cdma_event.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "cdma_uobj.h" #include "cdma_event.h" @@ -92,6 +93,189 @@ static int cdma_wait_event(struct cdma_jfe *jfe, bool nonblock, return 0; } +static int cdma_wait_event_timeout(struct cdma_jfe *jfe, + unsigned long max_timeout, + u32 max_event_cnt, + u32 *event_cnt, + struct list_head *event_list) +{ + long timeout = (long)max_timeout; + + *event_cnt = 0; + while (1) { + asm volatile("" : : : "memory"); + *event_cnt = cdma_read_jfe_event(jfe, max_event_cnt, event_list); + if (*event_cnt > 0) + break; + timeout = wait_event_interruptible_timeout(jfe->poll_wait, + !list_empty(&jfe->event_list), timeout); + if (timeout <= 0) + return timeout; + } + + return 0; +} + +static int cdma_jfce_wait(struct cdma_jfce *jfce, struct file *filp, + unsigned long arg) +{ + struct cdma_cmd_jfce_wait_args we = { 0 }; + struct cdma_jfe_event *event; + struct list_head event_list; + struct list_head *next; + struct list_head *p; + u32 max_event_cnt; + u32 i = 0; + int ret; + + if (copy_from_user(&we, (const void __user *)arg, + (u32)sizeof(we)) != 0) + return -EFAULT; + + max_event_cnt = min_t(u32, we.in.max_event_cnt, (u32)CDMA_MAX_JFCE_EVENT_CNT); + INIT_LIST_HEAD(&event_list); + if (we.in.time_out <= 0) { + ret = cdma_wait_event(&jfce->jfe, + (filp->f_flags & O_NONBLOCK) | + (!we.in.time_out), + max_event_cnt, + &we.out.event_cnt, &event_list); + } else { + ret = cdma_wait_event_timeout(&jfce->jfe, + msecs_to_jiffies(we.in.time_out), + max_event_cnt, &we.out.event_cnt, + &event_list); + } + + if (ret < 0) { + pr_err("wait jfce event failed, ret = %d\n", ret); + return ret; + } + + list_for_each_safe(p, next, &event_list) { + event = list_entry(p, struct cdma_jfe_event, node); + we.out.event_data[i++] = event->event_data; + list_del(p); + kfree(event); + } + + if (we.out.event_cnt > 0 && copy_to_user((void *)arg, &we, sizeof(we))) { + pr_err("copy to user failed.\n"); + return -EFAULT; + } + + return 0; +} + +static __poll_t cdma_jfce_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct cdma_jfce *jfce = (struct cdma_jfce *)filp->private_data; + + if (!jfce) + return POLLERR; + + return cdma_jfe_poll(&jfce->jfe, filp, wait); +} + +static long cdma_jfce_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct cdma_jfce *jfce = (struct cdma_jfce *)filp->private_data; + unsigned int nr; + int ret; + + if (!arg || !jfce || _IOC_TYPE(cmd) != CDMA_EVENT_CMD_MAGIC) { + pr_err("invalid parameter, cmd = %u.\n", cmd); + return -EINVAL; + } + + nr = (unsigned int)_IOC_NR(cmd); + switch (nr) { + case JFCE_CMD_WAIT_EVENT: + ret = cdma_jfce_wait(jfce, filp, arg); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} + +static int cdma_delete_jfce(struct inode *inode, struct file *filp) +{ + struct cdma_file *cfile; + struct cdma_jfce *jfce; + + if (!filp || !filp->private_data) + return 0; + + jfce = (struct cdma_jfce *)filp->private_data; + + cfile = jfce->cfile; + if (!cfile) + return 0; + + if (!mutex_trylock(&cfile->ctx_mutex)) + return -ENOLCK; + cdma_destroy_jfce(jfce); + filp->private_data = NULL; + mutex_unlock(&cfile->ctx_mutex); + cdma_close_uobj_fd(cfile); + + pr_info("jfce is release.\n"); + return 0; +} + +static int cdma_jfce_fasync(int fd, struct file *filp, int on) +{ + struct cdma_jfce *jfce = (struct cdma_jfce *)filp->private_data; + int ret; + + if (!jfce) + return -EINVAL; + + spin_lock_irq(&jfce->jfe.lock); + ret = fasync_helper(fd, filp, on, &jfce->jfe.async_queue); + spin_unlock_irq(&jfce->jfe.lock); + + return ret; +} + +const struct file_operations cdma_jfce_fops = { + .owner = THIS_MODULE, + .poll = cdma_jfce_poll, + .unlocked_ioctl = cdma_jfce_ioctl, + .release = cdma_delete_jfce, + .fasync = cdma_jfce_fasync, +}; + +static int cdma_jfce_id_alloc(struct cdma_dev *cdev, struct cdma_jfce *jfce) +{ + struct cdma_table *jfce_tbl = &cdev->jfce_table; + int id; + + idr_preload(GFP_KERNEL); + spin_lock(&jfce_tbl->lock); + id = idr_alloc(&jfce_tbl->idr_tbl.idr, jfce, jfce_tbl->idr_tbl.min, + jfce_tbl->idr_tbl.max, GFP_NOWAIT); + if (id < 0) + dev_err(cdev->dev, "alloc jfce id failed.\n"); + spin_unlock(&jfce_tbl->lock); + idr_preload_end(); + + return id; +} + +static void cdma_jfce_id_free(struct cdma_dev *cdev, u32 jfce_id) +{ + struct cdma_table *jfce_tbl = &cdev->jfce_table; + + spin_lock(&jfce_tbl->lock); + idr_remove(&jfce_tbl->idr_tbl.idr, jfce_id); + spin_unlock(&jfce_tbl->lock); +} + static void cdma_write_event(struct cdma_jfe *jfe, u64 event_data, u32 event_type, struct list_head *obj_event_list, u32 *counter) @@ -142,6 +326,136 @@ static void cdma_uninit_jfe(struct cdma_jfe *jfe) spin_unlock_irq(&jfe->lock); } +struct cdma_jfce *cdma_get_jfce_from_id(struct cdma_dev *cdev, int jfce_id) +{ + struct cdma_table *jfce_table = &cdev->jfce_table; + struct cdma_jfce *jfce; + struct file *file; + + spin_lock(&jfce_table->lock); + jfce = idr_find(&jfce_table->idr_tbl.idr, jfce_id); + if (!jfce) { + dev_err(cdev->dev, "find jfce failed, id = %d.\n", jfce_id); + } else { + file = fget(jfce->fd); + if (!file) { + jfce = NULL; + } else { + if (file->private_data != jfce) { + fput(file); + jfce = NULL; + } + } + } + spin_unlock(&jfce_table->lock); + + return jfce; +} + +void cdma_jfc_comp_event_cb(struct cdma_base_jfc *jfc) +{ + struct cdma_jfc_event *jfc_event; + struct cdma_jfce *jfce; + + if (!jfc) + return; + + jfc_event = &jfc->jfc_event; + if (!IS_ERR_OR_NULL(jfc_event->jfce)) { + jfce = jfc_event->jfce; + if (jfce->jfe.event_list_count >= MAX_EVENT_LIST_SIZE) + return; + + cdma_write_event(&jfce->jfe, jfc->jfc_cfg.queue_id, 0, + &jfc_event->comp_event_list, + &jfc_event->comp_events_reported); + } +} + +struct cdma_jfce *cdma_alloc_jfce(struct cdma_file *cfile) +{ + struct cdma_jfce *jfce; + struct file *file; + int new_fd; + int ret; + + if (!cfile) + return ERR_PTR(-EINVAL); + + new_fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC); + if (new_fd < 0) + return ERR_PTR(new_fd); + + jfce = kzalloc(sizeof(*jfce), GFP_KERNEL); + if (!jfce) { + ret = -ENOMEM; + goto err_put_unused_fd; + } + + ret = cdma_jfce_id_alloc(cfile->cdev, jfce); + if (ret < 0) + goto err_free_jfce; + jfce->id = ret; + + file = anon_inode_getfile("[jfce]", &cdma_jfce_fops, jfce, + O_RDWR | O_CLOEXEC); + if (IS_ERR(file)) { + ret = PTR_ERR(file); + goto err_free_id; + } + + cdma_init_jfe(&jfce->jfe); + jfce->cdev = cfile->cdev; + jfce->fd = new_fd; + jfce->file = file; + jfce->cfile = cfile; + fd_install(new_fd, file); + + return jfce; + +err_free_id: + cdma_jfce_id_free(cfile->cdev, jfce->id); +err_free_jfce: + kfree(jfce); +err_put_unused_fd: + put_unused_fd(new_fd); + + return ERR_PTR(ret); +} + +void cdma_free_jfce(struct cdma_jfce *jfce) +{ + struct cdma_dev *cdev; + + if (!jfce || !jfce->cdev) + return; + + cdev = jfce->cdev; + + if (jfce->id >= cdev->caps.jfce.max_cnt + cdev->caps.jfce.start_idx || + jfce->id < cdev->caps.jfce.start_idx) { + dev_err(cdev->dev, + "jfce id invalid, id = %u, start_idx = %u, max_cnt = %u.\n", + jfce->id, cdev->caps.jfce.start_idx, + cdev->caps.jfce.max_cnt); + return; + } + + fput(jfce->file); + put_unused_fd(jfce->fd); +} + +void cdma_destroy_jfce(struct cdma_jfce *jfce) +{ + if (!jfce) + return; + + cdma_uninit_jfe(&jfce->jfe); + if (jfce->cfile && jfce->cfile->cdev) + cdma_jfce_id_free(jfce->cdev, jfce->id); + kfree(jfce); +} + static void cdma_write_async_event(struct cdma_context *ctx, u64 event_data, u32 type, struct list_head *obj_event_list, u32 *counter) @@ -388,11 +702,31 @@ int cdma_get_jfae(struct cdma_context *ctx) void cdma_init_jfc_event(struct cdma_jfc_event *event, struct cdma_base_jfc *jfc) { + event->comp_events_reported = 0; event->async_events_reported = 0; + INIT_LIST_HEAD(&event->comp_event_list); INIT_LIST_HEAD(&event->async_event_list); event->jfc = jfc; } +void cdma_release_comp_event(struct cdma_jfce *jfce, struct list_head *event_list) +{ + struct cdma_jfe_event *event, *tmp; + struct cdma_jfe *jfe; + + if (!jfce) + return; + + jfe = &jfce->jfe; + spin_lock_irq(&jfe->lock); + list_for_each_entry_safe(event, tmp, event_list, obj_node) { + list_del(&event->node); + kfree(event); + } + spin_unlock_irq(&jfe->lock); + fput(jfce->file); +} + void cdma_release_async_event(struct cdma_context *ctx, struct list_head *event_list) { struct cdma_jfe_event *event, *tmp; diff --git a/drivers/ub/cdma/cdma_event.h b/drivers/ub/cdma/cdma_event.h index 9154ed10658a..4ca14c3c5fcb 100644 --- a/drivers/ub/cdma/cdma_event.h +++ b/drivers/ub/cdma/cdma_event.h @@ -40,6 +40,19 @@ struct cdma_jfe_event { u32 *counter; }; +struct cdma_jfce { + int id; + int fd; + struct cdma_dev *cdev; + struct cdma_file *cfile; + struct file *file; + struct cdma_jfe jfe; +}; + +struct cdma_jfce *cdma_alloc_jfce(struct cdma_file *cfile); + +void cdma_free_jfce(struct cdma_jfce *jfce); + void cdma_jfs_async_event_cb(struct cdma_event *event, struct cdma_context *ctx); void cdma_jfc_async_event_cb(struct cdma_event *event, struct cdma_context *ctx); @@ -50,8 +63,16 @@ void cdma_free_jfae(struct cdma_jfae *jfae); int cdma_get_jfae(struct cdma_context *ctx); +struct cdma_jfce *cdma_get_jfce_from_id(struct cdma_dev *cdev, int jfce_id); + +void cdma_jfc_comp_event_cb(struct cdma_base_jfc *jfc); + +void cdma_destroy_jfce(struct cdma_jfce *jfce); + void cdma_init_jfc_event(struct cdma_jfc_event *event, struct cdma_base_jfc *jfc); +void cdma_release_comp_event(struct cdma_jfce *jfce, struct list_head *event_list); + void cdma_release_async_event(struct cdma_context *ctx, struct list_head *event_list); void cdma_put_jfae(struct cdma_context *ctx); diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c index 98286749ceb2..f1513c162db2 100644 --- a/drivers/ub/cdma/cdma_ioctl.c +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -567,7 +567,11 @@ static int cdma_cmd_create_jfc(struct cdma_ioctl_hdr *hdr, arg.out.id = jfc->id; arg.out.depth = jfc->jfc_cfg.depth; arg.out.handle = uobj->id; - + jfc_event->jfce = cdma_get_jfce_from_id(cdev, arg.in.jfce_id); + if (!jfc_event->jfce) { + ret = -EFAULT; + goto err_get_jfce; + } ret = (int)copy_to_user((void *)hdr->args_addr, &arg, (u32)sizeof(arg)); if (ret != 0) { dev_err(cdev->dev, "copy jfc to user failed, ret = %d.\n", ret); @@ -579,6 +583,7 @@ static int cdma_cmd_create_jfc(struct cdma_ioctl_hdr *hdr, return 0; err_copy_to_user: +err_get_jfce: cdma_delete_jfc(cdev, jfc->id, NULL); err_create_jfc: cdma_uobj_delete(uobj); @@ -641,6 +646,41 @@ static int cdma_cmd_delete_jfc(struct cdma_ioctl_hdr *hdr, return 0; } +static int cdma_cmd_create_jfce(struct cdma_ioctl_hdr *hdr, + struct cdma_file *cfile) +{ + struct cdma_cmd_create_jfce_args arg = { 0 }; + struct cdma_jfce *jfce; + int ret; + + if (!hdr->args_addr || hdr->args_len != (u32)sizeof(arg)) + return -EINVAL; + + ret = (int)copy_from_user(&arg, (void *)hdr->args_addr, + (u32)sizeof(arg)); + if (ret) + return -EFAULT; + + jfce = cdma_alloc_jfce(cfile); + if (IS_ERR(jfce)) + return PTR_ERR(jfce); + + arg.out.fd = jfce->fd; + arg.out.id = jfce->id; + ret = (int)copy_to_user((void *)hdr->args_addr, &arg, (u32)sizeof(arg)); + if (ret) { + ret = -EFAULT; + goto err_out; + } + + return 0; + +err_out: + cdma_free_jfce(jfce); + + return ret; +} + static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { [CDMA_CMD_QUERY_DEV_INFO] = cdma_query_dev, [CDMA_CMD_CREATE_CTX] = cdma_create_ucontext, @@ -653,6 +693,7 @@ static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { [CDMA_CMD_DELETE_QUEUE] = cdma_cmd_delete_queue, [CDMA_CMD_CREATE_JFC] = cdma_cmd_create_jfc, [CDMA_CMD_DELETE_JFC] = cdma_cmd_delete_jfc, + [CDMA_CMD_CREATE_JFCE] = cdma_cmd_create_jfce, }; int cdma_cmd_parse(struct cdma_file *cfile, struct cdma_ioctl_hdr *hdr) diff --git a/drivers/ub/cdma/cdma_jfc.c b/drivers/ub/cdma/cdma_jfc.c index 80becf8753d9..cd92f90461ff 100644 --- a/drivers/ub/cdma/cdma_jfc.c +++ b/drivers/ub/cdma/cdma_jfc.c @@ -10,6 +10,7 @@ #include "cdma_common.h" #include "cdma_event.h" #include "cdma_db.h" +#include "cdma_jfs.h" #include "cdma_jfc.h" static int cdma_get_cmd_from_user(struct cdma_create_jfc_ucmd *ucmd, @@ -82,6 +83,7 @@ static void cdma_init_jfc_param(struct cdma_jfc_cfg *cfg, struct cdma_jfc *jfc) { jfc->base.id = jfc->jfcn; jfc->base.jfc_cfg = *cfg; + jfc->base.jfc_event.jfce = NULL; jfc->ceqn = cfg->ceqn; } @@ -272,8 +274,171 @@ static int cdma_destroy_and_flush_jfc(struct cdma_dev *cdev, u32 jfcn) return -ETIMEDOUT; } +static inline void *cdma_get_buf_entry(struct cdma_buf *buf, u32 n) +{ + uint32_t entry_index = n & buf->entry_cnt_mask; + + return (char *)buf->kva + (entry_index * buf->entry_size); +} + +static struct cdma_jfc_cqe *cdma_get_next_cqe(struct cdma_jfc *jfc, u32 n) +{ + struct cdma_jfc_cqe *cqe; + u32 valid_owner; + + cqe = (struct cdma_jfc_cqe *)cdma_get_buf_entry(&jfc->buf, n); + valid_owner = (jfc->ci >> jfc->buf.entry_cnt_mask_ilog2) & + CDMA_JFC_DB_VALID_OWNER_M; + if (!(cqe->owner ^ valid_owner)) + return NULL; + + return cqe; +} + +static struct cdma_jetty_queue *cdma_update_jetty_idx(struct cdma_jfc_cqe *cqe) +{ + struct cdma_jetty_queue *queue; + u32 entry_idx; + + entry_idx = cqe->entry_idx; + queue = (struct cdma_jetty_queue *)((u64)cqe->user_data_h << + CDMA_ADDR_SHIFT | cqe->user_data_l); + if (!queue) + return NULL; + + if (!!cqe->fd) + return queue; + + queue->ci += (entry_idx - queue->ci) & (queue->buf.entry_cnt - 1); + + return queue; +} + +static enum jfc_poll_state cdma_get_cr_status(u8 src_status, + u8 substatus, + enum dma_cr_status *dst_status) +{ +struct cdma_cqe_status { + bool is_valid; + enum dma_cr_status cr_status; +}; + + static struct cdma_cqe_status map[CDMA_CQE_STATUS_NUM][CDMA_CQE_SUB_STATUS_NUM] = { + {{true, DMA_CR_SUCCESS}, {false, DMA_CR_SUCCESS}, {false, DMA_CR_SUCCESS}, + {false, DMA_CR_SUCCESS}, {false, DMA_CR_SUCCESS}}, + {{true, DMA_CR_UNSUPPORTED_OPCODE_ERR}, {false, DMA_CR_SUCCESS}, + {false, DMA_CR_SUCCESS}, {false, DMA_CR_SUCCESS}, + {false, DMA_CR_SUCCESS}}, + {{false, DMA_CR_SUCCESS}, {true, DMA_CR_LOC_LEN_ERR}, + {true, DMA_CR_LOC_ACCESS_ERR}, {true, DMA_CR_REM_RESP_LEN_ERR}, + {true, DMA_CR_LOC_DATA_POISON}}, + {{false, DMA_CR_SUCCESS}, {true, DMA_CR_REM_UNSUPPORTED_REQ_ERR}, + {true, DMA_CR_REM_ACCESS_ABORT_ERR}, {false, DMA_CR_SUCCESS}, + {true, DMA_CR_REM_DATA_POISON}}, + {{true, DMA_CR_RNR_RETRY_CNT_EXC_ERR}, {false, DMA_CR_SUCCESS}, + {false, DMA_CR_SUCCESS}, {false, DMA_CR_SUCCESS}, + {false, DMA_CR_SUCCESS}}, + {{true, DMA_CR_ACK_TIMEOUT_ERR}, {false, DMA_CR_SUCCESS}, + {false, DMA_CR_SUCCESS}, {false, DMA_CR_SUCCESS}, + {false, DMA_CR_SUCCESS}}, + {{true, DMA_CR_WR_FLUSH_ERR}, {false, DMA_CR_SUCCESS}, + {false, DMA_CR_SUCCESS}, {false, DMA_CR_SUCCESS}, + {false, DMA_CR_SUCCESS}} + }; + + if ((src_status < CDMA_CQE_STATUS_NUM) && (substatus < CDMA_CQE_SUB_STATUS_NUM) && + map[src_status][substatus].is_valid) { + *dst_status = map[src_status][substatus].cr_status; + return JFC_OK; + } + + return JFC_POLL_ERR; +} + +static enum jfc_poll_state cdma_update_flush_cr(struct cdma_jetty_queue *queue, + struct cdma_jfc_cqe *cqe, + struct dma_cr *cr) +{ + if (cdma_get_cr_status(cqe->status, cqe->substatus, &cr->status)) + return JFC_POLL_ERR; + + if (cqe->fd) { + cr->status = DMA_CR_WR_FLUSH_ERR_DONE; + queue->flush_flag = true; + } else { + queue->ci++; + } + + return JFC_OK; +} + +static enum jfc_poll_state cdma_parse_cqe_for_jfc(struct cdma_dev *cdev, + struct cdma_jfc_cqe *cqe, + struct dma_cr *cr) +{ + struct cdma_jetty_queue *queue; + struct cdma_jfs *jfs; + + queue = cdma_update_jetty_idx(cqe); + if (!queue) { + dev_err(cdev->dev, "update jetty idx failed.\n"); + return JFC_POLL_ERR; + } + + jfs = container_of(queue, struct cdma_jfs, sq); + cr->flag.bs.s_r = cqe->s_r; + cr->flag.bs.jetty = cqe->is_jetty; + cr->completion_len = cqe->byte_cnt; + cr->tpn = cqe->tpn; + cr->local_id = cqe->local_num_h << CDMA_SRC_IDX_SHIFT | cqe->local_num_l; + cr->remote_id = cqe->rmt_idx; + + if (cqe->status) + dev_warn(cdev->dev, "get sq %u cqe status abnormal, ci = %u, pi = %u.\n", + queue->id, queue->ci, queue->pi); + + if (cdma_update_flush_cr(queue, cqe, cr)) { + dev_err(cdev->dev, + "update cr failed, status = %u, substatus = %u.\n", + cqe->status, cqe->substatus); + return JFC_POLL_ERR; + } + + return JFC_OK; +} + +static enum jfc_poll_state cdma_poll_one(struct cdma_dev *cdev, + struct cdma_jfc *jfc, + struct dma_cr *cr) +{ + enum dma_cr_status status; + struct cdma_jfc_cqe *cqe; + + cqe = cdma_get_next_cqe(jfc, jfc->ci); + if (!cqe) + return JFC_EMPTY; + + ++jfc->ci; + /* Ensure that the reading of the event is completed before parsing. */ + rmb(); + + if (cdma_parse_cqe_for_jfc(cdev, cqe, cr)) + return JFC_POLL_ERR; + + status = cr->status; + if (status == DMA_CR_WR_FLUSH_ERR_DONE || status == DMA_CR_WR_SUSPEND_DONE) { + dev_info(cdev->dev, "poll cr flush/suspend done, jfc id = %u, status = %u.\n", + jfc->jfcn, status); + return JFC_EMPTY; + } + + return JFC_OK; +} + static void cdma_release_jfc_event(struct cdma_jfc *jfc) { + cdma_release_comp_event(jfc->base.jfc_event.jfce, + &jfc->base.jfc_event.comp_event_list); cdma_release_async_event(jfc->base.ctx, &jfc->base.jfc_event.async_event_list); } @@ -343,6 +508,7 @@ struct cdma_base_jfc *cdma_create_jfc(struct cdma_dev *cdev, refcount_set(&jfc->event_refcount, 1); init_completion(&jfc->event_comp); jfc->base.jfae_handler = cdma_jfc_async_event_cb; + jfc->base.jfce_handler = cdma_jfc_comp_event_cb; jfc->base.dev = cdev; dev_dbg(cdev->dev, "create jfc id = %u, queue id = %u.\n", @@ -401,6 +567,7 @@ int cdma_delete_jfc(struct cdma_dev *cdev, u32 jfcn, cdma_jfc_id_free(cdev, jfc->jfcn); if (arg) { jfc_event = &jfc->base.jfc_event; + arg->out.comp_events_reported = jfc_event->comp_events_reported; arg->out.async_events_reported = jfc_event->async_events_reported; } @@ -411,3 +578,68 @@ int cdma_delete_jfc(struct cdma_dev *cdev, u32 jfcn, return 0; } + +int cdma_jfc_completion(struct notifier_block *nb, unsigned long jfcn, + void *data) +{ + struct auxiliary_device *adev = (struct auxiliary_device *)data; + struct cdma_base_jfc *base_jfc; + struct cdma_table *jfc_tbl; + struct cdma_dev *cdev; + struct cdma_jfc *jfc; + unsigned long flags; + + if (!adev) + return -EINVAL; + + cdev = get_cdma_dev(adev); + jfc_tbl = &cdev->jfc_table; + spin_lock_irqsave(&jfc_tbl->lock, flags); + jfc = idr_find(&jfc_tbl->idr_tbl.idr, jfcn); + if (!jfc) { + dev_warn(cdev->dev, "can not find jfc, jfcn = %lu.\n", jfcn); + spin_unlock_irqrestore(&jfc_tbl->lock, flags); + return -EINVAL; + } + + ++jfc->arm_sn; + base_jfc = &jfc->base; + if (base_jfc->jfce_handler) { + refcount_inc(&jfc->event_refcount); + spin_unlock_irqrestore(&jfc_tbl->lock, flags); + base_jfc->jfce_handler(base_jfc); + if (refcount_dec_and_test(&jfc->event_refcount)) + complete(&jfc->event_comp); + } else { + spin_unlock_irqrestore(&jfc_tbl->lock, flags); + } + + return 0; +} + +/* thanks to drivers/infiniband/hw/bnxt_re/ib_verbs.c */ +int cdma_poll_jfc(struct cdma_base_jfc *base_jfc, int cr_cnt, + struct dma_cr *cr) +{ + struct cdma_jfc *jfc = to_cdma_jfc(base_jfc); + enum jfc_poll_state err = JFC_OK; + int npolled = 0; + + jfc->buf.entry_cnt_mask = jfc->buf.entry_cnt - 1; + jfc->buf.entry_cnt_mask_ilog2 = ilog2(jfc->buf.entry_cnt); + + spin_lock(&jfc->lock); + + for (npolled = 0; npolled < cr_cnt; ++npolled) { + err = cdma_poll_one(base_jfc->dev, jfc, cr + npolled); + if (err != JFC_OK) + break; + } + + if (npolled) + *jfc->db.db_record = jfc->ci & (u32)CDMA_JFC_DB_CI_IDX_M; + + spin_unlock(&jfc->lock); + + return err == JFC_POLL_ERR ? -CDMA_INTER_ERR : npolled; +} diff --git a/drivers/ub/cdma/cdma_jfc.h b/drivers/ub/cdma/cdma_jfc.h index 612887837e39..7f512150e50c 100644 --- a/drivers/ub/cdma/cdma_jfc.h +++ b/drivers/ub/cdma/cdma_jfc.h @@ -18,6 +18,8 @@ #define CQE_VA_L_OFFSET 12 #define CQE_VA_H_OFFSET 32 +#define CDMA_IMM_DATA_SHIFT 32 + enum cdma_record_db { CDMA_NO_RECORD_EN, CDMA_RECORD_EN @@ -130,6 +132,46 @@ struct cdma_jfc_ctx { u32 rsv11[12]; }; +struct cdma_jfc_cqe { + /* DW0 */ + u32 s_r : 1; + u32 is_jetty : 1; + u32 owner : 1; + u32 inline_en : 1; + u32 opcode : 3; + u32 fd : 1; + u32 rsv : 8; + u32 substatus : 8; + u32 status : 8; + /* DW1 */ + u32 entry_idx : 16; + u32 local_num_l : 16; + /* DW2 */ + u32 local_num_h : 4; + u32 rmt_idx : 20; + u32 rsv1 : 8; + /* DW3 */ + u32 tpn : 24; + u32 rsv2 : 8; + /* DW4 */ + u32 byte_cnt; + /* DW5 ~ DW6 */ + u32 user_data_l; + u32 user_data_h; + /* DW7 ~ DW10 */ + u32 rmt_eid[4]; + /* DW11 ~ DW12 */ + u32 data_l; + u32 data_h; + /* DW13 ~ DW15 */ + u32 inline_data[3]; +}; + +static inline struct cdma_jfc *to_cdma_jfc(struct cdma_base_jfc *base_jfc) +{ + return container_of(base_jfc, struct cdma_jfc, base); +} + int cdma_post_destroy_jfc_mbox(struct cdma_dev *cdev, u32 jfcn, enum cdma_jfc_state state); @@ -140,4 +182,10 @@ struct cdma_base_jfc *cdma_create_jfc(struct cdma_dev *cdev, int cdma_delete_jfc(struct cdma_dev *cdev, u32 jfcn, struct cdma_cmd_delete_jfc_args *arg); +int cdma_jfc_completion(struct notifier_block *nb, unsigned long jfcn, + void *data); + +int cdma_poll_jfc(struct cdma_base_jfc *base_jfc, int cr_cnt, + struct dma_cr *cr); + #endif /* CDMA_JFC_H */ diff --git a/drivers/ub/cdma/cdma_main.c b/drivers/ub/cdma/cdma_main.c index 62c475e31a1c..82dc5ab40cf8 100644 --- a/drivers/ub/cdma/cdma_main.c +++ b/drivers/ub/cdma/cdma_main.c @@ -33,11 +33,21 @@ static int cdma_register_event(struct auxiliary_device *adev) if (ret) return ret; + ret = cdma_reg_ce_event(adev); + if (ret) + goto err_ce_register; + return 0; + +err_ce_register: + cdma_unreg_ae_event(adev); + + return ret; } static inline void cdma_unregister_event(struct auxiliary_device *adev) { + cdma_unreg_ce_event(adev); cdma_unreg_ae_event(adev); } diff --git a/drivers/ub/cdma/cdma_types.h b/drivers/ub/cdma/cdma_types.h index c7af05e282f2..e4c2f3fd7b52 100644 --- a/drivers/ub/cdma/cdma_types.h +++ b/drivers/ub/cdma/cdma_types.h @@ -105,11 +105,16 @@ struct cdma_jfc_cfg { u32 queue_id; }; +struct cdma_base_jfc; + +typedef void (*cdma_comp_callback_t)(struct cdma_base_jfc *jfc); + struct cdma_base_jfc { struct cdma_dev *dev; struct cdma_context *ctx; struct cdma_jfc_cfg jfc_cfg; u32 id; + cdma_comp_callback_t jfce_handler; cdma_event_callback_t jfae_handler; struct hlist_node hnode; atomic_t use_cnt; diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h index 0af30a39534e..fcee5800193d 100644 --- a/include/uapi/ub/cdma/cdma_abi.h +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -13,12 +13,22 @@ /* cdma event ioctl cmd */ #define CDMA_EVENT_CMD_MAGIC 'F' #define JFAE_CMD_GET_ASYNC_EVENT 0 +#define JFCE_CMD_WAIT_EVENT 0 #define CDMA_CMD_GET_ASYNC_EVENT \ _IOWR(CDMA_EVENT_CMD_MAGIC, JFAE_CMD_GET_ASYNC_EVENT, struct cdma_cmd_async_event) +#define CDMA_CMD_WAIT_JFC \ + _IOWR(CDMA_EVENT_CMD_MAGIC, JFCE_CMD_WAIT_EVENT, struct cdma_cmd_jfce_wait_args) +#define CDMA_ADDR_SHIFT 32 #define CDMA_DOORBELL_OFFSET 0x80 +#define CDMA_JFC_DB_CI_IDX_M GENMASK(21, 0) +#define CDMA_JFC_DB_VALID_OWNER_M 1 +#define CDMA_INTER_ERR 1 +#define CDMA_SRC_IDX_SHIFT 16 +#define CDMA_MAX_JFCE_EVENT_CNT 72 + #define MAP_COMMAND_MASK 0xff #define MAP_INDEX_MASK 0xffffff #define MAP_INDEX_SHIFT 8 @@ -27,6 +37,29 @@ #define CDMA_TYPICAL_RNR_RETRY 7 #define CDMA_TYPICAL_ERR_TIMEOUT 2 /* 0:128ms 1:1s 2:8s 3:64s */ +#define CDMA_CQE_STATUS_NUM 7 +#define CDMA_CQE_SUB_STATUS_NUM 5 + +enum dma_cr_status { + DMA_CR_SUCCESS = 0, + DMA_CR_UNSUPPORTED_OPCODE_ERR, + DMA_CR_LOC_LEN_ERR, + DMA_CR_LOC_OPERATION_ERR, + DMA_CR_LOC_ACCESS_ERR, + DMA_CR_REM_RESP_LEN_ERR, + DMA_CR_REM_UNSUPPORTED_REQ_ERR, + DMA_CR_REM_OPERATION_ERR, + DMA_CR_REM_ACCESS_ABORT_ERR, + DMA_CR_ACK_TIMEOUT_ERR, + DMA_CR_RNR_RETRY_CNT_EXC_ERR, + DMA_CR_WR_FLUSH_ERR, + DMA_CR_WR_SUSPEND_DONE, + DMA_CR_WR_FLUSH_ERR_DONE, + DMA_CR_WR_UNHANDLED, + DMA_CR_LOC_DATA_POISON, + DMA_CR_REM_DATA_POISON, +}; + enum db_mmap_type { CDMA_MMAP_JFC_PAGE, CDMA_MMAP_JETTY_DSQE @@ -44,9 +77,23 @@ enum cdma_cmd { CDMA_CMD_DELETE_QUEUE, CDMA_CMD_CREATE_JFC, CDMA_CMD_DELETE_JFC, + CDMA_CMD_CREATE_JFCE, CDMA_CMD_MAX }; +enum { + CQE_FOR_SEND, + CQE_FOR_RECEIVE +}; + +enum hw_cqe_opcode { + HW_CQE_OPC_SEND = 0x00, + HW_CQE_OPC_SEND_WITH_IMM = 0x01, + HW_CQE_OPC_SEND_WITH_INV = 0x02, + HW_CQE_OPC_WRITE_WITH_IMM = 0x03, + HW_CQE_OPC_ERR = 0xff +}; + struct cdma_ioctl_hdr { __u32 command; __u32 args_len; @@ -146,6 +193,13 @@ struct cdma_cmd_delete_ctp_args { } out; }; +struct cdma_cmd_create_jfce_args { + struct { + int fd; + int id; + } out; +}; + struct cdma_cmd_create_jfc_args { struct { __u32 depth; /* in terms of CQEBB */ @@ -169,6 +223,7 @@ struct cdma_cmd_delete_jfc_args { __u32 queue_id; } in; struct { + __u32 comp_events_reported; __u32 async_events_reported; } out; }; @@ -265,4 +320,21 @@ struct cdma_cmd_delete_queue_args { } in; }; +struct cdma_cmd_jfce_wait_args { + struct { + __u32 max_event_cnt; + int time_out; + } in; + struct { + __u32 event_cnt; + __u64 event_data[CDMA_MAX_JFCE_EVENT_CNT]; + } out; +}; + +enum jfc_poll_state { + JFC_OK, + JFC_EMPTY, + JFC_POLL_ERR, +}; + #endif diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index 5ebe4feebd1c..3ef1eedee111 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -13,6 +13,35 @@ struct dma_device { void *private_data; }; +enum dma_cr_opcode { + DMA_CR_OPC_SEND = 0x00, + DMA_CR_OPC_SEND_WITH_IMM, + DMA_CR_OPC_SEND_WITH_INV, + DMA_CR_OPC_WRITE_WITH_IMM, +}; + +union dma_cr_flag { + struct { + u8 s_r : 1; + u8 jetty : 1; + u8 suspend_done : 1; + u8 flush_err_done : 1; + u8 reserved : 4; + } bs; + u8 value; +}; + +struct dma_cr { + enum dma_cr_status status; + u64 user_ctx; + enum dma_cr_opcode opcode; + union dma_cr_flag flag; + u32 completion_len; + u32 local_id; + u32 remote_id; + u32 tpn; +}; + struct queue_cfg { u32 queue_depth; u8 priority; @@ -42,4 +71,7 @@ int dma_alloc_queue(struct dma_device *dma_dev, int ctx_id, void dma_free_queue(struct dma_device *dma_dev, int queue_id); +int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, + struct dma_cr *cr); + #endif -- Gitee From 79593865683d16f894bcb882da1b5f1ef5d07bd1 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 15:36:17 +0800 Subject: [PATCH 020/103] ub: cdma: support unregister segment commit 62072a52120125e0cf45f531ebacdad6e8b3d6f0 openEuler This patch implements local segment unregister and remote segment import/unimport functionalities within the CDMA driver. The implementation includes support for the interfaces dma_unregister_seg, dma_import_seg, and dma_unimport_seg. Signed-off-by: Zhipeng Lu Signed-off-by: Jinjie Cui Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/Makefile | 2 +- drivers/ub/cdma/cdma.h | 1 + drivers/ub/cdma/cdma_api.c | 55 +++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_context.h | 2 ++ drivers/ub/cdma/cdma_dev.c | 5 +++ drivers/ub/cdma/cdma_ioctl.c | 41 +++++++++++++++++++++++- drivers/ub/cdma/cdma_jfs.h | 1 + drivers/ub/cdma/cdma_segment.c | 51 ++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_segment.h | 26 ++++++++++++++++ include/uapi/ub/cdma/cdma_abi.h | 7 +++++ include/ub/cdma/cdma_api.h | 22 +++++++++++++ 11 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 drivers/ub/cdma/cdma_segment.c create mode 100644 drivers/ub/cdma/cdma_segment.h diff --git a/drivers/ub/cdma/Makefile b/drivers/ub/cdma/Makefile index 58a355df4c33..714e0542f387 100644 --- a/drivers/ub/cdma/Makefile +++ b/drivers/ub/cdma/Makefile @@ -2,6 +2,6 @@ cdma-$(CONFIG_UB_CDMA) := cdma_main.o cdma_dev.o cdma_chardev.o cdma_cmd.o cdma_tid.o cdma_ioctl.o \ cdma_api.o cdma_context.o cdma_queue.o cdma_uobj.o cdma_jfc.o cdma_common.o \ - cdma_db.o cdma_mbox.o cdma_tp.o cdma_jfs.o cdma_eq.o cdma_event.o + cdma_db.o cdma_mbox.o cdma_tp.o cdma_jfs.o cdma_eq.o cdma_event.o cdma_segment.o obj-m += cdma.o diff --git a/drivers/ub/cdma/cdma.h b/drivers/ub/cdma/cdma.h index 78ac66be6526..8ed8fdb4d6fa 100644 --- a/drivers/ub/cdma/cdma.h +++ b/drivers/ub/cdma/cdma.h @@ -188,6 +188,7 @@ struct cdma_dev { struct cdma_table jfs_table; struct cdma_table jfc_table; struct cdma_table jfce_table; + struct cdma_table seg_table; struct ubase_event_nb *ae_event_addr[UBASE_EVENT_TYPE_MAX]; struct mutex file_mutex; struct list_head file_list; diff --git a/drivers/ub/cdma/cdma_api.c b/drivers/ub/cdma/cdma_api.c index 8043b0238cb4..4ba886635ca0 100644 --- a/drivers/ub/cdma/cdma_api.c +++ b/drivers/ub/cdma/cdma_api.c @@ -4,6 +4,7 @@ #define pr_fmt(fmt) "CDMA: " fmt #define dev_fmt pr_fmt +#include "cdma_segment.h" #include "cdma_dev.h" #include "cdma_cmd.h" #include "cdma_context.h" @@ -310,6 +311,60 @@ void dma_free_queue(struct dma_device *dma_dev, int queue_id) } EXPORT_SYMBOL_GPL(dma_free_queue); +void dma_unregister_seg(struct dma_device *dma_dev, struct dma_seg *dma_seg) +{ + struct cdma_ctx_res *ctx_res; + struct cdma_context *ctx; + struct cdma_segment *seg; + struct cdma_dev *cdev; + + if (!dma_dev || !dma_dev->private_data || !dma_seg) + return; + + cdev = get_cdma_dev_by_eid(dma_dev->attr.eid.dw0); + if (!cdev) { + pr_err("can not find cdev by eid, eid = 0x%x\n", + dma_dev->attr.eid.dw0); + return; + } + + ctx_res = (struct cdma_ctx_res *)dma_dev->private_data; + seg = xa_load(&ctx_res->seg_xa, dma_seg->handle); + if (!seg) { + dev_err(cdev->dev, + "no segment found in this device, handle = %llu\n", + dma_seg->handle); + return; + } + xa_erase(&ctx_res->seg_xa, dma_seg->handle); + ctx = seg->ctx; + + cdma_seg_ungrant(seg); + cdma_unregister_seg(cdev, seg); + kfree(dma_seg); + + atomic_dec(&ctx->ref_cnt); +} +EXPORT_SYMBOL_GPL(dma_unregister_seg); + +struct dma_seg *dma_import_seg(struct dma_seg_cfg *cfg) +{ + if (!cfg || !cfg->sva || !cfg->len) + return NULL; + + return cdma_import_seg(cfg); +} +EXPORT_SYMBOL_GPL(dma_import_seg); + +void dma_unimport_seg(struct dma_seg *dma_seg) +{ + if (!dma_seg) + return; + + cdma_unimport_seg(dma_seg); +} +EXPORT_SYMBOL_GPL(dma_unimport_seg); + int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, struct dma_cr *cr) { diff --git a/drivers/ub/cdma/cdma_context.h b/drivers/ub/cdma/cdma_context.h index c48ac55631bf..590bffb14cce 100644 --- a/drivers/ub/cdma/cdma_context.h +++ b/drivers/ub/cdma/cdma_context.h @@ -23,11 +23,13 @@ struct cdma_context { bool is_kernel; atomic_t ref_cnt; struct list_head queue_list; + struct list_head seg_list; }; struct cdma_ctx_res { struct cdma_context *ctx; struct xarray queue_xa; + struct xarray seg_xa; }; struct cdma_context *cdma_find_ctx_by_handle(struct cdma_dev *cdev, int handle); diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index 96f33a55ebdf..79ad036557bf 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -122,6 +122,7 @@ static void cdma_init_tables(struct cdma_dev *cdev) static void cdma_destroy_tables(struct cdma_dev *cdev) { + cdma_tbl_destroy(cdev, &cdev->seg_table, "SEG"); cdma_tbl_destroy(cdev, &cdev->ctp_table, "CTP"); cdma_tbl_destroy(cdev, &cdev->jfs_table, "JFS"); cdma_tbl_destroy(cdev, &cdev->jfc_table, "JFC"); @@ -193,6 +194,7 @@ static void cdma_uninit_dev_param(struct cdma_dev *cdev) static void cdma_release_table_res(struct cdma_dev *cdev) { struct cdma_queue *queue; + struct cdma_segment *seg; struct cdma_jfc *jfc; struct cdma_jfs *jfs; struct cdma_tp *tmp; @@ -209,6 +211,9 @@ static void cdma_release_table_res(struct cdma_dev *cdev) idr_for_each_entry(&cdev->queue_table.idr_tbl.idr, queue, id) cdma_delete_queue(cdev, queue->id); + + idr_for_each_entry(&cdev->seg_table.idr_tbl.idr, seg, id) + cdma_unregister_seg(cdev, seg); } static int cdma_ctrlq_eu_add(struct cdma_dev *cdev, struct eu_info *eu) diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c index f1513c162db2..d9e8ca330bc8 100644 --- a/drivers/ub/cdma/cdma_ioctl.c +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -14,6 +14,7 @@ #include "cdma_queue.h" #include "cdma_event.h" #include "cdma_jfc.h" +#include "cdma_segment.h" #include "cdma_uobj.h" #include "cdma_ioctl.h" @@ -131,7 +132,8 @@ static int cdma_delete_ucontext(struct cdma_ioctl_hdr *hdr, dev_err(cdev->dev, "cdma context has not been created.\n"); return -ENOENT; } - if (!list_empty(&cfile->uctx->queue_list)) { + if (!list_empty(&cfile->uctx->queue_list) || + !list_empty(&cfile->uctx->seg_list)) { dev_err(cdev->dev, "queue/segment is still in use, ctx handle = %d.\n", cfile->uctx->handle); @@ -510,6 +512,42 @@ static int cdma_cmd_delete_queue(struct cdma_ioctl_hdr *hdr, struct cdma_file *c return ret; } +static int cdma_cmd_unregister_seg(struct cdma_ioctl_hdr *hdr, + struct cdma_file *cfile) +{ + struct cdma_cmd_unregister_seg_args arg = { 0 }; + struct cdma_dev *cdev = cfile->cdev; + struct cdma_segment *seg; + struct cdma_uobj *uobj; + int ret; + + if (!hdr->args_addr || hdr->args_len != sizeof(arg)) { + dev_err(cdev->dev, "unregister seg arg invalid.\n"); + return -EINVAL; + } + + ret = (int)copy_from_user(&arg, (void *)hdr->args_addr, + (u32)sizeof(arg)); + if (ret) { + dev_err(cdev->dev, + "unregister seg get user data failed, ret = %d.\n", + ret); + return -EFAULT; + } + + uobj = cdma_uobj_get(cfile, arg.in.handle, UOBJ_TYPE_SEGMENT); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, "get seg uobj failed.\n"); + return -EINVAL; + } + seg = uobj->object; + list_del(&seg->list); + cdma_unregister_seg(cdev, seg); + cdma_uobj_delete(uobj); + + return ret; +} + static int cdma_cmd_create_jfc(struct cdma_ioctl_hdr *hdr, struct cdma_file *cfile) { @@ -689,6 +727,7 @@ static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { [CDMA_CMD_DELETE_CTP] = cdma_cmd_delete_ctp, [CDMA_CMD_CREATE_JFS] = cdma_cmd_create_jfs, [CDMA_CMD_DELETE_JFS] = cdma_cmd_delete_jfs, + [CDMA_CMD_UNREGISTER_SEG] = cdma_cmd_unregister_seg, [CDMA_CMD_CREATE_QUEUE] = cdma_cmd_create_queue, [CDMA_CMD_DELETE_QUEUE] = cdma_cmd_delete_queue, [CDMA_CMD_CREATE_JFC] = cdma_cmd_create_jfc, diff --git a/drivers/ub/cdma/cdma_jfs.h b/drivers/ub/cdma/cdma_jfs.h index 7625ace4b5c7..e4dcaa765a89 100644 --- a/drivers/ub/cdma/cdma_jfs.h +++ b/drivers/ub/cdma/cdma_jfs.h @@ -6,6 +6,7 @@ #include "cdma_common.h" #include "cdma_types.h" +#include "cdma_segment.h" #define MAX_WQEBB_NUM 4 #define CDMA_JFS_WQEBB_SIZE 64 diff --git a/drivers/ub/cdma/cdma_segment.c b/drivers/ub/cdma/cdma_segment.c new file mode 100644 index 000000000000..c2746340c7cf --- /dev/null +++ b/drivers/ub/cdma/cdma_segment.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include +#include "cdma_segment.h" + +static inline void cdma_free_seg_handle(struct cdma_dev *cdev, u64 handle) +{ + spin_lock(&cdev->seg_table.lock); + idr_remove(&cdev->seg_table.idr_tbl.idr, handle); + spin_unlock(&cdev->seg_table.lock); +} + +void cdma_unregister_seg(struct cdma_dev *cdev, struct cdma_segment *seg) +{ + cdma_free_seg_handle(cdev, seg->base.handle); + cdma_umem_release(seg->umem, seg->is_kernel); + kfree(seg); +} + +void cdma_seg_ungrant(struct cdma_segment *seg) +{ + struct ummu_token_info token_info = { 0 }; + + token_info.tokenVal = seg->base.token_value; + + ummu_sva_ungrant_range(seg->ksva, (void *)seg->base.sva, + seg->base.len, &token_info); +} + +struct dma_seg *cdma_import_seg(struct dma_seg_cfg *cfg) +{ + struct dma_seg *seg; + + seg = kzalloc(sizeof(*seg), GFP_KERNEL); + if (!seg) + return NULL; + + seg->sva = cfg->sva; + seg->len = cfg->len; + seg->token_value = cfg->token_value; + + return seg; +} + +void cdma_unimport_seg(struct dma_seg *seg) +{ + kfree(seg); +} diff --git a/drivers/ub/cdma/cdma_segment.h b/drivers/ub/cdma/cdma_segment.h new file mode 100644 index 000000000000..67a9e714adec --- /dev/null +++ b/drivers/ub/cdma/cdma_segment.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_SEGMENT_H__ +#define __CDMA_SEGMENT_H__ + +#include "cdma_common.h" +#include + +struct cdma_dev; + +struct cdma_segment { + struct dma_seg base; + struct iommu_sva *ksva; + struct cdma_umem *umem; + struct cdma_context *ctx; + bool is_kernel; + struct list_head list; +}; + +void cdma_unregister_seg(struct cdma_dev *cdev, struct cdma_segment *seg); +void cdma_seg_ungrant(struct cdma_segment *seg); +struct dma_seg *cdma_import_seg(struct dma_seg_cfg *cfg); +void cdma_unimport_seg(struct dma_seg *seg); + +#endif /* CDMA_SEGMENT_H */ diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h index fcee5800193d..cdfcfc14a11d 100644 --- a/include/uapi/ub/cdma/cdma_abi.h +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -73,6 +73,7 @@ enum cdma_cmd { CDMA_CMD_DELETE_CTP, CDMA_CMD_CREATE_JFS, CDMA_CMD_DELETE_JFS, + CDMA_CMD_UNREGISTER_SEG, CDMA_CMD_CREATE_QUEUE, CDMA_CMD_DELETE_QUEUE, CDMA_CMD_CREATE_JFC, @@ -228,6 +229,12 @@ struct cdma_cmd_delete_jfc_args { } out; }; +struct cdma_cmd_unregister_seg_args { + struct { + __u64 handle; + } in; +}; + struct dev_eid { __u32 dw0; __u32 dw1; diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index 3ef1eedee111..d256aee9217b 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -51,6 +51,22 @@ struct queue_cfg { u32 trans_mode; }; +struct dma_seg { + u64 handle; + u64 sva; + u64 len; + u32 tid; /* data valid only in bit 0-19 */ + u32 token_value; + bool token_value_valid; +}; + +struct dma_seg_cfg { + u64 sva; + u64 len; + u32 token_value; + bool token_value_valid; +}; + struct dma_context { struct dma_device *dma_dev; u32 tid; /* data valid only in bit 0-19 */ @@ -71,6 +87,12 @@ int dma_alloc_queue(struct dma_device *dma_dev, int ctx_id, void dma_free_queue(struct dma_device *dma_dev, int queue_id); +void dma_unregister_seg(struct dma_device *dma_dev, struct dma_seg *dma_seg); + +struct dma_seg *dma_import_seg(struct dma_seg_cfg *cfg); + +void dma_unimport_seg(struct dma_seg *dma_seg); + int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, struct dma_cr *cr); -- Gitee From a7edc06d229c9f46e4c22e65c17ec6f3c2a22d2f Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 15:40:59 +0800 Subject: [PATCH 021/103] ub: cdma: support register segment commit 3aa2afdcbee97f1546e225a5f4f8c96cdc35e104 openEuler This patch implements local segment register-related functionality in the CDMA driver. The implementation includes support for the dma_register_seg interface. Signed-off-by: Zhipeng Lu Signed-off-by: Jinjie Cui Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma_api.c | 72 +++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_common.h | 1 + drivers/ub/cdma/cdma_context.c | 1 + drivers/ub/cdma/cdma_dev.c | 1 + drivers/ub/cdma/cdma_ioctl.c | 62 +++++++++++++++++++++++++ drivers/ub/cdma/cdma_segment.c | 81 +++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_segment.h | 9 ++++ include/uapi/ub/cdma/cdma_abi.h | 11 +++++ include/ub/cdma/cdma_api.h | 3 ++ 9 files changed, 241 insertions(+) diff --git a/drivers/ub/cdma/cdma_api.c b/drivers/ub/cdma/cdma_api.c index 4ba886635ca0..89d01159f797 100644 --- a/drivers/ub/cdma/cdma_api.c +++ b/drivers/ub/cdma/cdma_api.c @@ -311,6 +311,78 @@ void dma_free_queue(struct dma_device *dma_dev, int queue_id) } EXPORT_SYMBOL_GPL(dma_free_queue); +struct dma_seg *dma_register_seg(struct dma_device *dma_dev, int ctx_id, + struct dma_seg_cfg *cfg) +{ + struct cdma_ctx_res *ctx_res; + struct cdma_segment *seg; + struct cdma_context *ctx; + struct dma_seg *ret_seg; + struct cdma_dev *cdev; + int ret; + + if (!dma_dev || !dma_dev->private_data || !cfg || !cfg->sva || !cfg->len) + return NULL; + + cdev = get_cdma_dev_by_eid(dma_dev->attr.eid.dw0); + if (!cdev) { + pr_err("can not find normal cdev by eid, eid = 0x%x\n", + dma_dev->attr.eid.dw0); + return NULL; + } + + if (cdev->status == CDMA_SUSPEND) { + pr_warn("cdma device is not prepared, eid = 0x%x.\n", + dma_dev->attr.eid.dw0); + return NULL; + } + + ctx = cdma_find_ctx_by_handle(cdev, ctx_id); + if (!ctx) { + dev_err(cdev->dev, "find ctx by handle failed, handle = %d.\n", + ctx_id); + return NULL; + } + atomic_inc(&ctx->ref_cnt); + + seg = cdma_register_seg(cdev, cfg, true); + if (!seg) + goto decrease_cnt; + + seg->ctx = ctx; + ret = cdma_seg_grant(cdev, seg, cfg); + if (ret) + goto unregister_seg; + + ret_seg = kzalloc(sizeof(struct dma_seg), GFP_KERNEL); + if (!ret_seg) + goto ungrant_seg; + + memcpy(ret_seg, &seg->base, sizeof(struct dma_seg)); + + ctx_res = (struct cdma_ctx_res *)dma_dev->private_data; + ret = xa_err(xa_store(&ctx_res->seg_xa, ret_seg->handle, seg, + GFP_KERNEL)); + if (ret) { + dev_err(cdev->dev, "store seg to ctx_res failed, ret = %d\n", + ret); + goto free_seg; + } + + return ret_seg; + +free_seg: + kfree(ret_seg); +ungrant_seg: + cdma_seg_ungrant(seg); +unregister_seg: + cdma_unregister_seg(cdev, seg); +decrease_cnt: + atomic_dec(&ctx->ref_cnt); + return NULL; +} +EXPORT_SYMBOL_GPL(dma_register_seg); + void dma_unregister_seg(struct dma_device *dma_dev, struct dma_seg *dma_seg) { struct cdma_ctx_res *ctx_res; diff --git a/drivers/ub/cdma/cdma_common.h b/drivers/ub/cdma/cdma_common.h index b5a149658847..f0370bea2861 100644 --- a/drivers/ub/cdma/cdma_common.h +++ b/drivers/ub/cdma/cdma_common.h @@ -21,6 +21,7 @@ #define AVAIL_SGMT_OST_INIT 512 #define CDMA_RANGE_INDEX_ENTRY_CNT 0x100000 +#define CDMA_SEGMENT_ENTRY_CNT 0x10000 #define CDMA_DB_SIZE 64 diff --git a/drivers/ub/cdma/cdma_context.c b/drivers/ub/cdma/cdma_context.c index f13dcf8ccdbd..e3b3e13d8a4e 100644 --- a/drivers/ub/cdma/cdma_context.c +++ b/drivers/ub/cdma/cdma_context.c @@ -112,6 +112,7 @@ struct cdma_context *cdma_alloc_context(struct cdma_dev *cdev, bool is_kernel) INIT_LIST_HEAD(&ctx->pgdir_list); mutex_init(&ctx->pgdir_mutex); INIT_LIST_HEAD(&ctx->queue_list); + INIT_LIST_HEAD(&ctx->seg_list); return ctx; diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index 79ad036557bf..f08e60716edc 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -118,6 +118,7 @@ static void cdma_init_tables(struct cdma_dev *cdev) cdma_tbl_init(&cdev->jfs_table, jfs->max_cnt + jfs->start_idx - 1, jfs->start_idx); cdma_tbl_init(&cdev->ctp_table, CDMA_RANGE_INDEX_ENTRY_CNT, 0); + cdma_tbl_init(&cdev->seg_table, CDMA_SEGMENT_ENTRY_CNT, 0); } static void cdma_destroy_tables(struct cdma_dev *cdev) diff --git a/drivers/ub/cdma/cdma_ioctl.c b/drivers/ub/cdma/cdma_ioctl.c index d9e8ca330bc8..0a62e306d6f7 100644 --- a/drivers/ub/cdma/cdma_ioctl.c +++ b/drivers/ub/cdma/cdma_ioctl.c @@ -512,6 +512,67 @@ static int cdma_cmd_delete_queue(struct cdma_ioctl_hdr *hdr, struct cdma_file *c return ret; } +static int cdma_cmd_register_seg(struct cdma_ioctl_hdr *hdr, + struct cdma_file *cfile) +{ + struct cdma_cmd_register_seg_args arg = { 0 }; + struct cdma_dev *cdev = cfile->cdev; + struct dma_seg_cfg cfg = { 0 }; + struct cdma_segment *seg; + struct cdma_uobj *uobj; + int ret; + + if (!hdr->args_addr || hdr->args_len != sizeof(arg) || !cfile->uctx) { + dev_err(cdev->dev, "register seg arg invalid.\n"); + return -EINVAL; + } + + ret = (int)copy_from_user(&arg, (void *)hdr->args_addr, + (u32)sizeof(arg)); + if (ret) { + dev_err(cdev->dev, + "register seg get user data failed, ret = %d.\n", ret); + return -EFAULT; + } + + uobj = cdma_uobj_create(cfile, UOBJ_TYPE_SEGMENT); + if (IS_ERR(uobj)) { + dev_err(cdev->dev, "create seg uobj failed.\n"); + return -ENOMEM; + } + + cfg.sva = arg.in.addr; + cfg.len = arg.in.len; + seg = cdma_register_seg(cdev, &cfg, false); + if (!seg) { + dev_err(cdev->dev, "register seg failed.\n"); + ret = -EINVAL; + goto delete_uobj; + } + seg->ctx = cfile->uctx; + + list_add_tail(&seg->list, &cfile->uctx->seg_list); + arg.out.handle = uobj->id; + uobj->object = seg; + + ret = (int)copy_to_user((void *)hdr->args_addr, &arg, (u32)sizeof(arg)); + if (ret) { + dev_err(cdev->dev, + "register seg copy to user failed, ret = %d.\n", ret); + ret = -EFAULT; + goto free_seg; + } + return 0; + +free_seg: + list_del(&seg->list); + cdma_unregister_seg(cdev, seg); +delete_uobj: + cdma_uobj_delete(uobj); + + return ret; +} + static int cdma_cmd_unregister_seg(struct cdma_ioctl_hdr *hdr, struct cdma_file *cfile) { @@ -727,6 +788,7 @@ static cdma_cmd_handler g_cdma_cmd_handler[CDMA_CMD_MAX] = { [CDMA_CMD_DELETE_CTP] = cdma_cmd_delete_ctp, [CDMA_CMD_CREATE_JFS] = cdma_cmd_create_jfs, [CDMA_CMD_DELETE_JFS] = cdma_cmd_delete_jfs, + [CDMA_CMD_REGISTER_SEG] = cdma_cmd_register_seg, [CDMA_CMD_UNREGISTER_SEG] = cdma_cmd_unregister_seg, [CDMA_CMD_CREATE_QUEUE] = cdma_cmd_create_queue, [CDMA_CMD_DELETE_QUEUE] = cdma_cmd_delete_queue, diff --git a/drivers/ub/cdma/cdma_segment.c b/drivers/ub/cdma/cdma_segment.c index c2746340c7cf..6882d27cd70a 100644 --- a/drivers/ub/cdma/cdma_segment.c +++ b/drivers/ub/cdma/cdma_segment.c @@ -5,6 +5,27 @@ #include #include "cdma_segment.h" +#include "cdma_context.h" + +static int cdma_alloc_seg_handle(struct cdma_dev *cdev, + struct cdma_segment *seg) +{ + struct cdma_table *seg_table = &cdev->seg_table; + int handle; + + idr_preload(GFP_KERNEL); + spin_lock(&seg_table->lock); + + handle = idr_alloc(&seg_table->idr_tbl.idr, seg, seg_table->idr_tbl.min, + seg_table->idr_tbl.max, GFP_NOWAIT); + if (handle < 0) + dev_err(cdev->dev, "alloc seg handle failed.\n"); + + spin_unlock(&seg_table->lock); + idr_preload_end(); + + return handle; +} static inline void cdma_free_seg_handle(struct cdma_dev *cdev, u64 handle) { @@ -13,6 +34,43 @@ static inline void cdma_free_seg_handle(struct cdma_dev *cdev, u64 handle) spin_unlock(&cdev->seg_table.lock); } +struct cdma_segment *cdma_register_seg(struct cdma_dev *cdev, + struct dma_seg_cfg *cfg, bool is_kernel) +{ + struct cdma_segment *seg; + int handle; + + seg = kzalloc(sizeof(*seg), GFP_KERNEL); + if (!seg) + return NULL; + + seg->umem = cdma_umem_get(cdev, cfg->sva, cfg->len, is_kernel); + if (IS_ERR_OR_NULL(seg->umem)) { + dev_err(cdev->dev, "pin seg failed\n"); + goto free_seg; + } + + handle = cdma_alloc_seg_handle(cdev, seg); + if (handle < 0) + goto unpin_umem; + + seg->base.handle = (u64)handle; + seg->base.token_value = cfg->token_value; + seg->base.sva = cfg->sva; + seg->base.len = cfg->len; + seg->base.token_value_valid = cfg->token_value_valid; + seg->is_kernel = is_kernel; + + return seg; + +unpin_umem: + cdma_umem_release(seg->umem, is_kernel); +free_seg: + kfree(seg); + + return NULL; +} + void cdma_unregister_seg(struct cdma_dev *cdev, struct cdma_segment *seg) { cdma_free_seg_handle(cdev, seg->base.handle); @@ -20,6 +78,29 @@ void cdma_unregister_seg(struct cdma_dev *cdev, struct cdma_segment *seg) kfree(seg); } +int cdma_seg_grant(struct cdma_dev *cdev, struct cdma_segment *seg, + struct dma_seg_cfg *cfg) +{ + struct ummu_token_info token_info; + struct ummu_seg_attr seg_attr; + int ret; + + seg->base.tid = seg->ctx->tid; + seg->ksva = seg->ctx->sva; + + token_info.input = 0; + token_info.tokenVal = cfg->token_value; + seg_attr.token = &token_info; + seg_attr.e_bit = UMMU_EBIT_OFF; + + ret = ummu_sva_grant_range(seg->ksva, (void *)cfg->sva, cfg->len, + MAPT_PERM_RW, (void *)&seg_attr); + if (ret) + dev_err(cdev->dev, "grant seg failed, ret = %d.\n", ret); + + return ret; +} + void cdma_seg_ungrant(struct cdma_segment *seg) { struct ummu_token_info token_info = { 0 }; diff --git a/drivers/ub/cdma/cdma_segment.h b/drivers/ub/cdma/cdma_segment.h index 67a9e714adec..113e357fcedd 100644 --- a/drivers/ub/cdma/cdma_segment.h +++ b/drivers/ub/cdma/cdma_segment.h @@ -18,7 +18,16 @@ struct cdma_segment { struct list_head list; }; +static inline struct cdma_segment *to_cdma_seg(struct dma_seg *seg) +{ + return container_of(seg, struct cdma_segment, base); +} + +struct cdma_segment *cdma_register_seg(struct cdma_dev *cdev, + struct dma_seg_cfg *cfg, bool is_kernel); void cdma_unregister_seg(struct cdma_dev *cdev, struct cdma_segment *seg); +int cdma_seg_grant(struct cdma_dev *cdev, struct cdma_segment *seg, + struct dma_seg_cfg *cfg); void cdma_seg_ungrant(struct cdma_segment *seg); struct dma_seg *cdma_import_seg(struct dma_seg_cfg *cfg); void cdma_unimport_seg(struct dma_seg *seg); diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h index cdfcfc14a11d..b32954f28636 100644 --- a/include/uapi/ub/cdma/cdma_abi.h +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -73,6 +73,7 @@ enum cdma_cmd { CDMA_CMD_DELETE_CTP, CDMA_CMD_CREATE_JFS, CDMA_CMD_DELETE_JFS, + CDMA_CMD_REGISTER_SEG, CDMA_CMD_UNREGISTER_SEG, CDMA_CMD_CREATE_QUEUE, CDMA_CMD_DELETE_QUEUE, @@ -229,6 +230,16 @@ struct cdma_cmd_delete_jfc_args { } out; }; +struct cdma_cmd_register_seg_args { + struct { + __u64 addr; + __u64 len; + } in; + struct { + __u64 handle; + } out; +}; + struct cdma_cmd_unregister_seg_args { struct { __u64 handle; diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index d256aee9217b..ff69c268b569 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -87,6 +87,9 @@ int dma_alloc_queue(struct dma_device *dma_dev, int ctx_id, void dma_free_queue(struct dma_device *dma_dev, int queue_id); +struct dma_seg *dma_register_seg(struct dma_device *dma_dev, int ctx_id, + struct dma_seg_cfg *cfg); + void dma_unregister_seg(struct dma_device *dma_dev, struct dma_seg *dma_seg); struct dma_seg *dma_import_seg(struct dma_seg_cfg *cfg); -- Gitee From ba659c56a69f9a03859d9092f1a82807dc9e3ee0 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 27 Feb 2025 20:26:29 -0400 Subject: [PATCH 022/103] fwctl: Add basic structure for a class subsystem with a cdev [Upstream commit 2e4986cf2d525eed3a240b7821f89ca45cf36d78] Create the class, character device and functions for a fwctl driver to un/register to the subsystem. A typical fwctl driver has a sysfs presence like: $ ls -l /dev/fwctl/fwctl0 crw------- 1 root root 250, 0 Apr 25 19:16 /dev/fwctl/fwctl0 $ ls /sys/class/fwctl/fwctl0 dev device power subsystem uevent $ ls /sys/class/fwctl/fwctl0/device/infiniband/ ibp0s10f0 $ ls /sys/class/infiniband/ibp0s10f0/device/fwctl/ fwctl0/ $ ls /sys/devices/pci0000:00/0000:00:0a.0/fwctl/fwctl0 dev device power subsystem uevent Which allows userspace to link all the multi-subsystem driver components together and learn the subsystem specific names for the device's components. Link: https://patch.msgid.link/r/1-v5-642aa0c94070+4447f-fwctl_jgg@nvidia.com Reviewed-by: Jonathan Cameron Reviewed-by: Dan Williams Reviewed-by: Dave Jiang Reviewed-by: Shannon Nelson Tested-by: Dave Jiang Tested-by: Shannon Nelson Signed-off-by: Jason Gunthorpe Signed-off-by: huwentao --- MAINTAINERS | 9 ++ arch/arm64/configs/tencent.config | 3 + arch/x86/configs/tencent.config | 3 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwctl/Kconfig | 9 ++ drivers/fwctl/Makefile | 4 + drivers/fwctl/main.c | 173 ++++++++++++++++++++++++++++++ include/linux/fwctl.h | 69 ++++++++++++ 9 files changed, 273 insertions(+) create mode 100644 drivers/fwctl/Kconfig create mode 100644 drivers/fwctl/Makefile create mode 100644 drivers/fwctl/main.c create mode 100644 include/linux/fwctl.h diff --git a/MAINTAINERS b/MAINTAINERS index 29ee45a167d1..9cd5de7361ed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8640,6 +8640,15 @@ F: kernel/futex/* F: tools/perf/bench/futex* F: tools/testing/selftests/futex/ +FWCTL SUBSYSTEM +M: Dave Jiang +M: Jason Gunthorpe +M: Saeed Mahameed +R: Jonathan Cameron +S: Maintained +F: drivers/fwctl/ +F: include/linux/fwctl.h + GATEWORKS SYSTEM CONTROLLER (GSC) DRIVER M: Tim Harvey S: Maintained diff --git a/arch/arm64/configs/tencent.config b/arch/arm64/configs/tencent.config index b806c4dc225c..63cfddd36d14 100644 --- a/arch/arm64/configs/tencent.config +++ b/arch/arm64/configs/tencent.config @@ -1863,3 +1863,6 @@ CONFIG_UB_URMA=m CONFIG_IOMMUFD=m CONFIG_VFIO_DEVICE_CDEV=y # end of IOMMUFD + +# fwctl +CONFIG_FWCTL=y diff --git a/arch/x86/configs/tencent.config b/arch/x86/configs/tencent.config index 8958dc6d4527..126020c405a7 100644 --- a/arch/x86/configs/tencent.config +++ b/arch/x86/configs/tencent.config @@ -2026,3 +2026,6 @@ CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_KSTRTOX=y CONFIG_TEST_BPF=m CONFIG_EXT4_FS=y + +# fwctl +CONFIG_FWCTL=y diff --git a/drivers/Kconfig b/drivers/Kconfig index bfb2bdb00477..1a9785701376 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -22,6 +22,8 @@ source "drivers/connector/Kconfig" source "drivers/firmware/Kconfig" +source "drivers/fwctl/Kconfig" + source "drivers/gnss/Kconfig" source "drivers/mtd/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 800793aafbbb..269267ac3b4f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -141,6 +141,7 @@ obj-$(CONFIG_MEMSTICK) += memstick/ obj-$(CONFIG_NEW_LEDS) += leds/ obj-$(CONFIG_INFINIBAND) += infiniband/ obj-y += firmware/ +obj-$(CONFIG_FWCTL) += fwctl/ obj-$(CONFIG_CRYPTO) += crypto/ obj-$(CONFIG_SUPERH) += sh/ obj-y += clocksource/ diff --git a/drivers/fwctl/Kconfig b/drivers/fwctl/Kconfig new file mode 100644 index 000000000000..37147a695add --- /dev/null +++ b/drivers/fwctl/Kconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only +menuconfig FWCTL + tristate "fwctl device firmware access framework" + help + fwctl provides a userspace API for restricted access to communicate + with on-device firmware. The communication channel is intended to + support a wide range of lockdown compatible device behaviors including + manipulating device FLASH, debugging, and other activities that don't + fit neatly into an existing subsystem. diff --git a/drivers/fwctl/Makefile b/drivers/fwctl/Makefile new file mode 100644 index 000000000000..1cad210f6ba5 --- /dev/null +++ b/drivers/fwctl/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_FWCTL) += fwctl.o + +fwctl-y += main.o diff --git a/drivers/fwctl/main.c b/drivers/fwctl/main.c new file mode 100644 index 000000000000..9096b9ba9cf7 --- /dev/null +++ b/drivers/fwctl/main.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES + */ +#define pr_fmt(fmt) "fwctl: " fmt +#include + +#include +#include +#include +#include + +enum { + FWCTL_MAX_DEVICES = 4096, +}; +static_assert(FWCTL_MAX_DEVICES < (1U << MINORBITS)); + +static dev_t fwctl_dev; +static DEFINE_IDA(fwctl_ida); + +static int fwctl_fops_open(struct inode *inode, struct file *filp) +{ + struct fwctl_device *fwctl = + container_of(inode->i_cdev, struct fwctl_device, cdev); + + get_device(&fwctl->dev); + filp->private_data = fwctl; + return 0; +} + +static int fwctl_fops_release(struct inode *inode, struct file *filp) +{ + struct fwctl_device *fwctl = filp->private_data; + + fwctl_put(fwctl); + return 0; +} + +static const struct file_operations fwctl_fops = { + .owner = THIS_MODULE, + .open = fwctl_fops_open, + .release = fwctl_fops_release, +}; + +static void fwctl_device_release(struct device *device) +{ + struct fwctl_device *fwctl = + container_of(device, struct fwctl_device, dev); + + ida_free(&fwctl_ida, fwctl->dev.devt - fwctl_dev); + kfree(fwctl); +} + +static char *fwctl_devnode(const struct device *dev, umode_t *mode) +{ + return kasprintf(GFP_KERNEL, "fwctl/%s", dev_name(dev)); +} + +static struct class fwctl_class = { + .name = "fwctl", + .dev_release = fwctl_device_release, + .devnode = fwctl_devnode, +}; + +static struct fwctl_device * +_alloc_device(struct device *parent, const struct fwctl_ops *ops, size_t size) +{ + struct fwctl_device *fwctl __free(kfree) = kzalloc(size, GFP_KERNEL); + int devnum; + + if (!fwctl) + return NULL; + + fwctl->dev.class = &fwctl_class; + fwctl->dev.parent = parent; + + devnum = ida_alloc_max(&fwctl_ida, FWCTL_MAX_DEVICES - 1, GFP_KERNEL); + if (devnum < 0) + return NULL; + + fwctl->dev.devt = fwctl_dev + devnum; + fwctl->dev.class = &fwctl_class; + fwctl->dev.parent = parent; + + device_initialize(&fwctl->dev); + return_ptr(fwctl); +} + +/* Drivers use the fwctl_alloc_device() wrapper */ +struct fwctl_device *_fwctl_alloc_device(struct device *parent, + const struct fwctl_ops *ops, + size_t size) +{ + struct fwctl_device *fwctl __free(fwctl) = + _alloc_device(parent, ops, size); + + if (!fwctl) + return NULL; + + cdev_init(&fwctl->cdev, &fwctl_fops); + /* + * The driver module is protected by fwctl_register/unregister(), + * unregister won't complete until we are done with the driver's module. + */ + fwctl->cdev.owner = THIS_MODULE; + + if (dev_set_name(&fwctl->dev, "fwctl%d", fwctl->dev.devt - fwctl_dev)) + return NULL; + + fwctl->ops = ops; + return_ptr(fwctl); +} +EXPORT_SYMBOL_NS_GPL(_fwctl_alloc_device, FWCTL); + +/** + * fwctl_register - Register a new device to the subsystem + * @fwctl: Previously allocated fwctl_device + * + * On return the device is visible through sysfs and /dev, driver ops may be + * called. + */ +int fwctl_register(struct fwctl_device *fwctl) +{ + return cdev_device_add(&fwctl->cdev, &fwctl->dev); +} +EXPORT_SYMBOL_NS_GPL(fwctl_register, FWCTL); + +/** + * fwctl_unregister - Unregister a device from the subsystem + * @fwctl: Previously allocated and registered fwctl_device + * + * Undoes fwctl_register(). On return no driver ops will be called. The + * caller must still call fwctl_put() to free the fwctl. + * + * The design of fwctl allows this sort of disassociation of the driver from the + * subsystem primarily by keeping memory allocations owned by the core subsytem. + * The fwctl_device and fwctl_uctx can both be freed without requiring a driver + * callback. This allows the module to remain unlocked while FDs are open. + */ +void fwctl_unregister(struct fwctl_device *fwctl) +{ + cdev_device_del(&fwctl->cdev, &fwctl->dev); +} +EXPORT_SYMBOL_NS_GPL(fwctl_unregister, FWCTL); + +static int __init fwctl_init(void) +{ + int ret; + + ret = alloc_chrdev_region(&fwctl_dev, 0, FWCTL_MAX_DEVICES, "fwctl"); + if (ret) + return ret; + + ret = class_register(&fwctl_class); + if (ret) + goto err_chrdev; + return 0; + +err_chrdev: + unregister_chrdev_region(fwctl_dev, FWCTL_MAX_DEVICES); + return ret; +} + +static void __exit fwctl_exit(void) +{ + class_unregister(&fwctl_class); + unregister_chrdev_region(fwctl_dev, FWCTL_MAX_DEVICES); +} + +module_init(fwctl_init); +module_exit(fwctl_exit); +MODULE_DESCRIPTION("fwctl device firmware access framework"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/fwctl.h b/include/linux/fwctl.h new file mode 100644 index 000000000000..39d5059c9e59 --- /dev/null +++ b/include/linux/fwctl.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES + */ +#ifndef __LINUX_FWCTL_H +#define __LINUX_FWCTL_H +#include +#include +#include + +struct fwctl_device; +struct fwctl_uctx; + +struct fwctl_ops { +}; + +/** + * struct fwctl_device - Per-driver registration struct + * @dev: The sysfs (class/fwctl/fwctlXX) device + * + * Each driver instance will have one of these structs with the driver private + * data following immediately after. This struct is refcounted, it is freed by + * calling fwctl_put(). + */ +struct fwctl_device { + struct device dev; + /* private: */ + struct cdev cdev; + const struct fwctl_ops *ops; +}; + +struct fwctl_device *_fwctl_alloc_device(struct device *parent, + const struct fwctl_ops *ops, + size_t size); +/** + * fwctl_alloc_device - Allocate a fwctl + * @parent: Physical device that provides the FW interface + * @ops: Driver ops to register + * @drv_struct: 'struct driver_fwctl' that holds the struct fwctl_device + * @member: Name of the struct fwctl_device in @drv_struct + * + * This allocates and initializes the fwctl_device embedded in the drv_struct. + * Upon success the pointer must be freed via fwctl_put(). Returns a 'drv_struct + * \*' on success, NULL on error. + */ +#define fwctl_alloc_device(parent, ops, drv_struct, member) \ + ({ \ + static_assert(__same_type(struct fwctl_device, \ + ((drv_struct *)NULL)->member)); \ + static_assert(offsetof(drv_struct, member) == 0); \ + (drv_struct *)_fwctl_alloc_device(parent, ops, \ + sizeof(drv_struct)); \ + }) + +static inline struct fwctl_device *fwctl_get(struct fwctl_device *fwctl) +{ + get_device(&fwctl->dev); + return fwctl; +} +static inline void fwctl_put(struct fwctl_device *fwctl) +{ + put_device(&fwctl->dev); +} +DEFINE_FREE(fwctl, struct fwctl_device *, if (_T) fwctl_put(_T)); + +int fwctl_register(struct fwctl_device *fwctl); +void fwctl_unregister(struct fwctl_device *fwctl); + +#endif -- Gitee From 3aa3befb84b5226179f3066b8cfd5137013715ce Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 27 Feb 2025 20:26:30 -0400 Subject: [PATCH 023/103] fwctl: Basic ioctl dispatch for the character device [Upstream commit 0e79a47fb197b6937709a2af2a138c526a9bc374] Each file descriptor gets a chunk of per-FD driver specific context that allows the driver to attach a device specific struct to. The core code takes care of the memory lifetime for this structure. The ioctl dispatch and design is based on what was built for iommufd. The ioctls have a struct which has a combined in/out behavior with a typical 'zero pad' scheme for future extension and backwards compatibility. Like iommufd some shared logic does most of the ioctl marshaling and compatibility work and table dispatches to some function pointers for each unique ioctl. This approach has proven to work quite well in the iommufd and rdma subsystems. Allocate an ioctl number space for the subsystem. Link: https://patch.msgid.link/r/2-v5-642aa0c94070+4447f-fwctl_jgg@nvidia.com Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Reviewed-by: Shannon Nelson Tested-by: Dave Jiang Tested-by: Shannon Nelson Signed-off-by: Jason Gunthorpe Signed-off-by: huwentao --- .../userspace-api/ioctl/ioctl-number.rst | 1 + MAINTAINERS | 1 + drivers/fwctl/main.c | 143 +++++++++++++++++- include/linux/fwctl.h | 46 ++++++ include/uapi/fwctl/fwctl.h | 38 +++++ 5 files changed, 224 insertions(+), 5 deletions(-) create mode 100644 include/uapi/fwctl/fwctl.h diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index 4ea5b837399a..66ad52639a28 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -321,6 +321,7 @@ Code Seq# Include File Comments 0x97 00-7F fs/ceph/ioctl.h Ceph file system 0x99 00-0F 537-Addinboard driver +0x9A 00-0F include/uapi/fwctl/fwctl.h 0xA0 all linux/sdp/sdp.h Industrial Device Project 0xA1 0 linux/vtpm_proxy.h TPM Emulator Proxy Driver diff --git a/MAINTAINERS b/MAINTAINERS index 9cd5de7361ed..cd3481849a04 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8648,6 +8648,7 @@ R: Jonathan Cameron S: Maintained F: drivers/fwctl/ F: include/linux/fwctl.h +F: include/uapi/fwctl/ GATEWORKS SYSTEM CONTROLLER (GSC) DRIVER M: Tim Harvey diff --git a/drivers/fwctl/main.c b/drivers/fwctl/main.c index 9096b9ba9cf7..1aa0e4209a8c 100644 --- a/drivers/fwctl/main.c +++ b/drivers/fwctl/main.c @@ -10,6 +10,8 @@ #include #include +#include + enum { FWCTL_MAX_DEVICES = 4096, }; @@ -18,20 +20,128 @@ static_assert(FWCTL_MAX_DEVICES < (1U << MINORBITS)); static dev_t fwctl_dev; static DEFINE_IDA(fwctl_ida); +struct fwctl_ucmd { + struct fwctl_uctx *uctx; + void __user *ubuffer; + void *cmd; + u32 user_size; +}; + +/* On stack memory for the ioctl structs */ +union fwctl_ucmd_buffer { +}; + +struct fwctl_ioctl_op { + unsigned int size; + unsigned int min_size; + unsigned int ioctl_num; + int (*execute)(struct fwctl_ucmd *ucmd); +}; + +#define IOCTL_OP(_ioctl, _fn, _struct, _last) \ + [_IOC_NR(_ioctl) - FWCTL_CMD_BASE] = { \ + .size = sizeof(_struct) + \ + BUILD_BUG_ON_ZERO(sizeof(union fwctl_ucmd_buffer) < \ + sizeof(_struct)), \ + .min_size = offsetofend(_struct, _last), \ + .ioctl_num = _ioctl, \ + .execute = _fn, \ + } +static const struct fwctl_ioctl_op fwctl_ioctl_ops[] = { +}; + +static long fwctl_fops_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct fwctl_uctx *uctx = filp->private_data; + const struct fwctl_ioctl_op *op; + struct fwctl_ucmd ucmd = {}; + union fwctl_ucmd_buffer buf; + unsigned int nr; + int ret; + + nr = _IOC_NR(cmd); + if ((nr - FWCTL_CMD_BASE) >= ARRAY_SIZE(fwctl_ioctl_ops)) + return -ENOIOCTLCMD; + + op = &fwctl_ioctl_ops[nr - FWCTL_CMD_BASE]; + if (op->ioctl_num != cmd) + return -ENOIOCTLCMD; + + ucmd.uctx = uctx; + ucmd.cmd = &buf; + ucmd.ubuffer = (void __user *)arg; + ret = get_user(ucmd.user_size, (u32 __user *)ucmd.ubuffer); + if (ret) + return ret; + + if (ucmd.user_size < op->min_size) + return -EINVAL; + + ret = copy_struct_from_user(ucmd.cmd, op->size, ucmd.ubuffer, + ucmd.user_size); + if (ret) + return ret; + + guard(rwsem_read)(&uctx->fwctl->registration_lock); + if (!uctx->fwctl->ops) + return -ENODEV; + return op->execute(&ucmd); +} + static int fwctl_fops_open(struct inode *inode, struct file *filp) { struct fwctl_device *fwctl = container_of(inode->i_cdev, struct fwctl_device, cdev); + int ret; + + guard(rwsem_read)(&fwctl->registration_lock); + if (!fwctl->ops) + return -ENODEV; + + struct fwctl_uctx *uctx __free(kfree) = + kzalloc(fwctl->ops->uctx_size, GFP_KERNEL_ACCOUNT); + if (!uctx) + return -ENOMEM; + + uctx->fwctl = fwctl; + ret = fwctl->ops->open_uctx(uctx); + if (ret) + return ret; + + scoped_guard(mutex, &fwctl->uctx_list_lock) { + list_add_tail(&uctx->uctx_list_entry, &fwctl->uctx_list); + } get_device(&fwctl->dev); - filp->private_data = fwctl; + filp->private_data = no_free_ptr(uctx); return 0; } +static void fwctl_destroy_uctx(struct fwctl_uctx *uctx) +{ + lockdep_assert_held(&uctx->fwctl->uctx_list_lock); + list_del(&uctx->uctx_list_entry); + uctx->fwctl->ops->close_uctx(uctx); +} + static int fwctl_fops_release(struct inode *inode, struct file *filp) { - struct fwctl_device *fwctl = filp->private_data; + struct fwctl_uctx *uctx = filp->private_data; + struct fwctl_device *fwctl = uctx->fwctl; + scoped_guard(rwsem_read, &fwctl->registration_lock) { + /* + * NULL ops means fwctl_unregister() has already removed the + * driver and destroyed the uctx. + */ + if (fwctl->ops) { + guard(mutex)(&fwctl->uctx_list_lock); + fwctl_destroy_uctx(uctx); + } + } + + kfree(uctx); fwctl_put(fwctl); return 0; } @@ -40,6 +150,7 @@ static const struct file_operations fwctl_fops = { .owner = THIS_MODULE, .open = fwctl_fops_open, .release = fwctl_fops_release, + .unlocked_ioctl = fwctl_fops_ioctl, }; static void fwctl_device_release(struct device *device) @@ -48,6 +159,7 @@ static void fwctl_device_release(struct device *device) container_of(device, struct fwctl_device, dev); ida_free(&fwctl_ida, fwctl->dev.devt - fwctl_dev); + mutex_destroy(&fwctl->uctx_list_lock); kfree(fwctl); } @@ -71,9 +183,6 @@ _alloc_device(struct device *parent, const struct fwctl_ops *ops, size_t size) if (!fwctl) return NULL; - fwctl->dev.class = &fwctl_class; - fwctl->dev.parent = parent; - devnum = ida_alloc_max(&fwctl_ida, FWCTL_MAX_DEVICES - 1, GFP_KERNEL); if (devnum < 0) return NULL; @@ -82,6 +191,10 @@ _alloc_device(struct device *parent, const struct fwctl_ops *ops, size_t size) fwctl->dev.class = &fwctl_class; fwctl->dev.parent = parent; + init_rwsem(&fwctl->registration_lock); + mutex_init(&fwctl->uctx_list_lock); + INIT_LIST_HEAD(&fwctl->uctx_list); + device_initialize(&fwctl->dev); return_ptr(fwctl); } @@ -132,6 +245,10 @@ EXPORT_SYMBOL_NS_GPL(fwctl_register, FWCTL); * Undoes fwctl_register(). On return no driver ops will be called. The * caller must still call fwctl_put() to free the fwctl. * + * Unregister will return even if userspace still has file descriptors open. + * This will call ops->close_uctx() on any open FDs and after return no driver + * op will be called. The FDs remain open but all fops will return -ENODEV. + * * The design of fwctl allows this sort of disassociation of the driver from the * subsystem primarily by keeping memory allocations owned by the core subsytem. * The fwctl_device and fwctl_uctx can both be freed without requiring a driver @@ -139,7 +256,23 @@ EXPORT_SYMBOL_NS_GPL(fwctl_register, FWCTL); */ void fwctl_unregister(struct fwctl_device *fwctl) { + struct fwctl_uctx *uctx; + cdev_device_del(&fwctl->cdev, &fwctl->dev); + + /* Disable and free the driver's resources for any still open FDs. */ + guard(rwsem_write)(&fwctl->registration_lock); + guard(mutex)(&fwctl->uctx_list_lock); + while ((uctx = list_first_entry_or_null(&fwctl->uctx_list, + struct fwctl_uctx, + uctx_list_entry))) + fwctl_destroy_uctx(uctx); + + /* + * The driver module may unload after this returns, the op pointer will + * not be valid. + */ + fwctl->ops = NULL; } EXPORT_SYMBOL_NS_GPL(fwctl_unregister, FWCTL); diff --git a/include/linux/fwctl.h b/include/linux/fwctl.h index 39d5059c9e59..faa4b2c780e0 100644 --- a/include/linux/fwctl.h +++ b/include/linux/fwctl.h @@ -11,7 +11,30 @@ struct fwctl_device; struct fwctl_uctx; +/** + * struct fwctl_ops - Driver provided operations + * + * fwctl_unregister() will wait until all excuting ops are completed before it + * returns. Drivers should be mindful to not let their ops run for too long as + * it will block device hot unplug and module unloading. + */ struct fwctl_ops { + /** + * @uctx_size: The size of the fwctl_uctx struct to allocate. The first + * bytes of this memory will be a fwctl_uctx. The driver can use the + * remaining bytes as its private memory. + */ + size_t uctx_size; + /** + * @open_uctx: Called when a file descriptor is opened before the uctx + * is ever used. + */ + int (*open_uctx)(struct fwctl_uctx *uctx); + /** + * @close_uctx: Called when the uctx is destroyed, usually when the FD + * is closed. + */ + void (*close_uctx)(struct fwctl_uctx *uctx); }; /** @@ -26,6 +49,15 @@ struct fwctl_device { struct device dev; /* private: */ struct cdev cdev; + + /* Protect uctx_list */ + struct mutex uctx_list_lock; + struct list_head uctx_list; + /* + * Protect ops, held for write when ops becomes NULL during unregister, + * held for read whenever ops is loaded or an ops function is running. + */ + struct rw_semaphore registration_lock; const struct fwctl_ops *ops; }; @@ -66,4 +98,18 @@ DEFINE_FREE(fwctl, struct fwctl_device *, if (_T) fwctl_put(_T)); int fwctl_register(struct fwctl_device *fwctl); void fwctl_unregister(struct fwctl_device *fwctl); +/** + * struct fwctl_uctx - Per user FD context + * @fwctl: fwctl instance that owns the context + * + * Every FD opened by userspace will get a unique context allocation. Any driver + * private data will follow immediately after. + */ +struct fwctl_uctx { + struct fwctl_device *fwctl; + /* private: */ + /* Head at fwctl_device::uctx_list */ + struct list_head uctx_list_entry; +}; + #endif diff --git a/include/uapi/fwctl/fwctl.h b/include/uapi/fwctl/fwctl.h new file mode 100644 index 000000000000..8f5fe821cf28 --- /dev/null +++ b/include/uapi/fwctl/fwctl.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. + */ +#ifndef _UAPI_FWCTL_H +#define _UAPI_FWCTL_H + +#define FWCTL_TYPE 0x9A + +/** + * DOC: General ioctl format + * + * The ioctl interface follows a general format to allow for extensibility. Each + * ioctl is passed a structure pointer as the argument providing the size of + * the structure in the first u32. The kernel checks that any structure space + * beyond what it understands is 0. This allows userspace to use the backward + * compatible portion while consistently using the newer, larger, structures. + * + * ioctls use a standard meaning for common errnos: + * + * - ENOTTY: The IOCTL number itself is not supported at all + * - E2BIG: The IOCTL number is supported, but the provided structure has + * non-zero in a part the kernel does not understand. + * - EOPNOTSUPP: The IOCTL number is supported, and the structure is + * understood, however a known field has a value the kernel does not + * understand or support. + * - EINVAL: Everything about the IOCTL was understood, but a field is not + * correct. + * - ENOMEM: Out of memory. + * - ENODEV: The underlying device has been hot-unplugged and the FD is + * orphaned. + * + * As well as additional errnos, within specific ioctls. + */ +enum { + FWCTL_CMD_BASE = 0, +}; + +#endif -- Gitee From 2ce7983c7d3378053b64962d26243652883f9e50 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 27 Feb 2025 20:26:31 -0400 Subject: [PATCH 024/103] fwctl: FWCTL_INFO to return basic information about the device [Upstream commit fb39e9092be5a18eaab05b5a2492741fe6e395fe] Userspace will need to know some details about the fwctl interface being used to locate the correct userspace code to communicate with the kernel. Provide a simple device_type enum indicating what the kernel driver is. Allow the device to provide a device specific info struct that contains any additional information that the driver may need to provide to userspace. Link: https://patch.msgid.link/r/3-v5-642aa0c94070+4447f-fwctl_jgg@nvidia.com Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Reviewed-by: Shannon Nelson Tested-by: Dave Jiang Tested-by: Shannon Nelson Signed-off-by: Jason Gunthorpe Signed-off-by: huwentao --- drivers/fwctl/main.c | 55 ++++++++++++++++++++++++++++++++++++++ include/linux/fwctl.h | 12 +++++++++ include/uapi/fwctl/fwctl.h | 31 +++++++++++++++++++++ 3 files changed, 98 insertions(+) diff --git a/drivers/fwctl/main.c b/drivers/fwctl/main.c index 1aa0e4209a8c..44305af8a1c9 100644 --- a/drivers/fwctl/main.c +++ b/drivers/fwctl/main.c @@ -27,8 +27,62 @@ struct fwctl_ucmd { u32 user_size; }; +static int ucmd_respond(struct fwctl_ucmd *ucmd, size_t cmd_len) +{ + if (copy_to_user(ucmd->ubuffer, ucmd->cmd, + min_t(size_t, ucmd->user_size, cmd_len))) + return -EFAULT; + return 0; +} + +static int copy_to_user_zero_pad(void __user *to, const void *from, + size_t from_len, size_t user_len) +{ + size_t copy_len; + + copy_len = min(from_len, user_len); + if (copy_to_user(to, from, copy_len)) + return -EFAULT; + if (copy_len < user_len) { + if (clear_user(to + copy_len, user_len - copy_len)) + return -EFAULT; + } + return 0; +} + +static int fwctl_cmd_info(struct fwctl_ucmd *ucmd) +{ + struct fwctl_device *fwctl = ucmd->uctx->fwctl; + struct fwctl_info *cmd = ucmd->cmd; + size_t driver_info_len = 0; + + if (cmd->flags) + return -EOPNOTSUPP; + + if (!fwctl->ops->info && cmd->device_data_len) { + if (clear_user(u64_to_user_ptr(cmd->out_device_data), + cmd->device_data_len)) + return -EFAULT; + } else if (cmd->device_data_len) { + void *driver_info __free(kfree) = + fwctl->ops->info(ucmd->uctx, &driver_info_len); + if (IS_ERR(driver_info)) + return PTR_ERR(driver_info); + + if (copy_to_user_zero_pad(u64_to_user_ptr(cmd->out_device_data), + driver_info, driver_info_len, + cmd->device_data_len)) + return -EFAULT; + } + + cmd->out_device_type = fwctl->ops->device_type; + cmd->device_data_len = driver_info_len; + return ucmd_respond(ucmd, sizeof(*cmd)); +} + /* On stack memory for the ioctl structs */ union fwctl_ucmd_buffer { + struct fwctl_info info; }; struct fwctl_ioctl_op { @@ -48,6 +102,7 @@ struct fwctl_ioctl_op { .execute = _fn, \ } static const struct fwctl_ioctl_op fwctl_ioctl_ops[] = { + IOCTL_OP(FWCTL_INFO, fwctl_cmd_info, struct fwctl_info, out_device_data), }; static long fwctl_fops_ioctl(struct file *filp, unsigned int cmd, diff --git a/include/linux/fwctl.h b/include/linux/fwctl.h index faa4b2c780e0..700a5be940e3 100644 --- a/include/linux/fwctl.h +++ b/include/linux/fwctl.h @@ -7,6 +7,7 @@ #include #include #include +#include struct fwctl_device; struct fwctl_uctx; @@ -19,6 +20,10 @@ struct fwctl_uctx; * it will block device hot unplug and module unloading. */ struct fwctl_ops { + /** + * @device_type: The drivers assigned device_type number. This is uABI. + */ + enum fwctl_device_type device_type; /** * @uctx_size: The size of the fwctl_uctx struct to allocate. The first * bytes of this memory will be a fwctl_uctx. The driver can use the @@ -35,6 +40,13 @@ struct fwctl_ops { * is closed. */ void (*close_uctx)(struct fwctl_uctx *uctx); + /** + * @info: Implement FWCTL_INFO. Return a kmalloc() memory that is copied + * to out_device_data. On input length indicates the size of the user + * buffer on output it indicates the size of the memory. The driver can + * ignore length on input, the core code will handle everything. + */ + void *(*info)(struct fwctl_uctx *uctx, size_t *length); }; /** diff --git a/include/uapi/fwctl/fwctl.h b/include/uapi/fwctl/fwctl.h index 8f5fe821cf28..4052df63f66d 100644 --- a/include/uapi/fwctl/fwctl.h +++ b/include/uapi/fwctl/fwctl.h @@ -4,6 +4,9 @@ #ifndef _UAPI_FWCTL_H #define _UAPI_FWCTL_H +#include +#include + #define FWCTL_TYPE 0x9A /** @@ -33,6 +36,34 @@ */ enum { FWCTL_CMD_BASE = 0, + FWCTL_CMD_INFO = 0, +}; + +enum fwctl_device_type { + FWCTL_DEVICE_TYPE_ERROR = 0, +}; + +/** + * struct fwctl_info - ioctl(FWCTL_INFO) + * @size: sizeof(struct fwctl_info) + * @flags: Must be 0 + * @out_device_type: Returns the type of the device from enum fwctl_device_type + * @device_data_len: On input the length of the out_device_data memory. On + * output the size of the kernel's device_data which may be larger or + * smaller than the input. Maybe 0 on input. + * @out_device_data: Pointer to a memory of device_data_len bytes. Kernel will + * fill the entire memory, zeroing as required. + * + * Returns basic information about this fwctl instance, particularly what driver + * is being used to define the device_data format. + */ +struct fwctl_info { + __u32 size; + __u32 flags; + __u32 out_device_type; + __u32 device_data_len; + __aligned_u64 out_device_data; }; +#define FWCTL_INFO _IO(FWCTL_TYPE, FWCTL_CMD_INFO) #endif -- Gitee From 539f0dc269d4fd9013fc3ba022083ce1836b58f8 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 27 Feb 2025 20:26:32 -0400 Subject: [PATCH 025/103] taint: Add TAINT_FWCTL [Upstream commit 8eea4e74475804285507c077bec87d40be87ff06] Requesting a fwctl scope of access that includes mutating device debug data will cause the kernel to be tainted. Changing the device operation through things in the debug scope may cause the device to malfunction in undefined ways. This should be reflected in the TAINT flags to help any debuggers understand that something has been done. Link: https://patch.msgid.link/r/4-v5-642aa0c94070+4447f-fwctl_jgg@nvidia.com Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Reviewed-by: Shannon Nelson Tested-by: Dave Jiang Tested-by: Shannon Nelson Signed-off-by: Jason Gunthorpe Signed-off-by: huwentao --- Documentation/admin-guide/tainted-kernels.rst | 6 ++++++ include/linux/panic.h | 3 ++- kernel/panic.c | 1 + tools/debugging/kernel-chktaint | 8 ++++++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/tainted-kernels.rst b/Documentation/admin-guide/tainted-kernels.rst index 92a8a07f5c43..6a63aede0d86 100644 --- a/Documentation/admin-guide/tainted-kernels.rst +++ b/Documentation/admin-guide/tainted-kernels.rst @@ -101,6 +101,7 @@ Bit Log Number Reason that got the kernel tainted 16 _/X 65536 auxiliary taint, defined for and used by distros 17 _/T 131072 kernel was built with the struct randomization plugin 18 _/N 262144 an in-kernel test has been run + 19 _/J 524288 userspace used a mutating debug operation in fwctl === === ====== ======================================================== Note: The character ``_`` is representing a blank in this table to make reading @@ -182,3 +183,8 @@ More detailed explanation for tainting produce extremely unusual kernel structure layouts (even performance pathological ones), which is important to know when debugging. Set at build time. + + 19) ``J`` if userpace opened /dev/fwctl/* and performed a FWTCL_RPC_DEBUG_WRITE + to use the devices debugging features. Device debugging features could + cause the device to malfunction in undefined ways. + diff --git a/include/linux/panic.h b/include/linux/panic.h index d0d592e55173..adfe053cf6b2 100644 --- a/include/linux/panic.h +++ b/include/linux/panic.h @@ -75,7 +75,8 @@ static inline void set_arch_panic_timeout(int timeout, int arch_default_timeout) #define TAINT_AUX 16 #define TAINT_RANDSTRUCT 17 #define TAINT_TEST 18 -#define TAINT_FLAGS_COUNT 19 +#define TAINT_FWCTL 19 +#define TAINT_FLAGS_COUNT 20 #define TAINT_FLAGS_MAX ((1UL << TAINT_FLAGS_COUNT) - 1) struct taint_flag { diff --git a/kernel/panic.c b/kernel/panic.c index 8c54a4b96f03..0defd5bcfb89 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -482,6 +482,7 @@ const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = { [ TAINT_AUX ] = { 'X', ' ', true }, [ TAINT_RANDSTRUCT ] = { 'T', ' ', true }, [ TAINT_TEST ] = { 'N', ' ', true }, + [ TAINT_FWCTL ] = { 'J', ' ', true }, }; /** diff --git a/tools/debugging/kernel-chktaint b/tools/debugging/kernel-chktaint index 279be06332be..e7da0909d097 100755 --- a/tools/debugging/kernel-chktaint +++ b/tools/debugging/kernel-chktaint @@ -204,6 +204,14 @@ else echo " * an in-kernel test (such as a KUnit test) has been run (#18)" fi +T=`expr $T / 2` +if [ `expr $T % 2` -eq 0 ]; then + addout " " +else + addout "J" + echo " * fwctl's mutating debug interface was used (#19)" +fi + echo "For a more detailed explanation of the various taint flags see" echo " Documentation/admin-guide/tainted-kernels.rst in the Linux kernel sources" echo " or https://kernel.org/doc/html/latest/admin-guide/tainted-kernels.html" -- Gitee From dfd3a195aa57652878b5ea2a4735940d03b22871 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 27 Feb 2025 20:26:33 -0400 Subject: [PATCH 026/103] fwctl: FWCTL_RPC to execute a Remote Procedure Call to device firmware [Upstream commit 840cfb7cf570b681f5d20e19f7c2675a9d991732] Add the FWCTL_RPC ioctl which allows a request/response RPC call to device firmware. Drivers implementing this call must follow the security guidelines under Documentation/userspace-api/fwctl.rst The core code provides some memory management helpers to get the messages copied from and back to userspace. The driver is responsible for allocating the output message memory and delivering the message to the device. Link: https://patch.msgid.link/r/5-v5-642aa0c94070+4447f-fwctl_jgg@nvidia.com Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Reviewed-by: Shannon Nelson Tested-by: Dave Jiang Tested-by: Shannon Nelson Signed-off-by: Jason Gunthorpe Signed-off-by: huwentao --- drivers/fwctl/main.c | 60 +++++++++++++++++++++++++++++++++ include/linux/fwctl.h | 8 +++++ include/uapi/fwctl/fwctl.h | 69 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) diff --git a/drivers/fwctl/main.c b/drivers/fwctl/main.c index 44305af8a1c9..c783e94c9c65 100644 --- a/drivers/fwctl/main.c +++ b/drivers/fwctl/main.c @@ -8,17 +8,20 @@ #include #include #include +#include #include #include enum { FWCTL_MAX_DEVICES = 4096, + MAX_RPC_LEN = SZ_2M, }; static_assert(FWCTL_MAX_DEVICES < (1U << MINORBITS)); static dev_t fwctl_dev; static DEFINE_IDA(fwctl_ida); +static unsigned long fwctl_tainted; struct fwctl_ucmd { struct fwctl_uctx *uctx; @@ -80,9 +83,65 @@ static int fwctl_cmd_info(struct fwctl_ucmd *ucmd) return ucmd_respond(ucmd, sizeof(*cmd)); } +static int fwctl_cmd_rpc(struct fwctl_ucmd *ucmd) +{ + struct fwctl_device *fwctl = ucmd->uctx->fwctl; + struct fwctl_rpc *cmd = ucmd->cmd; + size_t out_len; + + if (cmd->in_len > MAX_RPC_LEN || cmd->out_len > MAX_RPC_LEN) + return -EMSGSIZE; + + switch (cmd->scope) { + case FWCTL_RPC_CONFIGURATION: + case FWCTL_RPC_DEBUG_READ_ONLY: + break; + + case FWCTL_RPC_DEBUG_WRITE_FULL: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + fallthrough; + case FWCTL_RPC_DEBUG_WRITE: + if (!test_and_set_bit(0, &fwctl_tainted)) { + dev_warn( + &fwctl->dev, + "%s(%d): has requested full access to the physical device device", + current->comm, task_pid_nr(current)); + add_taint(TAINT_FWCTL, LOCKDEP_STILL_OK); + } + break; + default: + return -EOPNOTSUPP; + } + + void *inbuf __free(kvfree) = kvzalloc(cmd->in_len, GFP_KERNEL_ACCOUNT); + if (!inbuf) + return -ENOMEM; + if (copy_from_user(inbuf, u64_to_user_ptr(cmd->in), cmd->in_len)) + return -EFAULT; + + out_len = cmd->out_len; + void *outbuf __free(kvfree) = fwctl->ops->fw_rpc( + ucmd->uctx, cmd->scope, inbuf, cmd->in_len, &out_len); + if (IS_ERR(outbuf)) + return PTR_ERR(outbuf); + if (outbuf == inbuf) { + /* The driver can re-use inbuf as outbuf */ + inbuf = NULL; + } + + if (copy_to_user(u64_to_user_ptr(cmd->out), outbuf, + min(cmd->out_len, out_len))) + return -EFAULT; + + cmd->out_len = out_len; + return ucmd_respond(ucmd, sizeof(*cmd)); +} + /* On stack memory for the ioctl structs */ union fwctl_ucmd_buffer { struct fwctl_info info; + struct fwctl_rpc rpc; }; struct fwctl_ioctl_op { @@ -103,6 +162,7 @@ struct fwctl_ioctl_op { } static const struct fwctl_ioctl_op fwctl_ioctl_ops[] = { IOCTL_OP(FWCTL_INFO, fwctl_cmd_info, struct fwctl_info, out_device_data), + IOCTL_OP(FWCTL_RPC, fwctl_cmd_rpc, struct fwctl_rpc, out), }; static long fwctl_fops_ioctl(struct file *filp, unsigned int cmd, diff --git a/include/linux/fwctl.h b/include/linux/fwctl.h index 700a5be940e3..5d61fc8a6871 100644 --- a/include/linux/fwctl.h +++ b/include/linux/fwctl.h @@ -47,6 +47,14 @@ struct fwctl_ops { * ignore length on input, the core code will handle everything. */ void *(*info)(struct fwctl_uctx *uctx, size_t *length); + /** + * @fw_rpc: Implement FWCTL_RPC. Deliver rpc_in/in_len to the FW and + * return the response and set out_len. rpc_in can be returned as the + * response pointer. Otherwise the returned pointer is freed with + * kvfree(). + */ + void *(*fw_rpc)(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope, + void *rpc_in, size_t in_len, size_t *out_len); }; /** diff --git a/include/uapi/fwctl/fwctl.h b/include/uapi/fwctl/fwctl.h index 4052df63f66d..0bec798790a6 100644 --- a/include/uapi/fwctl/fwctl.h +++ b/include/uapi/fwctl/fwctl.h @@ -37,6 +37,7 @@ enum { FWCTL_CMD_BASE = 0, FWCTL_CMD_INFO = 0, + FWCTL_CMD_RPC = 1, }; enum fwctl_device_type { @@ -66,4 +67,72 @@ struct fwctl_info { }; #define FWCTL_INFO _IO(FWCTL_TYPE, FWCTL_CMD_INFO) +/** + * enum fwctl_rpc_scope - Scope of access for the RPC + * + * Refer to fwctl.rst for a more detailed discussion of these scopes. + */ +enum fwctl_rpc_scope { + /** + * @FWCTL_RPC_CONFIGURATION: Device configuration access scope + * + * Read/write access to device configuration. When configuration + * is written to the device it remains in a fully supported state. + */ + FWCTL_RPC_CONFIGURATION = 0, + /** + * @FWCTL_RPC_DEBUG_READ_ONLY: Read only access to debug information + * + * Readable debug information. Debug information is compatible with + * kernel lockdown, and does not disclose any sensitive information. For + * instance exposing any encryption secrets from this information is + * forbidden. + */ + FWCTL_RPC_DEBUG_READ_ONLY = 1, + /** + * @FWCTL_RPC_DEBUG_WRITE: Writable access to lockdown compatible debug information + * + * Allows write access to data in the device which may leave a fully + * supported state. This is intended to permit intensive and possibly + * invasive debugging. This scope will taint the kernel. + */ + FWCTL_RPC_DEBUG_WRITE = 2, + /** + * @FWCTL_RPC_DEBUG_WRITE_FULL: Write access to all debug information + * + * Allows read/write access to everything. Requires CAP_SYS_RAW_IO, so + * it is not required to follow lockdown principals. If in doubt + * debugging should be placed in this scope. This scope will taint the + * kernel. + */ + FWCTL_RPC_DEBUG_WRITE_FULL = 3, +}; + +/** + * struct fwctl_rpc - ioctl(FWCTL_RPC) + * @size: sizeof(struct fwctl_rpc) + * @scope: One of enum fwctl_rpc_scope, required scope for the RPC + * @in_len: Length of the in memory + * @out_len: Length of the out memory + * @in: Request message in device specific format + * @out: Response message in device specific format + * + * Deliver a Remote Procedure Call to the device FW and return the response. The + * call's parameters and return are marshaled into linear buffers of memory. Any + * errno indicates that delivery of the RPC to the device failed. Return status + * originating in the device during a successful delivery must be encoded into + * out. + * + * The format of the buffers matches the out_device_type from FWCTL_INFO. + */ +struct fwctl_rpc { + __u32 size; + __u32 scope; + __u32 in_len; + __u32 out_len; + __aligned_u64 in; + __aligned_u64 out; +}; +#define FWCTL_RPC _IO(FWCTL_TYPE, FWCTL_CMD_RPC) + #endif -- Gitee From 4084f086b43dba0ca4318f5154fe8249d0dc5a44 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 27 Feb 2025 20:26:34 -0400 Subject: [PATCH 027/103] fwctl: Add documentation [Upstream commit 18285acc2c047cda2449f426c09fc8969b04b8b1] Document the purpose and rules for the fwctl subsystem. Link in kdocs to the doc tree. Link: https://patch.msgid.link/r/6-v5-642aa0c94070+4447f-fwctl_jgg@nvidia.com Nacked-by: Jakub Kicinski Link: https://lore.kernel.org/r/20240603114250.5325279c@kernel.org Acked-by: Daniel Vetter Link: https://lore.kernel.org/r/ZrHY2Bds7oF7KRGz@phenom.ffwll.local Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Reviewed-by: Shannon Nelson Reviewed-by: Bagas Sanjaya Signed-off-by: Jason Gunthorpe Signed-off-by: huwentao --- Documentation/userspace-api/fwctl/fwctl.rst | 284 ++++++++++++++++++++ Documentation/userspace-api/fwctl/index.rst | 12 + Documentation/userspace-api/index.rst | 1 + MAINTAINERS | 1 + 4 files changed, 298 insertions(+) create mode 100644 Documentation/userspace-api/fwctl/fwctl.rst create mode 100644 Documentation/userspace-api/fwctl/index.rst diff --git a/Documentation/userspace-api/fwctl/fwctl.rst b/Documentation/userspace-api/fwctl/fwctl.rst new file mode 100644 index 000000000000..8c586a8f677d --- /dev/null +++ b/Documentation/userspace-api/fwctl/fwctl.rst @@ -0,0 +1,284 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=============== +fwctl subsystem +=============== + +:Author: Jason Gunthorpe + +Overview +======== + +Modern devices contain extensive amounts of FW, and in many cases, are largely +software-defined pieces of hardware. The evolution of this approach is largely a +reaction to Moore's Law where a chip tape out is now highly expensive, and the +chip design is extremely large. Replacing fixed HW logic with a flexible and +tightly coupled FW/HW combination is an effective risk mitigation against chip +respin. Problems in the HW design can be counteracted in device FW. This is +especially true for devices which present a stable and backwards compatible +interface to the operating system driver (such as NVMe). + +The FW layer in devices has grown to incredible size and devices frequently +integrate clusters of fast processors to run it. For example, mlx5 devices have +over 30MB of FW code, and big configurations operate with over 1GB of FW managed +runtime state. + +The availability of such a flexible layer has created quite a variety in the +industry where single pieces of silicon are now configurable software-defined +devices and can operate in substantially different ways depending on the need. +Further, we often see cases where specific sites wish to operate devices in ways +that are highly specialized and require applications that have been tailored to +their unique configuration. + +Further, devices have become multi-functional and integrated to the point they +no longer fit neatly into the kernel's division of subsystems. Modern +multi-functional devices have drivers, such as bnxt/ice/mlx5/pds, that span many +subsystems while sharing the underlying hardware using the auxiliary device +system. + +All together this creates a challenge for the operating system, where devices +have an expansive FW environment that needs robust device-specific debugging +support, and FW-driven functionality that is not well suited to “generic” +interfaces. fwctl seeks to allow access to the full device functionality from +user space in the areas of debuggability, management, and first-boot/nth-boot +provisioning. + +fwctl is aimed at the common device design pattern where the OS and FW +communicate via an RPC message layer constructed with a queue or mailbox scheme. +In this case the driver will typically have some layer to deliver RPC messages +and collect RPC responses from device FW. The in-kernel subsystem drivers that +operate the device for its primary purposes will use these RPCs to build their +drivers, but devices also usually have a set of ancillary RPCs that don't really +fit into any specific subsystem. For example, a HW RAID controller is primarily +operated by the block layer but also comes with a set of RPCs to administer the +construction of drives within the HW RAID. + +In the past when devices were more single function, individual subsystems would +grow different approaches to solving some of these common problems. For instance +monitoring device health, manipulating its FLASH, debugging the FW, +provisioning, all have various unique interfaces across the kernel. + +fwctl's purpose is to define a common set of limited rules, described below, +that allow user space to securely construct and execute RPCs inside device FW. +The rules serve as an agreement between the operating system and FW on how to +correctly design the RPC interface. As a uAPI the subsystem provides a thin +layer of discovery and a generic uAPI to deliver the RPCs and collect the +response. It supports a system of user space libraries and tools which will +use this interface to control the device using the device native protocols. + +Scope of Action +--------------- + +fwctl drivers are strictly restricted to being a way to operate the device FW. +It is not an avenue to access random kernel internals, or other operating system +SW states. + +fwctl instances must operate on a well-defined device function, and the device +should have a well-defined security model for what scope within the physical +device the function is permitted to access. For instance, the most complex PCIe +device today may broadly have several function-level scopes: + + 1. A privileged function with full access to the on-device global state and + configuration + + 2. Multiple hypervisor functions with control over itself and child functions + used with VMs + + 3. Multiple VM functions tightly scoped within the VM + +The device may create a logical parent/child relationship between these scopes. +For instance a child VM's FW may be within the scope of the hypervisor FW. It is +quite common in the VFIO world that the hypervisor environment has a complex +provisioning/profiling/configuration responsibility for the function VFIO +assigns to the VM. + +Further, within the function, devices often have RPC commands that fall within +some general scopes of action (see enum fwctl_rpc_scope): + + 1. Access to function & child configuration, FLASH, etc. that becomes live at a + function reset. Access to function & child runtime configuration that is + transparent or non-disruptive to any driver or VM. + + 2. Read-only access to function debug information that may report on FW objects + in the function & child, including FW objects owned by other kernel + subsystems. + + 3. Write access to function & child debug information strictly compatible with + the principles of kernel lockdown and kernel integrity protection. Triggers + a kernel Taint. + + 4. Full debug device access. Triggers a kernel Taint, requires CAP_SYS_RAWIO. + +User space will provide a scope label on each RPC and the kernel must enforce the +above CAPs and taints based on that scope. A combination of kernel and FW can +enforce that RPCs are placed in the correct scope by user space. + +Denied behavior +--------------- + +There are many things this interface must not allow user space to do (without a +Taint or CAP), broadly derived from the principles of kernel lockdown. Some +examples: + + 1. DMA to/from arbitrary memory, hang the system, compromise FW integrity with + untrusted code, or otherwise compromise device or system security and + integrity. + + 2. Provide an abnormal “back door” to kernel drivers. No manipulation of kernel + objects owned by kernel drivers. + + 3. Directly configure or otherwise control kernel drivers. A subsystem kernel + driver can react to the device configuration at function reset/driver load + time, but otherwise must not be coupled to fwctl. + + 4. Operate the HW in a way that overlaps with the core purpose of another + primary kernel subsystem, such as read/write to LBAs, send/receive of + network packets, or operate an accelerator's data plane. + +fwctl is not a replacement for device direct access subsystems like uacce or +VFIO. + +Operations exposed through fwctl's non-taining interfaces should be fully +sharable with other users of the device. For instance exposing a RPC through +fwctl should never prevent a kernel subsystem from also concurrently using that +same RPC or hardware unit down the road. In such cases fwctl will be less +important than proper kernel subsystems that eventually emerge. Mistakes in this +area resulting in clashes will be resolved in favour of a kernel implementation. + +fwctl User API +============== + +.. kernel-doc:: include/uapi/fwctl/fwctl.h + +sysfs Class +----------- + +fwctl has a sysfs class (/sys/class/fwctl/fwctlNN/) and character devices +(/dev/fwctl/fwctlNN) with a simple numbered scheme. The character device +operates the iotcl uAPI described above. + +fwctl devices can be related to driver components in other subsystems through +sysfs:: + + $ ls /sys/class/fwctl/fwctl0/device/infiniband/ + ibp0s10f0 + + $ ls /sys/class/infiniband/ibp0s10f0/device/fwctl/ + fwctl0/ + + $ ls /sys/devices/pci0000:00/0000:00:0a.0/fwctl/fwctl0 + dev device power subsystem uevent + +User space Community +-------------------- + +Drawing inspiration from nvme-cli, participating in the kernel side must come +with a user space in a common TBD git tree, at a minimum to usefully operate the +kernel driver. Providing such an implementation is a pre-condition to merging a +kernel driver. + +The goal is to build user space community around some of the shared problems +we all have, and ideally develop some common user space programs with some +starting themes of: + + - Device in-field debugging + + - HW provisioning + + - VFIO child device profiling before VM boot + + - Confidential Compute topics (attestation, secure provisioning) + +that stretch across all subsystems in the kernel. fwupd is a great example of +how an excellent user space experience can emerge out of kernel-side diversity. + +fwctl Kernel API +================ + +.. kernel-doc:: drivers/fwctl/main.c + :export: +.. kernel-doc:: include/linux/fwctl.h + +fwctl Driver design +------------------- + +In many cases a fwctl driver is going to be part of a larger cross-subsystem +device possibly using the auxiliary_device mechanism. In that case several +subsystems are going to be sharing the same device and FW interface layer so the +device design must already provide for isolation and cooperation between kernel +subsystems. fwctl should fit into that same model. + +Part of the driver should include a description of how its scope restrictions +and security model work. The driver and FW together must ensure that RPCs +provided by user space are mapped to the appropriate scope. If the validation is +done in the driver then the validation can read a 'command effects' report from +the device, or hardwire the enforcement. If the validation is done in the FW, +then the driver should pass the fwctl_rpc_scope to the FW along with the command. + +The driver and FW must cooperate to ensure that either fwctl cannot allocate +any FW resources, or any resources it does allocate are freed on FD closure. A +driver primarily constructed around FW RPCs may find that its core PCI function +and RPC layer belongs under fwctl with auxiliary devices connecting to other +subsystems. + +Each device type must be mindful of Linux's philosophy for stable ABI. The FW +RPC interface does not have to meet a strictly stable ABI, but it does need to +meet an expectation that userspace tools that are deployed and in significant +use don't needlessly break. FW upgrade and kernel upgrade should keep widely +deployed tooling working. + +Development and debugging focused RPCs under more permissive scopes can have +less stabilitiy if the tools using them are only run under exceptional +circumstances and not for every day use of the device. Debugging tools may even +require exact version matching as they may require something similar to DWARF +debug information from the FW binary. + +Security Response +================= + +The kernel remains the gatekeeper for this interface. If violations of the +scopes, security or isolation principles are found, we have options to let +devices fix them with a FW update, push a kernel patch to parse and block RPC +commands or push a kernel patch to block entire firmware versions/devices. + +While the kernel can always directly parse and restrict RPCs, it is expected +that the existing kernel pattern of allowing drivers to delegate validation to +FW to be a useful design. + +Existing Similar Examples +========================= + +The approach described in this document is not a new idea. Direct, or near +direct device access has been offered by the kernel in different areas for +decades. With more devices wanting to follow this design pattern it is becoming +clear that it is not entirely well understood and, more importantly, the +security considerations are not well defined or agreed upon. + +Some examples: + + - HW RAID controllers. This includes RPCs to do things like compose drives into + a RAID volume, configure RAID parameters, monitor the HW and more. + + - Baseboard managers. RPCs for configuring settings in the device and more + + - NVMe vendor command capsules. nvme-cli provides access to some monitoring + functions that different products have defined, but more exist. + + - CXL also has a NVMe-like vendor command system. + + - DRM allows user space drivers to send commands to the device via kernel + mediation + + - RDMA allows user space drivers to directly push commands to the device + without kernel involvement + + - Various “raw” APIs, raw HID (SDL2), raw USB, NVMe Generic Interface, etc. + +The first 4 are examples of areas that fwctl intends to cover. The latter three +are examples of denied behavior as they fully overlap with the primary purpose +of a kernel subsystem. + +Some key lessons learned from these past efforts are the importance of having a +common user space project to use as a pre-condition for obtaining a kernel +driver. Developing good community around useful software in user space is key to +getting companies to fund participation to enable their products. diff --git a/Documentation/userspace-api/fwctl/index.rst b/Documentation/userspace-api/fwctl/index.rst new file mode 100644 index 000000000000..06959fbf1547 --- /dev/null +++ b/Documentation/userspace-api/fwctl/index.rst @@ -0,0 +1,12 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Firmware Control (FWCTL) Userspace API +====================================== + +A framework that define a common set of limited rules that allows user space +to securely construct and execute RPCs inside device firmware. + +.. toctree:: + :maxdepth: 1 + + fwctl diff --git a/Documentation/userspace-api/index.rst b/Documentation/userspace-api/index.rst index 72a65db0c498..2125bb520e52 100644 --- a/Documentation/userspace-api/index.rst +++ b/Documentation/userspace-api/index.rst @@ -26,6 +26,7 @@ place where this information is gathered. ELF ioctl/index iommu + fwctl/index iommufd media/index netlink/index diff --git a/MAINTAINERS b/MAINTAINERS index cd3481849a04..cac72e421f1a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8646,6 +8646,7 @@ M: Jason Gunthorpe M: Saeed Mahameed R: Jonathan Cameron S: Maintained +F: Documentation/userspace-api/fwctl/ F: drivers/fwctl/ F: include/linux/fwctl.h F: include/uapi/fwctl/ -- Gitee From 731e27c0a60c0db9e8997ea1642d19ff34a6e35a Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Tue, 8 Apr 2025 15:33:00 -0700 Subject: [PATCH 028/103] fwctl: Fix repeated device word in log message [Upstream commit c92ae5d4f53ebf9c32ace69c1f89a47e8714d18b] Remove the repeated word "device" from a dev_warn() message. Link: https://patch.msgid.link/r/20250408223300.24561-1-shannon.nelson@amd.com Signed-off-by: Shannon Nelson Reviewed-by: Dave Jiang Signed-off-by: Jason Gunthorpe Signed-off-by: huwentao --- drivers/fwctl/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/fwctl/main.c b/drivers/fwctl/main.c index c783e94c9c65..7854ab0369f2 100644 --- a/drivers/fwctl/main.c +++ b/drivers/fwctl/main.c @@ -105,7 +105,7 @@ static int fwctl_cmd_rpc(struct fwctl_ucmd *ucmd) if (!test_and_set_bit(0, &fwctl_tainted)) { dev_warn( &fwctl->dev, - "%s(%d): has requested full access to the physical device device", + "%s(%d): has requested full access to the physical device", current->comm, task_pid_nr(current)); add_taint(TAINT_FWCTL, LOCKDEP_STILL_OK); } -- Gitee From 0d9fa1760e985d72c2b7cece2366494c1400c440 Mon Sep 17 00:00:00 2001 From: Jiaqi Cheng Date: Thu, 14 Aug 2025 16:53:23 +0800 Subject: [PATCH 029/103] ub: ub_fwctl: Add the ub_fwctl driver and its basic features. commit aabc3d6533494ed9a3ace44576d03572746f91cd openEuler Add support for the loading and unloading of ub_fwctl drivers. ub_fwctl drv supports Auxiliary devices. ub_fwctl drv adaptation to fwctl framework. The ub_fwctl driver needs to impose traffic restrictions on the ioctl command to prevent the occurrence of CMDQ storms. Signed-off-by: Jiaqi Cheng Signed-off-by: huwentao --- arch/arm64/configs/tencent.config | 4 + drivers/fwctl/Kconfig | 10 ++ drivers/fwctl/Makefile | 1 + drivers/fwctl/ub/Makefile | 4 + drivers/fwctl/ub/main.c | 215 ++++++++++++++++++++++++++++++ drivers/fwctl/ub/ub_cmd_reg.c | 26 ++++ drivers/fwctl/ub/ub_cmd_reg.h | 13 ++ drivers/fwctl/ub/ub_common.h | 58 ++++++++ include/uapi/fwctl/fwctl.h | 1 + include/uapi/fwctl/ub_fwctl.h | 43 ++++++ 10 files changed, 375 insertions(+) create mode 100644 drivers/fwctl/ub/Makefile create mode 100644 drivers/fwctl/ub/main.c create mode 100644 drivers/fwctl/ub/ub_cmd_reg.c create mode 100644 drivers/fwctl/ub/ub_cmd_reg.h create mode 100644 drivers/fwctl/ub/ub_common.h create mode 100644 include/uapi/fwctl/ub_fwctl.h diff --git a/arch/arm64/configs/tencent.config b/arch/arm64/configs/tencent.config index 63cfddd36d14..d122f864bc43 100644 --- a/arch/arm64/configs/tencent.config +++ b/arch/arm64/configs/tencent.config @@ -1866,3 +1866,7 @@ CONFIG_VFIO_DEVICE_CDEV=y # fwctl CONFIG_FWCTL=y + +# UB_FWCTL +CONFIG_FWCTL_UB=m +# end of UB_FWCTL diff --git a/drivers/fwctl/Kconfig b/drivers/fwctl/Kconfig index 37147a695add..24c3c83437a0 100644 --- a/drivers/fwctl/Kconfig +++ b/drivers/fwctl/Kconfig @@ -7,3 +7,13 @@ menuconfig FWCTL support a wide range of lockdown compatible device behaviors including manipulating device FLASH, debugging, and other activities that don't fit neatly into an existing subsystem. + +if FWCTL +config FWCTL_UB + tristate "ub_fwctl depend on fwctl driver" + help + ub_fwctl provides users with various information related to + querying UB (UnifiedBus) registers or devices. + + If you don't know what to do here, say N. +endif diff --git a/drivers/fwctl/Makefile b/drivers/fwctl/Makefile index 1cad210f6ba5..9005cdf31dfd 100644 --- a/drivers/fwctl/Makefile +++ b/drivers/fwctl/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_FWCTL) += fwctl.o +obj-$(CONFIG_FWCTL_UB) += ub/ fwctl-y += main.o diff --git a/drivers/fwctl/ub/Makefile b/drivers/fwctl/ub/Makefile new file mode 100644 index 000000000000..a6669814dbbf --- /dev/null +++ b/drivers/fwctl/ub/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0+ +obj-$(CONFIG_FWCTL_UB) += ub_fwctl.o + +ub_fwctl-y += main.o ub_cmd_reg.o diff --git a/drivers/fwctl/ub/main.c b/drivers/fwctl/ub/main.c new file mode 100644 index 000000000000..63de07d5d028 --- /dev/null +++ b/drivers/fwctl/ub/main.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. + */ + +#include +#include +#include +#include + +#include "ub_common.h" +#include "ub_cmd_reg.h" + +#define MAX_IOCTL_COUNT 1024 +#define TIME_WINDOW_MS 3000 +#define TIME_WINDOW_JIFFIES msecs_to_jiffies(TIME_WINDOW_MS) + +struct ubctl_uctx { + struct fwctl_uctx uctx; +}; + +static int ubctl_open_uctx(struct fwctl_uctx *uctx) +{ + return 0; +} + +static void ubctl_close_uctx(struct fwctl_uctx *uctx) +{ + +} + +static void *ubctl_fw_info(struct fwctl_uctx *uctx, size_t *length) +{ + return NULL; +} + +static int ubctl_legitimacy_rpc(struct ubctl_dev *ucdev, size_t out_len, + enum fwctl_rpc_scope scope) +{ + /* + * Verify if RPC (Remote Procedure Call) requests are valid. + * It determines whether the request is within the allowed time window + * and whether the output length meets the requirements by checking + * the timestamp and output length of the request. + */ + unsigned long current_jiffies = jiffies; + unsigned long earliest_jiffies = current_jiffies - TIME_WINDOW_JIFFIES; + unsigned long record_jiffies = 0; + int kfifo_ret = 0; + + while (kfifo_peek(&ucdev->ioctl_fifo, &record_jiffies) && record_jiffies) { + if (time_after(record_jiffies, earliest_jiffies)) + break; + + kfifo_ret = kfifo_get(&ucdev->ioctl_fifo, &record_jiffies); + if (!kfifo_ret) { + ubctl_err(ucdev, "unexpected events occurred while obtaining data.\n"); + return kfifo_ret; + } + } + + if (kfifo_is_full(&ucdev->ioctl_fifo)) { + ubctl_err(ucdev, "the current number of valid requests exceeds the limit.\n"); + return -EBADMSG; + } + + kfifo_ret = kfifo_put(&ucdev->ioctl_fifo, current_jiffies); + if (!kfifo_ret) { + ubctl_err(ucdev, "unexpected events occurred while writing data.\n"); + return kfifo_ret; + } + + if (out_len < sizeof(struct fwctl_rpc_ub_out)) { + ubctl_dbg(ucdev, "outlen %zu is less than min value %zu.\n", + out_len, sizeof(struct fwctl_rpc_ub_out)); + return -EBADMSG; + } + + if (scope != FWCTL_RPC_CONFIGURATION && + scope != FWCTL_RPC_DEBUG_READ_ONLY) + return -EOPNOTSUPP; + + return 0; +} + +static int ubctl_cmd_err(struct ubctl_dev *ucdev, int ret, struct fwctl_rpc_ub_out *out) +{ + /* Keep rpc_out as contains useful debug info for userspace */ + if (!ret || out->retval) + return 0; + + return ret; +} + +static int ub_cmd_do(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param) +{ + u32 rpc_cmd = query_cmd_param->in->rpc_cmd; + struct ubctl_func_dispatch *ubctl_query_reg = ubctl_get_query_reg_func( + ucdev, rpc_cmd); + int ret; + + if (ubctl_query_reg && ubctl_query_reg->execute) { + ret = ubctl_query_reg->execute(ucdev, query_cmd_param, + ubctl_query_reg); + } else { + ubctl_err(ucdev, "No corresponding query was found.\n"); + return -EINVAL; + } + + return ubctl_cmd_err(ucdev, ret, query_cmd_param->out); +} + +static void *ubctl_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope, + void *rpc_in, size_t in_len, size_t *out_len) +{ + struct ubctl_dev *ucdev = container_of(uctx->fwctl, struct ubctl_dev, + fwctl); + u32 opcode = ((struct fwctl_rpc_ub_in *)rpc_in)->rpc_cmd; + struct ubctl_query_cmd_param query_cmd_param; + void *rpc_out; + int ret; + + ubctl_dbg(ucdev, "cmdif: opcode 0x%x inlen %zu outlen %zu\n", + opcode, in_len, *out_len); + + ret = ubctl_legitimacy_rpc(ucdev, *out_len, scope); + if (ret) + return ERR_PTR(ret); + + rpc_out = kvzalloc(*out_len, GFP_KERNEL); + if (!rpc_out) + return ERR_PTR(-ENOMEM); + + query_cmd_param.out = rpc_out; + query_cmd_param.in = rpc_in; + query_cmd_param.out_len = *out_len - offsetof(struct fwctl_rpc_ub_out, data); + query_cmd_param.in_len = in_len; + + ret = ub_cmd_do(ucdev, &query_cmd_param); + + ubctl_dbg(ucdev, "cmdif: opcode 0x%x retval %d\n", opcode, ret); + + return rpc_out; +} + +static const struct fwctl_ops ubctl_ops = { + .device_type = FWCTL_DEVICE_TYPE_UB, + .uctx_size = sizeof(struct ubctl_uctx), + .open_uctx = ubctl_open_uctx, + .close_uctx = ubctl_close_uctx, + .info = ubctl_fw_info, + .fw_rpc = ubctl_fw_rpc, +}; + +DEFINE_FREE(ubctl, struct ubctl_dev *, if (_T) fwctl_put(&_T->fwctl)) + +static int ubctl_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct ubctl_dev *ucdev __free(ubctl) = fwctl_alloc_device( + adev->dev.parent, &ubctl_ops, struct ubctl_dev, fwctl); + int ret; + + if (!ucdev) + return -ENOMEM; + + ret = kfifo_alloc(&ucdev->ioctl_fifo, MAX_IOCTL_COUNT, GFP_KERNEL); + if (ret) { + ubctl_err(ucdev, "kfifo alloc device failed, retval = %d.\n", ret); + return -ENOMEM; + } + + ret = fwctl_register(&ucdev->fwctl); + if (ret) { + ubctl_err(ucdev, "fwctl register failed, retval = %d.\n", ret); + kfifo_free(&ucdev->ioctl_fifo); + return ret; + } + + ucdev->adev = adev; + auxiliary_set_drvdata(adev, no_free_ptr(ucdev)); + return 0; +} + +static void ubctl_remove(struct auxiliary_device *adev) +{ + struct ubctl_dev *ucdev = auxiliary_get_drvdata(adev); + + fwctl_unregister(&ucdev->fwctl); + kfifo_free(&ucdev->ioctl_fifo); + fwctl_put(&ucdev->fwctl); +} + +static const struct auxiliary_device_id ubctl_id_table[] = { + { + .name = "ubase.fwctl", + }, + {} +}; +MODULE_DEVICE_TABLE(auxiliary, ubctl_id_table); + +static struct auxiliary_driver ubctl_driver = { + .name = "ub_fwctl", + .probe = ubctl_probe, + .remove = ubctl_remove, + .id_table = ubctl_id_table, +}; + +module_auxiliary_driver(ubctl_driver); + +MODULE_IMPORT_NS(FWCTL); +MODULE_DESCRIPTION("UB fwctl driver"); +MODULE_AUTHOR("HiSilicon Tech. Co., Ltd."); +MODULE_LICENSE("GPL"); diff --git a/drivers/fwctl/ub/ub_cmd_reg.c b/drivers/fwctl/ub/ub_cmd_reg.c new file mode 100644 index 000000000000..61caefa7c06e --- /dev/null +++ b/drivers/fwctl/ub/ub_cmd_reg.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. + */ + +#include "ub_cmd_reg.h" + +static struct ubctl_func_dispatch g_ubctl_query_reg[] = { + { UTOOL_CMD_QUERY_MAX, NULL, NULL } +}; + +struct ubctl_func_dispatch *ubctl_get_query_reg_func(struct ubctl_dev *ucdev, + u32 rpc_cmd) +{ + u32 i; + + if (!ucdev) + return NULL; + + for (i = 0; i < ARRAY_SIZE(g_ubctl_query_reg); i++) { + if (g_ubctl_query_reg[i].rpc_cmd == rpc_cmd) + return &g_ubctl_query_reg[i]; + } + + return NULL; +} diff --git a/drivers/fwctl/ub/ub_cmd_reg.h b/drivers/fwctl/ub/ub_cmd_reg.h new file mode 100644 index 000000000000..87b3e0183cd9 --- /dev/null +++ b/drivers/fwctl/ub/ub_cmd_reg.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. 2025-2025. All rights reserved. + */ + +#ifndef __UB_CMD_REG_H__ +#define __UB_CMD_REG_H__ + +#include "ub_common.h" + +struct ubctl_func_dispatch *ubctl_get_query_reg_func(struct ubctl_dev *ucdev, + u32 rpc_cmd); +#endif diff --git a/drivers/fwctl/ub/ub_common.h b/drivers/fwctl/ub/ub_common.h new file mode 100644 index 000000000000..7eef8a6ca937 --- /dev/null +++ b/drivers/fwctl/ub/ub_common.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. + */ + +#ifndef __UB_COMMAND_H__ +#define __UB_COMMAND_H__ + +#include +#include +#include + +#include + +#define ubctl_err(ucdev, format, ...) \ + dev_err(&ucdev->fwctl.dev, format, ##__VA_ARGS__) + +#define ubctl_dbg(ucdev, format, ...) \ + dev_dbg(&ucdev->fwctl.dev, "PID %u: " format, current->pid, \ + ##__VA_ARGS__) + +#define ubctl_info(ucdev, format, ...) \ + dev_info(&ucdev->fwctl.dev, "PID %u: " format, current->pid, \ + ##__VA_ARGS__) + +struct ubctl_dev { + struct fwctl_device fwctl; + DECLARE_KFIFO_PTR(ioctl_fifo, unsigned long); + struct auxiliary_device *adev; +}; + +struct ubctl_query_cmd_param { + size_t in_len; + struct fwctl_rpc_ub_in *in; + size_t out_len; + struct fwctl_rpc_ub_out *out; +}; + +struct ubctl_cmd { + u32 op_code; + u32 is_read; + u32 in_len; + u32 out_len; + void *in_data; + void *out_data; +}; + +struct ubctl_func_dispatch { + u32 rpc_cmd; + int (*execute)(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func); + int (*data_deal)(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_cmd *cmd, u32 out_len, u32 offset_index); +}; + +#endif diff --git a/include/uapi/fwctl/fwctl.h b/include/uapi/fwctl/fwctl.h index 0bec798790a6..bddd8d19695c 100644 --- a/include/uapi/fwctl/fwctl.h +++ b/include/uapi/fwctl/fwctl.h @@ -42,6 +42,7 @@ enum { enum fwctl_device_type { FWCTL_DEVICE_TYPE_ERROR = 0, + FWCTL_DEVICE_TYPE_UB = 5, }; /** diff --git a/include/uapi/fwctl/ub_fwctl.h b/include/uapi/fwctl/ub_fwctl.h new file mode 100644 index 000000000000..e534f22cf146 --- /dev/null +++ b/include/uapi/fwctl/ub_fwctl.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note*/ +/* + * Copyright(c) 2025 HiSilicon Technologies CO., Limited. All rights reserved. + */ + +#ifndef _UAPI_UB_FWCTL_H_ +#define _UAPI_UB_FWCTL_H_ + +#include + +/** + * struct fwctl_rpc_ub_in - ioctl(FWCTL_RPC) input + * @rpc_cmd: user specified opcode + * @data_size: Length of @data + * @version: Version passed in by the user + * @rsvd: reserved + * @data: user inputs specified input data + */ +struct fwctl_rpc_ub_in { + __u32 rpc_cmd; + __u32 data_size; + __u32 version; + __u32 rsvd; + __u32 data[] __counted_by(data_size); +}; + +/** + * struct fwctl_rpc_ub_out - ioctl(FWCTL_RPC) output + * @retval: The value returned when querying data with an error message + * @data_size: Length of @data + * @data: data transmitted to users + */ +struct fwctl_rpc_ub_out { + int retval; + __u32 data_size; + __u32 data[]; +}; + +enum ub_fwctl_cmdrpc_type { + UTOOL_CMD_QUERY_MAX, +}; + +#endif -- Gitee From 27807fe5083d2709994f1102f99b7d427b803ccc Mon Sep 17 00:00:00 2001 From: Jiaqi Cheng Date: Thu, 21 Aug 2025 14:38:11 +0800 Subject: [PATCH 030/103] ub: ub_fwctl: Add some simple common framework functions commit fe9e7907e911ee1469da9ee52535d1b0b61bdb3a openEuler Ub_fwctl adds some simple common framework functions, mainly to assemble data structures that interact with software, call software query interaction functions, and return the queried data to user mode and other main functions. Added a basic feature: support querying NL(Network Layer) statistical register information Signed-off-by: Jiaqi Cheng Signed-off-by: huwentao --- drivers/fwctl/Kconfig | 2 + drivers/fwctl/ub/Makefile | 2 +- drivers/fwctl/ub/ub_cmd_reg.c | 16 +++ drivers/fwctl/ub/ub_cmdq.h | 13 +++ drivers/fwctl/ub/ub_common.c | 197 ++++++++++++++++++++++++++++++++++ drivers/fwctl/ub/ub_common.h | 28 +++++ include/uapi/fwctl/ub_fwctl.h | 2 + 7 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 drivers/fwctl/ub/ub_cmdq.h create mode 100644 drivers/fwctl/ub/ub_common.c diff --git a/drivers/fwctl/Kconfig b/drivers/fwctl/Kconfig index 24c3c83437a0..88b346631ebe 100644 --- a/drivers/fwctl/Kconfig +++ b/drivers/fwctl/Kconfig @@ -11,6 +11,8 @@ menuconfig FWCTL if FWCTL config FWCTL_UB tristate "ub_fwctl depend on fwctl driver" + depends on UB_UBASE + default n help ub_fwctl provides users with various information related to querying UB (UnifiedBus) registers or devices. diff --git a/drivers/fwctl/ub/Makefile b/drivers/fwctl/ub/Makefile index a6669814dbbf..c2c2008b2653 100644 --- a/drivers/fwctl/ub/Makefile +++ b/drivers/fwctl/ub/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0+ obj-$(CONFIG_FWCTL_UB) += ub_fwctl.o -ub_fwctl-y += main.o ub_cmd_reg.o +ub_fwctl-y += main.o ub_cmd_reg.o ub_common.o diff --git a/drivers/fwctl/ub/ub_cmd_reg.c b/drivers/fwctl/ub/ub_cmd_reg.c index 61caefa7c06e..3154d7f10a35 100644 --- a/drivers/fwctl/ub/ub_cmd_reg.c +++ b/drivers/fwctl/ub/ub_cmd_reg.c @@ -3,9 +3,25 @@ * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ +#include "ub_cmdq.h" #include "ub_cmd_reg.h" +static int ubctl_query_nl_pkt_stats_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_NL_PKT_STATS_DFX, UBCTL_NL_PKT_STATS_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + static struct ubctl_func_dispatch g_ubctl_query_reg[] = { + { UTOOL_CMD_QUERY_NL_PKT_STATS, ubctl_query_nl_pkt_stats_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_MAX, NULL, NULL } }; diff --git a/drivers/fwctl/ub/ub_cmdq.h b/drivers/fwctl/ub/ub_cmdq.h new file mode 100644 index 000000000000..05db6aa07d5b --- /dev/null +++ b/drivers/fwctl/ub/ub_cmdq.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. + */ + +#ifndef __UB_CMDQ_H__ +#define __UB_CMDQ_H__ + +#define UBCTL_QUERY_NL_PKT_STATS_DFX 0xA001 + +#define UBCTL_NL_PKT_STATS_LEN 632 + +#endif diff --git a/drivers/fwctl/ub/ub_common.c b/drivers/fwctl/ub/ub_common.c new file mode 100644 index 000000000000..87654eb0aefc --- /dev/null +++ b/drivers/fwctl/ub/ub_common.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. 2025-2025. All rights reserved. + */ + +#include + +#include "ub_common.h" + +static inline void ubctl_struct_cpu_to_le32(u32 *data, u32 cnt) +{ + for (u32 i = 0; i < cnt; i++) + data[i] = cpu_to_le32(data[i]); +} + +static inline void ubctl_struct_le32_to_cpu(u32 *data, u32 cnt) +{ + for (u32 i = 0; i < cnt; i++) + data[i] = le32_to_cpu(data[i]); +} + +static inline int ubctl_ubase_cmd_send_param_check(struct auxiliary_device *adev, + struct ubctl_cmd *cmd) +{ + if (!adev || !cmd) + return -EINVAL; + + if (!cmd->in_data || !cmd->out_data) + return -EINVAL; + + return 0; +} + +int ubctl_ubase_cmd_send(struct auxiliary_device *adev, struct ubctl_cmd *cmd) +{ + struct ubase_cmd_buf in, out; + int ret; + + if (ubctl_ubase_cmd_send_param_check(adev, cmd)) + return -EINVAL; + + ubctl_struct_cpu_to_le32(cmd->in_data, cmd->in_len / sizeof(u32)); + ubase_fill_inout_buf(&in, cmd->op_code, cmd->is_read, cmd->in_len, + cmd->in_data); + ubase_fill_inout_buf(&out, cmd->op_code, cmd->is_read, cmd->out_len, + cmd->out_data); + + ret = ubase_cmd_send_inout(adev, &in, &out); + if (ret) + return ret; + + ubctl_struct_le32_to_cpu(cmd->out_data, cmd->out_len / sizeof(u32)); + + return 0; +} + +int ubctl_fill_cmd(struct ubctl_cmd *cmd, void *cmd_in, void *cmd_out, + u32 out_len, u32 is_read) +{ + if (!cmd || !cmd_in || !cmd_out) + return -EINVAL; + + cmd->is_read = is_read; + cmd->in_data = cmd_in; + cmd->out_data = cmd_out; + cmd->in_len = out_len; + cmd->out_len = out_len; + + return 0; +} + +static int ubctl_query_param_check(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func, + struct ubctl_query_dp *query_dp) +{ + if (!ucdev || !query_cmd_param || !query_func || !query_dp) + return -EINVAL; + + if (!query_cmd_param->in || !query_cmd_param->out) { + ubctl_err(ucdev, "ubctl in or out is null.\n"); + return -EINVAL; + } + + if (!query_func->data_deal) { + ubctl_err(ucdev, "ubctl data deal func is null.\n"); + return -EINVAL; + } + + return 0; +} + +static int ubctl_cmd_send_deal(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_query_dp *query_dp, + struct ubctl_query_cmd_dp *cmd_data, u32 offset) +{ + int *retval = &query_cmd_param->out->retval; + struct ubctl_cmd cmd = {}; + int ret = 0; + + cmd.op_code = query_dp->op_code; + ret = ubctl_fill_cmd(&cmd, cmd_data->cmd_in, cmd_data->cmd_out, + query_dp->out_len, query_dp->is_read); + if (ret) { + ubctl_err(ucdev, "ubctl fill cmd failed.\n"); + return ret; + } + + *retval = ubctl_ubase_cmd_send(ucdev->adev, &cmd); + if (*retval) { + ubctl_err(ucdev, "ubctl ubase cmd send failed, retval = %d.\n", + *retval); + return -EINVAL; + } + + ret = cmd_data->query_func->data_deal(ucdev, query_cmd_param, &cmd, + query_dp->out_len, offset); + if (ret) + ubctl_err(ucdev, "ubctl data deal failed, ret = %d.\n", ret); + + return ret; +} + +int ubctl_query_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func, + struct ubctl_query_dp *query_dp, u32 query_dp_num) +{ + u32 offset = 0; + int ret = 0; + u32 i; + + ret = ubctl_query_param_check(ucdev, query_cmd_param, query_func, query_dp); + if (ret) { + ubctl_err(ucdev, "ubctl query param check failed, ret = %d.\n", ret); + return ret; + } + + for (i = 0; i < query_dp_num; i++) { + if (query_cmd_param->in->data_size > query_dp[i].out_len) { + ubctl_err(ucdev, "ubctl in data size is bigger than out len.\n"); + return -EINVAL; + } + + void *cmd_in __free(kvfree) = kvzalloc(query_dp[i].out_len, GFP_KERNEL); + if (!cmd_in) + return -ENOMEM; + + void *cmd_out __free(kvfree) = kvzalloc(query_dp[i].out_len, GFP_KERNEL); + if (!cmd_out) + return -ENOMEM; + + struct ubctl_query_cmd_dp cmd_dp = (struct ubctl_query_cmd_dp) { + .cmd_in = cmd_in, + .cmd_out = cmd_out, + .query_func = query_func, + }; + + memcpy(cmd_dp.cmd_in, query_cmd_param->in->data, query_cmd_param->in->data_size); + ret = ubctl_cmd_send_deal(ucdev, query_cmd_param, &query_dp[i], + &cmd_dp, offset); + if (ret) + return ret; + + offset += query_dp[i].out_len / sizeof(u32); + } + return 0; +} + +int ubctl_query_data_deal(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_cmd *cmd, u32 out_len, u32 offset) +{ + if (!ucdev || !query_cmd_param || !cmd) + return -EINVAL; + + if (!query_cmd_param->in || !query_cmd_param->out) { + ubctl_err(ucdev, "ubctl in or out is null.\n"); + return -EINVAL; + } + + if (cmd->out_len != out_len) { + ubctl_err(ucdev, "out data size is not equal to out len.\n"); + return -EINVAL; + } + + if ((offset * (u32)sizeof(u32) + out_len) > query_cmd_param->out_len) { + ubctl_err(ucdev, "offset size is bigger than user out len.\n"); + return -EINVAL; + } + + memcpy(&query_cmd_param->out->data[offset], cmd->out_data, cmd->out_len); + query_cmd_param->out->data_size += cmd->out_len; + + return 0; +} diff --git a/drivers/fwctl/ub/ub_common.h b/drivers/fwctl/ub/ub_common.h index 7eef8a6ca937..0eda05fc5932 100644 --- a/drivers/fwctl/ub/ub_common.h +++ b/drivers/fwctl/ub/ub_common.h @@ -12,6 +12,8 @@ #include +#define UBCTL_READ true + #define ubctl_err(ucdev, format, ...) \ dev_err(&ucdev->fwctl.dev, format, ##__VA_ARGS__) @@ -55,4 +57,30 @@ struct ubctl_func_dispatch { struct ubctl_cmd *cmd, u32 out_len, u32 offset_index); }; +struct ubctl_query_dp { + u32 op_code; + u32 out_len; + bool is_read; + void *data; + u32 data_len; +}; + +struct ubctl_query_cmd_dp { + struct ubctl_func_dispatch *query_func; + void *cmd_in; + void *cmd_out; +}; + +int ubctl_ubase_cmd_send(struct auxiliary_device *adev, + struct ubctl_cmd *cmd); +int ubctl_fill_cmd(struct ubctl_cmd *cmd, void *cmd_in, void *cmd_out, + u32 out_len, u32 is_read); +int ubctl_query_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func, + struct ubctl_query_dp *query_dp, u32 query_dp_num); +int ubctl_query_data_deal(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_cmd *cmd, u32 out_len, u32 offset); + #endif diff --git a/include/uapi/fwctl/ub_fwctl.h b/include/uapi/fwctl/ub_fwctl.h index e534f22cf146..011c4d48bada 100644 --- a/include/uapi/fwctl/ub_fwctl.h +++ b/include/uapi/fwctl/ub_fwctl.h @@ -37,6 +37,8 @@ struct fwctl_rpc_ub_out { }; enum ub_fwctl_cmdrpc_type { + UTOOL_CMD_QUERY_NL_PKT_STATS = 0x0002, + UTOOL_CMD_QUERY_MAX, }; -- Gitee From 06106b1a7ab37057ac87ebc0e2330ca0455b3108 Mon Sep 17 00:00:00 2001 From: Jiaqi Cheng Date: Thu, 21 Aug 2025 15:02:31 +0800 Subject: [PATCH 031/103] ub: ub_fwctl: supports querying NL, TA, DL related register information commit 7607eafee2394d691fe29632a217e8371feec2ce openEuler 1. Support querying NL SSU related register information, and exception message statistical register information. 2. Support querying TA(Transaction Layer) layer statistical register information and abnormal message statistical register information. 3. Support querying DL(Data Link&Physical Layer) statistical register information, port link status, lane information, port error rate, BIST testing. Signed-off-by: Jiaqi Cheng Signed-off-by: huwentao --- drivers/fwctl/ub/ub_cmd_reg.c | 202 ++++++++++++++++++++++++++++++++++ drivers/fwctl/ub/ub_cmdq.h | 26 +++++ drivers/fwctl/ub/ub_common.h | 1 + include/uapi/fwctl/ub_fwctl.h | 16 +++ 4 files changed, 245 insertions(+) diff --git a/drivers/fwctl/ub/ub_cmd_reg.c b/drivers/fwctl/ub/ub_cmd_reg.c index 3154d7f10a35..17a695a81c0b 100644 --- a/drivers/fwctl/ub/ub_cmd_reg.c +++ b/drivers/fwctl/ub/ub_cmd_reg.c @@ -6,6 +6,20 @@ #include "ub_cmdq.h" #include "ub_cmd_reg.h" +static int ubctl_query_nl_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_NL_PKT_STATS_DFX, UBCTL_NL_PKT_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_NL_SSU_STATS_DFX, UBCTL_NL_SSU_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_NL_ABN_DFX, UBCTL_NL_ABN_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + static int ubctl_query_nl_pkt_stats_data(struct ubctl_dev *ucdev, struct ubctl_query_cmd_param *query_cmd_param, struct ubctl_func_dispatch *query_func) @@ -18,9 +32,197 @@ static int ubctl_query_nl_pkt_stats_data(struct ubctl_dev *ucdev, query_dp, ARRAY_SIZE(query_dp)); } +static int ubctl_query_nl_ssu_stats_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_NL_SSU_STATS_DFX, UBCTL_NL_SSU_STATS_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_nl_abn_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_NL_ABN_DFX, UBCTL_NL_ABN_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_dl_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_DL_PKT_STATS_DFX, UBCTL_DL_PKT_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_DL_REPL_DFX, UBCTL_DL_REPL_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_DL_LINK_STATUS_DFX, UBCTL_DL_LINK_STATUS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_DL_LANE_DFX, UBCTL_DL_LANE_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_DL_BIT_ERR_DFX, UBCTL_DL_BIT_ERR_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_dl_pkt_stats_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_DL_PKT_STATS_DFX, UBCTL_DL_PKT_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_DL_REPL_DFX, UBCTL_DL_REPL_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_dl_link_status_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_DL_LINK_STATUS_DFX, UBCTL_DL_LINK_STATUS_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_dl_lane_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_DL_LANE_DFX, UBCTL_DL_LANE_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_dl_bit_err_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_DL_BIT_ERR_DFX, UBCTL_DL_BIT_ERR_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_dl_bist_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_CONF_DL_BIST_DFX, UBCTL_DL_BIST_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_conf_dl_bist_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_CONF_DL_BIST_DFX, UBCTL_DL_BIST_LEN, UBCTL_WRITE, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_dl_bist_err_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_DL_BIST_ERR_DFX, UBCTL_DL_BIST_ERR_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_ta_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_TA_PKT_STATS_DFX, UBCTL_TA_PKT_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TA_ABN_STATS_DFX, UBCTL_TA_ABN_STATS_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_ta_pkt_stats(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_TA_PKT_STATS_DFX, UBCTL_TA_PKT_STATS_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_ta_abn_stats(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_TA_ABN_STATS_DFX, UBCTL_TA_ABN_STATS_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + static struct ubctl_func_dispatch g_ubctl_query_reg[] = { + { UTOOL_CMD_QUERY_NL, ubctl_query_nl_data, ubctl_query_data_deal }, { UTOOL_CMD_QUERY_NL_PKT_STATS, ubctl_query_nl_pkt_stats_data, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_NL_SSU_STATS, ubctl_query_nl_ssu_stats_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_NL_ABN, ubctl_query_nl_abn_data, ubctl_query_data_deal }, + + { UTOOL_CMD_QUERY_DL, ubctl_query_dl_data, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_DL_PKT_STATS, ubctl_query_dl_pkt_stats_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_DL_LINK_STATUS, ubctl_query_dl_link_status_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_DL_LANE, ubctl_query_dl_lane_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_DL_BIT_ERR, ubctl_query_dl_bit_err_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_DL_BIST, ubctl_query_dl_bist_data, + ubctl_query_data_deal }, + { UTOOL_CMD_CONF_DL_BIST, ubctl_conf_dl_bist_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_DL_BIST_ERR, ubctl_query_dl_bist_err_data, + ubctl_query_data_deal }, + + { UTOOL_CMD_QUERY_TA, ubctl_query_ta_data, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_TA_PKT_STATS, ubctl_query_ta_pkt_stats, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_TA_ABN_STATS, ubctl_query_ta_abn_stats, + ubctl_query_data_deal }, { UTOOL_CMD_QUERY_MAX, NULL, NULL } }; diff --git a/drivers/fwctl/ub/ub_cmdq.h b/drivers/fwctl/ub/ub_cmdq.h index 05db6aa07d5b..c4420884928c 100644 --- a/drivers/fwctl/ub/ub_cmdq.h +++ b/drivers/fwctl/ub/ub_cmdq.h @@ -7,7 +7,33 @@ #define __UB_CMDQ_H__ #define UBCTL_QUERY_NL_PKT_STATS_DFX 0xA001 +#define UBCTL_QUERY_NL_SSU_STATS_DFX 0xA002 +#define UBCTL_QUERY_NL_ABN_DFX 0xA003 + +#define UBCTL_QUERY_TA_PKT_STATS_DFX 0xA006 +#define UBCTL_QUERY_TA_ABN_STATS_DFX 0xA023 + +#define UBCTL_QUERY_DL_PKT_STATS_DFX 0xA007 +#define UBCTL_QUERY_DL_LINK_STATUS_DFX 0xA008 +#define UBCTL_QUERY_DL_LANE_DFX 0xA009 +#define UBCTL_QUERY_DL_BIT_ERR_DFX 0xA00A +#define UBCTL_QUERY_CONF_DL_BIST_DFX 0xA020 +#define UBCTL_QUERY_DL_BIST_ERR_DFX 0xA021 +#define UBCTL_QUERY_DL_REPL_DFX 0xA022 #define UBCTL_NL_PKT_STATS_LEN 632 +#define UBCTL_NL_SSU_STATS_LEN 408 +#define UBCTL_NL_ABN_LEN 56 + +#define UBCTL_TA_PKT_STATS_LEN 920 +#define UBCTL_TA_ABN_STATS_LEN 168 + +#define UBCTL_DL_PKT_STATS_LEN 984 +#define UBCTL_DL_REPL_LEN 120 +#define UBCTL_DL_LINK_STATUS_LEN 24 +#define UBCTL_DL_LANE_LEN 24 +#define UBCTL_DL_BIT_ERR_LEN 56 +#define UBCTL_DL_BIST_LEN 24 +#define UBCTL_DL_BIST_ERR_LEN 24 #endif diff --git a/drivers/fwctl/ub/ub_common.h b/drivers/fwctl/ub/ub_common.h index 0eda05fc5932..cde0a09b85e2 100644 --- a/drivers/fwctl/ub/ub_common.h +++ b/drivers/fwctl/ub/ub_common.h @@ -13,6 +13,7 @@ #include #define UBCTL_READ true +#define UBCTL_WRITE false #define ubctl_err(ucdev, format, ...) \ dev_err(&ucdev->fwctl.dev, format, ##__VA_ARGS__) diff --git a/include/uapi/fwctl/ub_fwctl.h b/include/uapi/fwctl/ub_fwctl.h index 011c4d48bada..3f540cb826b3 100644 --- a/include/uapi/fwctl/ub_fwctl.h +++ b/include/uapi/fwctl/ub_fwctl.h @@ -37,7 +37,23 @@ struct fwctl_rpc_ub_out { }; enum ub_fwctl_cmdrpc_type { + UTOOL_CMD_QUERY_NL = 0x0001, UTOOL_CMD_QUERY_NL_PKT_STATS = 0x0002, + UTOOL_CMD_QUERY_NL_SSU_STATS = 0x0003, + UTOOL_CMD_QUERY_NL_ABN = 0x0004, + + UTOOL_CMD_QUERY_DL = 0x0011, + UTOOL_CMD_QUERY_DL_PKT_STATS = 0x0012, + UTOOL_CMD_QUERY_DL_LINK_STATUS = 0x0013, + UTOOL_CMD_QUERY_DL_LANE = 0x0014, + UTOOL_CMD_QUERY_DL_BIT_ERR = 0x0015, + UTOOL_CMD_QUERY_DL_BIST = 0x0017, + UTOOL_CMD_CONF_DL_BIST = 0x0018, + UTOOL_CMD_QUERY_DL_BIST_ERR = 0x0019, + + UTOOL_CMD_QUERY_TA = 0x0031, + UTOOL_CMD_QUERY_TA_PKT_STATS = 0x0032, + UTOOL_CMD_QUERY_TA_ABN_STATS = 0x0033, UTOOL_CMD_QUERY_MAX, }; -- Gitee From 62fec57e914384beb5a99e9dae5ec358924755a5 Mon Sep 17 00:00:00 2001 From: Jiaqi Cheng Date: Fri, 22 Aug 2025 15:24:10 +0800 Subject: [PATCH 032/103] ub: ub_fwctl: supports querying TP, BA related register information commit 12da5b6ce2af648d4cacb5429731e6542c30f535 openEuler 1. Support querying statistical register information for TP(Tranport) TX and RX directions, as well as abnormal message statistical register information 2. Support querying BA(Bus Adapter) statistical register information, querying MAR DFX including entry status, CXT status, traffic statistics, error information, etc. 3. Supports UB Memory PMU function, which calculates traffic information in UB Memory, including write traffic, read traffic, total traffic, average read payload length, average write payload length, average payload length, write delay, and read delay. Signed-off-by: Jiaqi Cheng Signed-off-by: huwentao --- drivers/fwctl/ub/ub_cmd_reg.c | 248 ++++++++++++++++++++++++++++++++++ drivers/fwctl/ub/ub_cmdq.h | 32 +++++ drivers/fwctl/ub/ub_common.c | 17 ++- include/uapi/fwctl/ub_fwctl.h | 22 +++ 4 files changed, 318 insertions(+), 1 deletion(-) diff --git a/drivers/fwctl/ub/ub_cmd_reg.c b/drivers/fwctl/ub/ub_cmd_reg.c index 17a695a81c0b..6bb8bf7625be 100644 --- a/drivers/fwctl/ub/ub_cmd_reg.c +++ b/drivers/fwctl/ub/ub_cmd_reg.c @@ -157,6 +157,120 @@ static int ubctl_query_dl_bist_err_data(struct ubctl_dev *ucdev, query_dp, ARRAY_SIZE(query_dp)); } +static int ubctl_query_dp_deal(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func, + struct ubctl_query_dp *query_dp, u32 query_dp_num) +{ +#define UBCTL_TP_RX_BANK_NUM 3U + + u32 *rx_bank_id __free(kvfree) = kvzalloc(sizeof(u32) * UBCTL_TP_RX_BANK_NUM, GFP_KERNEL); + u32 bank_idx = 0; + u32 bank_id = 0; + int ret = 0; + u32 i; + + if (!rx_bank_id) + return -ENOMEM; + + for (i = 0; i < query_dp_num; i++) { + if (query_dp[i].op_code != UBCTL_QUERY_TP_RX_BANK_DFX) + continue; + if (bank_idx >= UBCTL_TP_RX_BANK_NUM) { + ubctl_err(ucdev, "bank_idx is out of bounds: %u.\n", bank_idx); + return -EINVAL; + } + + rx_bank_id[bank_idx] = bank_id++; + query_dp[i].data = (void *)&rx_bank_id[bank_idx++]; + query_dp[i].data_len = (u32)sizeof(u32); + } + + ret = ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, query_dp_num); + if (ret) + ubctl_err(ucdev, "ubctl query data failed, ret = %d.\n", ret); + + return ret; +} + +static int ubctl_query_tp_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_TP_TX_DFX, UBCTL_TP_TX_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_DFX, UBCTL_TP_RX_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RQM_DFX, UBCTL_TP_RQM_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_STATE_DFX, UBCTL_TP_STATE_DFX_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_TX_ROUTE_DFX, UBCTL_TP_TX_ROUTE_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_BANK_DFX, UBCTL_TP_RX_BANK_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_BANK_DFX, UBCTL_TP_RX_BANK_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_BANK_DFX, UBCTL_TP_RX_BANK_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_TX_DFX, UBCTL_TP_TX_ABN_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_DFX, UBCTL_TP_RX_ABN_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_ABN_STATS_DFX, UBCTL_TP_REG_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_dp_deal(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_tp_tx_route_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_TP_TX_ROUTE_DFX, UBCTL_TP_TX_ROUTE_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, query_dp, + ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_tp_abn_stats_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_TP_TX_DFX, UBCTL_TP_TX_ABN_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_DFX, UBCTL_TP_RX_ABN_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_ABN_STATS_DFX, UBCTL_TP_REG_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, query_dp, + ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_tp_pkt_stats_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_TP_TX_DFX, UBCTL_TP_TX_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_DFX, UBCTL_TP_RX_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RQM_DFX, UBCTL_TP_RQM_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_STATE_DFX, UBCTL_TP_STATE_DFX_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_tp_rx_bank_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_TP_RX_BANK_DFX, UBCTL_TP_RX_BANK_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_BANK_DFX, UBCTL_TP_RX_BANK_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_BANK_DFX, UBCTL_TP_RX_BANK_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_dp_deal(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + static int ubctl_query_ta_data(struct ubctl_dev *ucdev, struct ubctl_query_cmd_param *query_cmd_param, struct ubctl_func_dispatch *query_func) @@ -194,6 +308,115 @@ static int ubctl_query_ta_abn_stats(struct ubctl_dev *ucdev, query_dp, ARRAY_SIZE(query_dp)); } +static int ubctl_query_ba_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_BA_PKT_STATS_DFX, UBCTL_BA_PKT_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_BA_MAR_DFX, UBCTL_BA_MAR_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_ba_pkt_stats_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_BA_PKT_STATS_DFX, UBCTL_BA_PKT_STATS_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_conf_ba_mar_perf(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_CONF_BA_PERF_DFX, UBCTL_CONF_BA_MAR_PERF_LEN, UBCTL_WRITE, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_ba_mar_perf(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_BA_MAR_PERF_DFX, UBCTL_QUERY_BA_MAR_PERF_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_ba_mar_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_BA_MAR_DFX, UBCTL_BA_MAR_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_mar_cyc_en_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_MAR_CYC_EN_DFX, UBCTL_MAR_CYC_EN_LEN, UBCTL_READ, NULL, 0 }, + }; + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_conf_mar_cyc_en_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_MAR_CYC_EN_DFX, UBCTL_MAR_CYC_EN_LEN, UBCTL_WRITE, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_mar_table_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ +#define UBCTL_UB_MEM_TABLE_ENTRY_LEN 16U +#define UBCTL_UB_MEM_TABLE_ENTRY_NUM 7U + + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_MAR_TABLE_DFX, UBCTL_MAR_TABLE_LEN, UBCTL_READ, NULL, 0 }, + }; + struct fwctl_pkt_in_table *mar_table = + (struct fwctl_pkt_in_table *)(query_cmd_param->in->data); + + if (query_cmd_param->in->data_size != sizeof(*mar_table)) { + ubctl_err(ucdev, "user data of mar table is invalid.\n"); + return -EINVAL; + } + + if (mar_table->table_num == UBCTL_UB_MEM_TABLE_ENTRY_NUM) + mar_table->index *= UBCTL_UB_MEM_TABLE_ENTRY_LEN; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + static struct ubctl_func_dispatch g_ubctl_query_reg[] = { { UTOOL_CMD_QUERY_NL, ubctl_query_nl_data, ubctl_query_data_deal }, { UTOOL_CMD_QUERY_NL_PKT_STATS, ubctl_query_nl_pkt_stats_data, @@ -218,12 +441,37 @@ static struct ubctl_func_dispatch g_ubctl_query_reg[] = { { UTOOL_CMD_QUERY_DL_BIST_ERR, ubctl_query_dl_bist_err_data, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_TP, ubctl_query_tp_data, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_TP_PKT_STATS, ubctl_query_tp_pkt_stats_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_TP_ABN_STATS, ubctl_query_tp_abn_stats_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_TP_TX_ROUTE, ubctl_query_tp_tx_route_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_TP_RX_BANK, ubctl_query_tp_rx_bank_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_TA, ubctl_query_ta_data, ubctl_query_data_deal }, { UTOOL_CMD_QUERY_TA_PKT_STATS, ubctl_query_ta_pkt_stats, ubctl_query_data_deal }, { UTOOL_CMD_QUERY_TA_ABN_STATS, ubctl_query_ta_abn_stats, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_BA, ubctl_query_ba_data, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_BA_PKT_STATS, ubctl_query_ba_pkt_stats_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_BA_MAR, ubctl_query_ba_mar_data, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_BA_MAR_TABLE, ubctl_query_mar_table_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_BA_MAR_CYC_EN, ubctl_query_mar_cyc_en_data, + ubctl_query_data_deal }, + { UTOOL_CMD_CONF_BA_MAR_CYC_EN, ubctl_conf_mar_cyc_en_data, + ubctl_query_data_deal }, + { UTOOL_CMD_CONFIG_BA_MAR_PEFR_STATS, ubctl_conf_ba_mar_perf, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_BA_MAR_PEFR_STATS, ubctl_query_ba_mar_perf, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_MAX, NULL, NULL } }; diff --git a/drivers/fwctl/ub/ub_cmdq.h b/drivers/fwctl/ub/ub_cmdq.h index c4420884928c..026f751d365b 100644 --- a/drivers/fwctl/ub/ub_cmdq.h +++ b/drivers/fwctl/ub/ub_cmdq.h @@ -10,6 +10,14 @@ #define UBCTL_QUERY_NL_SSU_STATS_DFX 0xA002 #define UBCTL_QUERY_NL_ABN_DFX 0xA003 +#define UBCTL_QUERY_TP_TX_DFX 0xA004 +#define UBCTL_QUERY_TP_RX_DFX 0xA005 +#define UBCTL_QUERY_TP_TX_ROUTE_DFX 0xA01A +#define UBCTL_QUERY_TP_RX_BANK_DFX 0xA01C +#define UBCTL_QUERY_TP_ABN_STATS_DFX 0xA01D +#define UBCTL_QUERY_TP_RQM_DFX 0xA01E +#define UBCTL_QUERY_TP_STATE_DFX 0xA024 + #define UBCTL_QUERY_TA_PKT_STATS_DFX 0xA006 #define UBCTL_QUERY_TA_ABN_STATS_DFX 0xA023 @@ -21,10 +29,27 @@ #define UBCTL_QUERY_DL_BIST_ERR_DFX 0xA021 #define UBCTL_QUERY_DL_REPL_DFX 0xA022 +#define UBCTL_QUERY_BA_PKT_STATS_DFX 0xA00B +#define UBCTL_QUERY_BA_MAR_DFX 0xA00C +#define UBCTL_QUERY_MAR_TABLE_DFX 0xA012 +#define UBCTL_QUERY_MAR_CYC_EN_DFX 0xA013 +#define UBCTL_CONF_BA_PERF_DFX 0xA014 +#define UBCTL_QUERY_BA_MAR_PERF_DFX 0xA015 + #define UBCTL_NL_PKT_STATS_LEN 632 #define UBCTL_NL_SSU_STATS_LEN 408 #define UBCTL_NL_ABN_LEN 56 +#define UBCTL_TP_TX_STATS_LEN 904 +#define UBCTL_TP_RX_STATS_LEN 704 +#define UBCTL_TP_TX_ABN_LEN 948 +#define UBCTL_TP_RX_ABN_LEN 760 +#define UBCTL_TP_REG_LEN 24 +#define UBCTL_TP_TX_ROUTE_LEN 216 +#define UBCTL_TP_RX_BANK_LEN 408 +#define UBCTL_TP_RQM_LEN 88 +#define UBCTL_TP_STATE_DFX_LEN 376 + #define UBCTL_TA_PKT_STATS_LEN 920 #define UBCTL_TA_ABN_STATS_LEN 168 @@ -36,4 +61,11 @@ #define UBCTL_DL_BIST_LEN 24 #define UBCTL_DL_BIST_ERR_LEN 24 +#define UBCTL_BA_PKT_STATS_LEN 792 +#define UBCTL_BA_MAR_LEN 440 +#define UBCTL_MAR_TABLE_LEN 88 +#define UBCTL_MAR_CYC_EN_LEN 24 +#define UBCTL_CONF_BA_MAR_PERF_LEN 24 +#define UBCTL_QUERY_BA_MAR_PERF_LEN 56 + #endif diff --git a/drivers/fwctl/ub/ub_common.c b/drivers/fwctl/ub/ub_common.c index 87654eb0aefc..23d67829c8de 100644 --- a/drivers/fwctl/ub/ub_common.c +++ b/drivers/fwctl/ub/ub_common.c @@ -6,6 +6,7 @@ #include #include "ub_common.h" +#include "ub_cmdq.h" static inline void ubctl_struct_cpu_to_le32(u32 *data, u32 cnt) { @@ -122,6 +123,20 @@ static int ubctl_cmd_send_deal(struct ubctl_dev *ucdev, return ret; } +static void ubctl_cmd_data_deal(struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_query_dp *query_dp, + struct ubctl_query_cmd_dp *cmd_dp) +{ + if (!query_dp->data) { + memcpy(cmd_dp->cmd_in, query_cmd_param->in->data, query_cmd_param->in->data_size); + return; + } + + if (query_dp->op_code == UBCTL_QUERY_TP_RX_BANK_DFX && + query_dp->data_len == (u32)sizeof(u32)) + memcpy(cmd_dp->cmd_in, query_dp->data, sizeof(u32)); +} + int ubctl_query_data(struct ubctl_dev *ucdev, struct ubctl_query_cmd_param *query_cmd_param, struct ubctl_func_dispatch *query_func, @@ -157,7 +172,7 @@ int ubctl_query_data(struct ubctl_dev *ucdev, .query_func = query_func, }; - memcpy(cmd_dp.cmd_in, query_cmd_param->in->data, query_cmd_param->in->data_size); + ubctl_cmd_data_deal(query_cmd_param, &query_dp[i], &cmd_dp); ret = ubctl_cmd_send_deal(ucdev, query_cmd_param, &query_dp[i], &cmd_dp, offset); if (ret) diff --git a/include/uapi/fwctl/ub_fwctl.h b/include/uapi/fwctl/ub_fwctl.h index 3f540cb826b3..e7aa1df3a660 100644 --- a/include/uapi/fwctl/ub_fwctl.h +++ b/include/uapi/fwctl/ub_fwctl.h @@ -42,6 +42,12 @@ enum ub_fwctl_cmdrpc_type { UTOOL_CMD_QUERY_NL_SSU_STATS = 0x0003, UTOOL_CMD_QUERY_NL_ABN = 0x0004, + UTOOL_CMD_QUERY_TP = 0x0021, + UTOOL_CMD_QUERY_TP_PKT_STATS = 0x0022, + UTOOL_CMD_QUERY_TP_TX_ROUTE = 0x0023, + UTOOL_CMD_QUERY_TP_ABN_STATS = 0x0024, + UTOOL_CMD_QUERY_TP_RX_BANK = 0x0025, + UTOOL_CMD_QUERY_DL = 0x0011, UTOOL_CMD_QUERY_DL_PKT_STATS = 0x0012, UTOOL_CMD_QUERY_DL_LINK_STATUS = 0x0013, @@ -55,7 +61,23 @@ enum ub_fwctl_cmdrpc_type { UTOOL_CMD_QUERY_TA_PKT_STATS = 0x0032, UTOOL_CMD_QUERY_TA_ABN_STATS = 0x0033, + UTOOL_CMD_QUERY_BA = 0x0041, + UTOOL_CMD_QUERY_BA_PKT_STATS = 0x0042, + UTOOL_CMD_QUERY_BA_MAR = 0x0043, + UTOOL_CMD_QUERY_BA_MAR_TABLE = 0x0044, + UTOOL_CMD_QUERY_BA_MAR_CYC_EN = 0x0045, + UTOOL_CMD_CONF_BA_MAR_CYC_EN = 0x0046, + UTOOL_CMD_CONFIG_BA_MAR_PEFR_STATS = 0x0047, + UTOOL_CMD_QUERY_BA_MAR_PEFR_STATS = 0x0048, + UTOOL_CMD_QUERY_MAX, }; +struct fwctl_pkt_in_table { + __u32 port_id; + __u32 table_num; + __u32 index; +}; + + #endif -- Gitee From 583ce1ad460b8dfe88df7dc512fd3b477f9b8593 Mon Sep 17 00:00:00 2001 From: Jiaqi Cheng Date: Wed, 20 Aug 2025 17:13:53 +0800 Subject: [PATCH 033/103] ub: ub_fwctl: supports querying and configuring some scattered registers. commit bb849315817d8c5dd1f7759ec06016d434ed449e openEuler 1. Support querying QOS(Quality of Service) related registers. 2. Support SCC debug switch configuration query. 3. Support querying UBOMMU(UB Memory Management Unit) related registers information. 4. Support querying software UB port link building process software and hardware information. 5. Support querying multi bit ECC statistics. 6. Support querying queue status registers. 7. Support Uboe port PRBS packet self-test. 8. Support configuring uboe port loopback. Signed-off-by: Jiaqi Cheng Signed-off-by: huwentao --- drivers/fwctl/ub/ub_cmd_reg.c | 177 ++++++++++++++++++++++++++++++++++ drivers/fwctl/ub/ub_cmdq.h | 29 ++++++ include/uapi/fwctl/ub_fwctl.h | 23 +++++ 3 files changed, 229 insertions(+) diff --git a/drivers/fwctl/ub/ub_cmd_reg.c b/drivers/fwctl/ub/ub_cmd_reg.c index 6bb8bf7625be..bfc480c73c1d 100644 --- a/drivers/fwctl/ub/ub_cmd_reg.c +++ b/drivers/fwctl/ub/ub_cmd_reg.c @@ -417,6 +417,161 @@ static int ubctl_query_mar_table_data(struct ubctl_dev *ucdev, query_dp, ARRAY_SIZE(query_dp)); } +static int ubctl_query_qos_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_QOS_DFX, UBCTL_QOS_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_scc_debug(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_SCC_DEBUG_DFX, UBCTL_SCC_DEBUG_EN_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_config_scc_debug(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_SCC_DEBUG_DFX, UBCTL_SCC_DEBUG_EN_LEN, UBCTL_WRITE, NULL, 0 }, + }; + + if (query_cmd_param->in->data_size != sizeof(struct fwctl_pkt_in_enable)) { + ubctl_err(ucdev, "user data of scc debug is invalid.\n"); + return -EINVAL; + } + u8 *scc_debug_en = (u8 *)(query_cmd_param->in->data); + + if (*scc_debug_en > 1) + return -EINVAL; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_ubommu_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_UBOMMU_DFX, UBCTL_UBOMMU_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_port_info_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_PORT_INFO_DFX, UBCTL_PORT_INFO_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, query_dp, + ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_ecc_2b_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_ECC_2B_DFX, UBCTL_ECC_2B_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, query_dp, + ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_queue_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_QUEUE_DFX, UBCTL_QUEUE_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, query_dp, + ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_loopback(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_LOOPBACK, UBCTL_QUERY_DEBUG_EN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_config_loopback(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_LOOPBACK, UBCTL_QUERY_DEBUG_EN, UBCTL_WRITE, NULL, 0 }, + }; + int ret; + + ret = ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); + + if (query_cmd_param->out->retval == -EBUSY) + ubctl_err(ucdev, "Current port has been enabled for another loopback mode.\n"); + if (query_cmd_param->out->retval == -EMLINK) + ubctl_err(ucdev, "Another port has already been enabled.\n"); + + return ret; +} + +static int ubctl_query_prbs(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_PRBS_RESULT, UBCTL_QUERY_DEBUG_EN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_config_prbs(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_PRBS_RESULT, UBCTL_QUERY_DEBUG_EN, UBCTL_WRITE, NULL, 0 }, + }; + int ret; + + ret = ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); + + if (query_cmd_param->out->retval == -EMLINK) + ubctl_err(ucdev, "Another port has already been enabled.\n"); + + return ret; +} + static struct ubctl_func_dispatch g_ubctl_query_reg[] = { { UTOOL_CMD_QUERY_NL, ubctl_query_nl_data, ubctl_query_data_deal }, { UTOOL_CMD_QUERY_NL_PKT_STATS, ubctl_query_nl_pkt_stats_data, @@ -472,6 +627,28 @@ static struct ubctl_func_dispatch g_ubctl_query_reg[] = { { UTOOL_CMD_QUERY_BA_MAR_PEFR_STATS, ubctl_query_ba_mar_perf, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_QOS, ubctl_query_qos_data, ubctl_query_data_deal }, + + { UTOOL_CMD_QUERY_SCC_DEBUG_EN, ubctl_query_scc_debug, + ubctl_query_data_deal }, + { UTOOL_CMD_CONF_SCC_DEBUG_EN, ubctl_config_scc_debug, + ubctl_query_data_deal }, + + { UTOOL_CMD_QUERY_UBOMMU, ubctl_query_ubommu_data, ubctl_query_data_deal }, + + { UTOOL_CMD_QUERY_PORT_INFO, ubctl_query_port_info_data, + ubctl_query_data_deal }, + + { UTOOL_CMD_QUERY_ECC_2B, ubctl_query_ecc_2b_data, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_QUEUE, ubctl_query_queue_data, ubctl_query_data_deal }, + + { UTOOL_CMD_QUERY_LOOPBACK, ubctl_query_loopback, ubctl_query_data_deal }, + { UTOOL_CMD_CONF_LOOPBACK, ubctl_config_loopback, ubctl_query_data_deal }, + + { UTOOL_CMD_QUERY_PRBS_EN, ubctl_query_prbs, ubctl_query_data_deal }, + { UTOOL_CMD_CONF_PRBS_EN, ubctl_config_prbs, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_PRBS_RESULT, ubctl_query_prbs, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_MAX, NULL, NULL } }; diff --git a/drivers/fwctl/ub/ub_cmdq.h b/drivers/fwctl/ub/ub_cmdq.h index 026f751d365b..67e0bd576a6f 100644 --- a/drivers/fwctl/ub/ub_cmdq.h +++ b/drivers/fwctl/ub/ub_cmdq.h @@ -36,6 +36,21 @@ #define UBCTL_CONF_BA_PERF_DFX 0xA014 #define UBCTL_QUERY_BA_MAR_PERF_DFX 0xA015 +#define UBCTL_QUERY_QOS_DFX 0xA00D + +#define UBCTL_QUERY_SCC_DEBUG_DFX 0xA011 + +#define UBCTL_QUERY_QUEUE_DFX 0xA01B + +#define UBCTL_QUERY_UBOMMU_DFX 0xA016 + +#define UBCTL_QUERY_PORT_INFO_DFX 0xA018 + +#define UBCTL_QUERY_ECC_2B_DFX 0xA019 + +#define UBCTL_QUERY_LOOPBACK 0xA025 +#define UBCTL_QUERY_PRBS_RESULT 0xA026 + #define UBCTL_NL_PKT_STATS_LEN 632 #define UBCTL_NL_SSU_STATS_LEN 408 #define UBCTL_NL_ABN_LEN 56 @@ -68,4 +83,18 @@ #define UBCTL_CONF_BA_MAR_PERF_LEN 24 #define UBCTL_QUERY_BA_MAR_PERF_LEN 56 +#define UBCTL_QOS_LEN 284 + +#define UBCTL_SCC_DEBUG_EN_LEN 24 + +#define UBCTL_QUEUE_LEN 120 + +#define UBCTL_PORT_INFO_LEN 56 + +#define UBCTL_UBOMMU_LEN 56 + +#define UBCTL_ECC_2B_LEN 344 + +#define UBCTL_QUERY_DEBUG_EN 24 + #endif diff --git a/include/uapi/fwctl/ub_fwctl.h b/include/uapi/fwctl/ub_fwctl.h index e7aa1df3a660..432ea55ff59a 100644 --- a/include/uapi/fwctl/ub_fwctl.h +++ b/include/uapi/fwctl/ub_fwctl.h @@ -70,9 +70,32 @@ enum ub_fwctl_cmdrpc_type { UTOOL_CMD_CONFIG_BA_MAR_PEFR_STATS = 0x0047, UTOOL_CMD_QUERY_BA_MAR_PEFR_STATS = 0x0048, + UTOOL_CMD_QUERY_QOS = 0x0051, + + UTOOL_CMD_QUERY_SCC_DEBUG_EN = 0x0063, + UTOOL_CMD_CONF_SCC_DEBUG_EN = 0x0064, + + UTOOL_CMD_QUERY_QUEUE = 0x0073, + + UTOOL_CMD_QUERY_PORT_INFO = 0x0081, + + UTOOL_CMD_QUERY_UBOMMU = 0x0091, + + UTOOL_CMD_QUERY_ECC_2B = 0x00B1, + + UTOOL_CMD_QUERY_LOOPBACK = 0x00D1, + UTOOL_CMD_CONF_LOOPBACK = 0x00D2, + UTOOL_CMD_QUERY_PRBS_EN = 0x00D3, + UTOOL_CMD_CONF_PRBS_EN = 0x00D4, + UTOOL_CMD_QUERY_PRBS_RESULT = 0x00D5, + UTOOL_CMD_QUERY_MAX, }; +struct fwctl_pkt_in_enable { + __u8 enable; +}; + struct fwctl_pkt_in_table { __u32 port_id; __u32 table_num; -- Gitee From b9347c9dcb1f8d19f4bb2e4b8cead96029518869 Mon Sep 17 00:00:00 2001 From: Jiaqi Cheng Date: Wed, 20 Aug 2025 19:43:59 +0800 Subject: [PATCH 034/103] ub: ub_fwctl: Support Dump register. commit d9fe3f4bd8c5bd7eeb7e2c5e787f7056b3b9d7dd openEuler Support Dump registers at various levels, mainly consisting of statistical information registers and status registers. Not all registers. Signed-off-by: Jiaqi Cheng Signed-off-by: huwentao --- drivers/fwctl/ub/ub_cmd_reg.c | 46 +++++++++++++++++++++++++++++++++++ include/uapi/fwctl/ub_fwctl.h | 2 ++ 2 files changed, 48 insertions(+) diff --git a/drivers/fwctl/ub/ub_cmd_reg.c b/drivers/fwctl/ub/ub_cmd_reg.c index bfc480c73c1d..026ac3f2fe90 100644 --- a/drivers/fwctl/ub/ub_cmd_reg.c +++ b/drivers/fwctl/ub/ub_cmd_reg.c @@ -572,6 +572,50 @@ static int ubctl_config_prbs(struct ubctl_dev *ucdev, return ret; } +static int ubctl_query_dump_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_NL_PKT_STATS_DFX, UBCTL_NL_PKT_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_NL_SSU_STATS_DFX, UBCTL_NL_SSU_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_NL_ABN_DFX, UBCTL_NL_ABN_LEN, UBCTL_READ, NULL, 0 }, + + { UBCTL_QUERY_TP_TX_DFX, UBCTL_TP_TX_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_DFX, UBCTL_TP_RX_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RQM_DFX, UBCTL_TP_RQM_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_STATE_DFX, UBCTL_TP_STATE_DFX_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_TX_ROUTE_DFX, UBCTL_TP_TX_ROUTE_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_BANK_DFX, UBCTL_TP_RX_BANK_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_BANK_DFX, UBCTL_TP_RX_BANK_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_BANK_DFX, UBCTL_TP_RX_BANK_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_TX_DFX, UBCTL_TP_TX_ABN_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_RX_DFX, UBCTL_TP_RX_ABN_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TP_ABN_STATS_DFX, UBCTL_TP_REG_LEN, UBCTL_READ, NULL, 0 }, + + { UBCTL_QUERY_TA_PKT_STATS_DFX, UBCTL_TA_PKT_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_TA_ABN_STATS_DFX, UBCTL_TA_ABN_STATS_LEN, UBCTL_READ, NULL, 0 }, + + { UBCTL_QUERY_DL_PKT_STATS_DFX, UBCTL_DL_PKT_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_DL_REPL_DFX, UBCTL_DL_REPL_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_DL_LINK_STATUS_DFX, UBCTL_DL_LINK_STATUS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_DL_LANE_DFX, UBCTL_DL_LANE_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_DL_BIT_ERR_DFX, UBCTL_DL_BIT_ERR_LEN, UBCTL_READ, NULL, 0 }, + + { UBCTL_QUERY_BA_PKT_STATS_DFX, UBCTL_BA_PKT_STATS_LEN, UBCTL_READ, NULL, 0 }, + { UBCTL_QUERY_BA_MAR_DFX, UBCTL_BA_MAR_LEN, UBCTL_READ, NULL, 0 }, + + { UBCTL_QUERY_QOS_DFX, UBCTL_QOS_LEN, UBCTL_READ, NULL, 0 }, + + { UBCTL_QUERY_UBOMMU_DFX, UBCTL_UBOMMU_LEN, UBCTL_READ, NULL, 0 }, + + { UBCTL_QUERY_ECC_2B_DFX, UBCTL_ECC_2B_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_dp_deal(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + static struct ubctl_func_dispatch g_ubctl_query_reg[] = { { UTOOL_CMD_QUERY_NL, ubctl_query_nl_data, ubctl_query_data_deal }, { UTOOL_CMD_QUERY_NL_PKT_STATS, ubctl_query_nl_pkt_stats_data, @@ -649,6 +693,8 @@ static struct ubctl_func_dispatch g_ubctl_query_reg[] = { { UTOOL_CMD_CONF_PRBS_EN, ubctl_config_prbs, ubctl_query_data_deal }, { UTOOL_CMD_QUERY_PRBS_RESULT, ubctl_query_prbs, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_DUMP, ubctl_query_dump_data, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_MAX, NULL, NULL } }; diff --git a/include/uapi/fwctl/ub_fwctl.h b/include/uapi/fwctl/ub_fwctl.h index 432ea55ff59a..1e40bd8f4a1c 100644 --- a/include/uapi/fwctl/ub_fwctl.h +++ b/include/uapi/fwctl/ub_fwctl.h @@ -89,6 +89,8 @@ enum ub_fwctl_cmdrpc_type { UTOOL_CMD_CONF_PRBS_EN = 0x00D4, UTOOL_CMD_QUERY_PRBS_RESULT = 0x00D5, + UTOOL_CMD_QUERY_DUMP = 0xFFFE, + UTOOL_CMD_QUERY_MAX, }; -- Gitee From e88b342cf967834b9b199d4f2c927094fb4ecc92 Mon Sep 17 00:00:00 2001 From: Jiaqi Cheng Date: Thu, 21 Aug 2025 17:09:08 +0800 Subject: [PATCH 035/103] ub: ub_fwctl: support querying UB link trace information. commit d275d5c4931372d973499ea430bb7cb787d0b617 openEuler ub_fwctl adds some complex query processing. Support ub_fwctl to query UB link trace information. Signed-off-by: Jiaqi Cheng Signed-off-by: huwentao --- drivers/fwctl/ub/Makefile | 2 +- drivers/fwctl/ub/main.c | 8 +- drivers/fwctl/ub/ub_cmd.c | 157 ++++++++++++++++++++++++++++++++++ drivers/fwctl/ub/ub_cmd.h | 13 +++ drivers/fwctl/ub/ub_cmdq.h | 2 + include/uapi/fwctl/ub_fwctl.h | 4 + 6 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 drivers/fwctl/ub/ub_cmd.c create mode 100644 drivers/fwctl/ub/ub_cmd.h diff --git a/drivers/fwctl/ub/Makefile b/drivers/fwctl/ub/Makefile index c2c2008b2653..391aa5f909c5 100644 --- a/drivers/fwctl/ub/Makefile +++ b/drivers/fwctl/ub/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0+ obj-$(CONFIG_FWCTL_UB) += ub_fwctl.o -ub_fwctl-y += main.o ub_cmd_reg.o ub_common.o +ub_fwctl-y += main.o ub_cmd_reg.o ub_common.o ub_cmd.o diff --git a/drivers/fwctl/ub/main.c b/drivers/fwctl/ub/main.c index 63de07d5d028..e96ccf5afa55 100644 --- a/drivers/fwctl/ub/main.c +++ b/drivers/fwctl/ub/main.c @@ -10,6 +10,7 @@ #include "ub_common.h" #include "ub_cmd_reg.h" +#include "ub_cmd.h" #define MAX_IOCTL_COUNT 1024 #define TIME_WINDOW_MS 3000 @@ -98,9 +99,14 @@ static int ub_cmd_do(struct ubctl_dev *ucdev, u32 rpc_cmd = query_cmd_param->in->rpc_cmd; struct ubctl_func_dispatch *ubctl_query_reg = ubctl_get_query_reg_func( ucdev, rpc_cmd); + struct ubctl_func_dispatch *ubctl_query_func = ubctl_get_query_func( + ucdev, rpc_cmd); int ret; - if (ubctl_query_reg && ubctl_query_reg->execute) { + if (ubctl_query_func && ubctl_query_func->execute) { + ret = ubctl_query_func->execute(ucdev, query_cmd_param, + ubctl_query_func); + } else if (ubctl_query_reg && ubctl_query_reg->execute) { ret = ubctl_query_reg->execute(ucdev, query_cmd_param, ubctl_query_reg); } else { diff --git a/drivers/fwctl/ub/ub_cmd.c b/drivers/fwctl/ub/ub_cmd.c new file mode 100644 index 000000000000..22577289998c --- /dev/null +++ b/drivers/fwctl/ub/ub_cmd.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. + */ + +#include "ub_cmdq.h" +#include "ub_cmd.h" + +struct ubctl_query_trace { + u32 port_id; + u32 index; + u32 cur_count; + u32 total_count; + u32 data[]; +}; + +static int ubctl_trace_data_deal(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_cmd *cmd, u32 out_len, u32 offset) +{ +#define UBCTL_TRACE_SIZE 4U +#define UBCTL_TOTAL_CNT_MAX 64U + + struct fwctl_rpc_ub_out *trace_out = query_cmd_param->out; + struct ubctl_query_trace *trace_info = cmd->out_data; + u32 trace_max_len = query_cmd_param->out_len; + u32 pos_index = offset * UBCTL_TRACE_SIZE; + + if ((trace_info->total_count > UBCTL_TOTAL_CNT_MAX) || + (trace_info->total_count * UBCTL_TRACE_SIZE >= trace_max_len) || + (pos_index >= trace_max_len || cmd->out_len < sizeof(struct ubctl_query_trace))) { + ubctl_err(ucdev, "cmd out data length is error.\n"); + return -EINVAL; + } + + if (pos_index == 0) + memcpy(trace_out->data, cmd->out_data, cmd->out_len); + else + memcpy((u32 *)(trace_out->data) + pos_index, trace_info->data, + cmd->out_len - sizeof(struct ubctl_query_trace)); + + trace_out->data_size = query_cmd_param->out_len; + return 0; +} + +static int ubctl_send_deal_trace(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_query_cmd_dp *cmd_data, u32 offset) +{ + u32 out_len = UBCTL_DL_TRACE_LEN; + struct ubctl_cmd cmd = {}; + int ret = 0; + + if (!cmd_data->query_func->data_deal) { + ubctl_err(ucdev, "ubctl data deal func is null.\n"); + return -EINVAL; + } + + cmd.op_code = UBCTL_QUERY_DL_TRACE_DFX; + + ret = ubctl_fill_cmd(&cmd, cmd_data->cmd_in, cmd_data->cmd_out, + out_len, UBCTL_READ); + if (ret) { + ubctl_err(ucdev, "ubctl fill cmd failed.\n"); + return ret; + } + + ret = ubctl_ubase_cmd_send(ucdev->adev, &cmd); + if (ret) { + ubctl_err(ucdev, "ubctl ubase cmd send failed, ret = %d.\n", ret); + return -EINVAL; + } + + ret = cmd_data->query_func->data_deal(ucdev, query_cmd_param, &cmd, + out_len, offset); + if (ret) + ubctl_err(ucdev, "ubctl data deal failed, ret = %d.\n", ret); + + return ret; +} + +static int ubctl_query_dl_trace_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct fwctl_pkt_in_port *pkt_in = (struct fwctl_pkt_in_port *)query_cmd_param->in->data; + u32 trace_index = 0, offset = 0, expect_total = 0, out_len = UBCTL_DL_TRACE_LEN, tmp_sum; + struct ubctl_query_cmd_dp cmd_dp = {}; + int ret = 0; + + if (query_cmd_param->in->data_size != sizeof(struct fwctl_pkt_in_port)) { + ubctl_err(ucdev, "user data of trace is invalid.\n"); + return -EINVAL; + } + + while (1) { + struct ubctl_query_trace *cmd_in __free(kvfree) = kvzalloc(out_len, GFP_KERNEL); + if (!cmd_in) + return -ENOMEM; + + struct ubctl_query_trace *cmd_out __free(kvfree) = kvzalloc(out_len, GFP_KERNEL); + if (!cmd_out) + return -ENOMEM; + + cmd_in->index = trace_index; + cmd_in->port_id = pkt_in->port_id; + + cmd_dp = (struct ubctl_query_cmd_dp) { + .cmd_in = cmd_in, + .cmd_out = cmd_out, + .query_func = query_func, + }; + + ret = ubctl_send_deal_trace(ucdev, query_cmd_param, + &cmd_dp, offset); + if (ret) + return ret; + + offset = cmd_out->cur_count + 1; + trace_index = cmd_out->cur_count; + tmp_sum = cmd_out->cur_count + cmd_in->index; + + if ((tmp_sum <= expect_total) || (tmp_sum > cmd_out->total_count)) { + ubctl_err(ucdev, "software data of trace is invalid.\n"); + return -EINVAL; + } + + if (tmp_sum == cmd_out->total_count) + break; + + expect_total = tmp_sum; + } + + return ret; +} + +static struct ubctl_func_dispatch g_ubctl_query_func[] = { + { UTOOL_CMD_QUERY_DL_LINK_TRACE, ubctl_query_dl_trace_data, + ubctl_trace_data_deal }, + + { UTOOL_CMD_QUERY_MAX, NULL, NULL } +}; + +struct ubctl_func_dispatch *ubctl_get_query_func(struct ubctl_dev *ucdev, u32 rpc_cmd) +{ + u32 i; + + if (!ucdev) + return NULL; + + for (i = 0; i < ARRAY_SIZE(g_ubctl_query_func); i++) { + if (g_ubctl_query_func[i].rpc_cmd == rpc_cmd) + return &g_ubctl_query_func[i]; + } + + return NULL; +} diff --git a/drivers/fwctl/ub/ub_cmd.h b/drivers/fwctl/ub/ub_cmd.h new file mode 100644 index 000000000000..69bb2ea43c52 --- /dev/null +++ b/drivers/fwctl/ub/ub_cmd.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. + */ + +#ifndef __UB_CMD_H__ +#define __UB_CMD_H__ + +#include "ub_common.h" + +struct ubctl_func_dispatch *ubctl_get_query_func(struct ubctl_dev *ucdev, + u32 rpc_cmd); +#endif diff --git a/drivers/fwctl/ub/ub_cmdq.h b/drivers/fwctl/ub/ub_cmdq.h index 67e0bd576a6f..32323a4c0bbb 100644 --- a/drivers/fwctl/ub/ub_cmdq.h +++ b/drivers/fwctl/ub/ub_cmdq.h @@ -24,6 +24,7 @@ #define UBCTL_QUERY_DL_PKT_STATS_DFX 0xA007 #define UBCTL_QUERY_DL_LINK_STATUS_DFX 0xA008 #define UBCTL_QUERY_DL_LANE_DFX 0xA009 +#define UBCTL_QUERY_DL_TRACE_DFX 0xA010 #define UBCTL_QUERY_DL_BIT_ERR_DFX 0xA00A #define UBCTL_QUERY_CONF_DL_BIST_DFX 0xA020 #define UBCTL_QUERY_DL_BIST_ERR_DFX 0xA021 @@ -75,6 +76,7 @@ #define UBCTL_DL_BIT_ERR_LEN 56 #define UBCTL_DL_BIST_LEN 24 #define UBCTL_DL_BIST_ERR_LEN 24 +#define UBCTL_DL_TRACE_LEN 1016 #define UBCTL_BA_PKT_STATS_LEN 792 #define UBCTL_BA_MAR_LEN 440 diff --git a/include/uapi/fwctl/ub_fwctl.h b/include/uapi/fwctl/ub_fwctl.h index 1e40bd8f4a1c..411d8849d43b 100644 --- a/include/uapi/fwctl/ub_fwctl.h +++ b/include/uapi/fwctl/ub_fwctl.h @@ -53,6 +53,7 @@ enum ub_fwctl_cmdrpc_type { UTOOL_CMD_QUERY_DL_LINK_STATUS = 0x0013, UTOOL_CMD_QUERY_DL_LANE = 0x0014, UTOOL_CMD_QUERY_DL_BIT_ERR = 0x0015, + UTOOL_CMD_QUERY_DL_LINK_TRACE = 0x0016, UTOOL_CMD_QUERY_DL_BIST = 0x0017, UTOOL_CMD_CONF_DL_BIST = 0x0018, UTOOL_CMD_QUERY_DL_BIST_ERR = 0x0019, @@ -104,5 +105,8 @@ struct fwctl_pkt_in_table { __u32 index; }; +struct fwctl_pkt_in_port { + __u32 port_id; +}; #endif -- Gitee From 51106e493290d56e12e4e4cddb57414a80801cb6 Mon Sep 17 00:00:00 2001 From: Jiaqi Cheng Date: Thu, 21 Aug 2025 17:25:32 +0800 Subject: [PATCH 036/103] ub: ub_fwctl: support querying SCC and io_die related information. commit 59043edff2c8b6a5cdd746dda78e62db9a718d2e openEuler Support ub_fwctl query, support querying SCC version number and diagnostic log information. Support ub_fwctl to query all die information on the environment, including the chip ID of each IO die, die ID, and all enabled port information under that die (including port number, port type, and port link status). Signed-off-by: Jiaqi Cheng Signed-off-by: huwentao --- drivers/fwctl/ub/ub_cmd.c | 219 ++++++++++++++++++++++++++++++++++ drivers/fwctl/ub/ub_cmdq.h | 5 + drivers/fwctl/ub/ub_common.h | 2 + include/uapi/fwctl/ub_fwctl.h | 7 ++ 4 files changed, 233 insertions(+) diff --git a/drivers/fwctl/ub/ub_cmd.c b/drivers/fwctl/ub/ub_cmd.c index 22577289998c..da37575bb36f 100644 --- a/drivers/fwctl/ub/ub_cmd.c +++ b/drivers/fwctl/ub/ub_cmd.c @@ -6,6 +6,8 @@ #include "ub_cmdq.h" #include "ub_cmd.h" +#define UBCTL_SCC_SZ_1M 0x100000 + struct ubctl_query_trace { u32 port_id; u32 index; @@ -14,6 +16,13 @@ struct ubctl_query_trace { u32 data[]; }; +struct ubctl_scc_data { + u32 phy_addr_low; + u32 phy_addr_high; + u32 data_size; + u32 rsv[3]; +}; + static int ubctl_trace_data_deal(struct ubctl_dev *ucdev, struct ubctl_query_cmd_param *query_cmd_param, struct ubctl_cmd *cmd, u32 out_len, u32 offset) @@ -134,10 +143,220 @@ static int ubctl_query_dl_trace_data(struct ubctl_dev *ucdev, return ret; } +static int ubctl_scc_data_deal(struct ubctl_dev *ucdev, u32 index, + struct fwctl_rpc_ub_out *out, + struct ubctl_scc_data *scc) +{ +#define UBCTL_SCC_OUT_LEN ((UBCTL_SCC_SZ_1M) / (sizeof(u32))) +#define UBCTL_SCC_INDEX_MAX_NUM 1 + + u32 scc_data_len = scc->data_size / sizeof(u32); + u32 data_len = out->data_size / sizeof(u32); + u32 offset = index * UBCTL_SCC_OUT_LEN; + u32 *scc_data = out->data; + void __iomem *vir_addr; + u64 phy_addr; + u32 i, j; + + if (index > UBCTL_SCC_INDEX_MAX_NUM) { + ubctl_err(ucdev, "scc index is invalid, index = %u.\n", index); + return -EINVAL; + } + + phy_addr = UBCTL_GET_PHY_ADDR(scc->phy_addr_high, scc->phy_addr_low); + + vir_addr = ioremap(phy_addr, scc->data_size); + if (!vir_addr) { + ubctl_err(ucdev, "addr ioremap failed.\n"); + return -EFAULT; + } + + for (i = offset, j = 0; i < scc_data_len && j < data_len; i++, j++) + scc_data[j] = readl(vir_addr + i * sizeof(u32)); + + iounmap(vir_addr); + return 0; +} + +static int ubctl_scc_data_len_check(struct ubctl_dev *ucdev, u32 out_len, + u32 data_size, u32 scc_len) +{ +#define UBCTL_SCC_CACHE 0x200000 + + if (data_size != UBCTL_SCC_CACHE) { + ubctl_err(ucdev, "scc data size is not equal to 2M, data size = %u.\n", + data_size); + return -EINVAL; + } + + if (out_len != scc_len) { + ubctl_err(ucdev, "scc out len is invalid, out len = %u.\n", + out_len); + return -EINVAL; + } + + return 0; +} + +static int ubctl_scc_version_deal(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_cmd *cmd, u32 out_len, u32 offset) +{ +#define UBCTL_SCC_VERSION_SZ 24 + + struct fwctl_pkt_in_index *pkt_in = NULL; + struct ubctl_scc_data *scc = NULL; + int ret = 0; + + if (query_cmd_param->in->data_size != sizeof(struct fwctl_pkt_in_index)) { + ubctl_err(ucdev, "user data of scc version is invalid.\n"); + return -EINVAL; + } + pkt_in = (struct fwctl_pkt_in_index *)query_cmd_param->in->data; + scc = (struct ubctl_scc_data *)cmd->out_data; + + ret = ubctl_scc_data_len_check(ucdev, query_cmd_param->out_len, + scc->data_size, UBCTL_SCC_VERSION_SZ); + if (ret) { + ubctl_err(ucdev, "scc version data len check failed, ret = %d.\n", ret); + return -EINVAL; + } + + query_cmd_param->out->data_size = query_cmd_param->out_len; + scc->data_size = sizeof(u32); + + return ubctl_scc_data_deal(ucdev, pkt_in->index, query_cmd_param->out, scc); +} + +static int ubctl_scc_log_deal(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_cmd *cmd, u32 out_len, u32 offset) +{ + struct fwctl_pkt_in_index *pkt_in = (struct fwctl_pkt_in_index *)query_cmd_param->in->data; + struct ubctl_scc_data *scc = (struct ubctl_scc_data *)cmd->out_data; + int ret = 0; + + if (query_cmd_param->in->data_size != sizeof(*pkt_in)) { + ubctl_err(ucdev, "user data of scc log is invalid.\n"); + return -EINVAL; + } + + ret = ubctl_scc_data_len_check(ucdev, query_cmd_param->out_len, + scc->data_size, UBCTL_SCC_SZ_1M); + if (ret) { + ubctl_err(ucdev, "scc log data len check failed, ret = %d.\n", ret); + return -EINVAL; + } + + query_cmd_param->out->data_size = query_cmd_param->out_len; + + return ubctl_scc_data_deal(ucdev, pkt_in->index, query_cmd_param->out, scc); +} + +static int ubctl_query_scc_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_SCC_DFX, UBCTL_SCC_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + +static int ubctl_query_port_infos(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func, + u32 port_bitmap) +{ +#define UBCTL_U32_BIT_NUM 32U + + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_DL_LINK_STATUS_DFX, UBCTL_DL_LINK_STATUS_LEN, UBCTL_READ, NULL, 0 }, + }; + u32 iodie_len = sizeof(struct fwctl_rpc_ub_out) + UBCTL_IO_DIE_INFO_LEN; + u32 out_data_offset = UBCTL_IO_DIE_INFO_LEN / sizeof(u32); + struct fwctl_rpc_ub_out *out = query_cmd_param->out; + u32 out_mem_size = query_cmd_param->out_len; + u32 *pkt_in = query_cmd_param->in->data; + u32 data_size = out->data_size; + int port_num = 0; + int ret = 0; + u32 i; + + if (port_bitmap == 0) + return ret; + + struct fwctl_rpc_ub_out *out_temp __free(kvfree) = kvzalloc(iodie_len, GFP_KERNEL); + if (!out_temp) + return -ENOMEM; + + query_cmd_param->out = out_temp; + + for (i = 0; i < UBCTL_U32_BIT_NUM; i++) { + if (!(port_bitmap & (1UL << i))) + continue; + out_temp->data_size = 0; + *pkt_in = i; + ret = ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); + if (ret != 0) + break; + + if ((out_temp->data_size + out_data_offset * sizeof(u32)) > out_mem_size) { + ubctl_err(ucdev, "port info size = %u, total size = %u, offset size = %lu.\n", + out_temp->data_size, out_mem_size, + out_data_offset * sizeof(u32)); + ret = -ENOMEM; + break; + } + + memcpy(&out->data[out_data_offset], out_temp->data, out_temp->data_size); + data_size += out_temp->data_size; + out_data_offset += UBCTL_DL_LINK_STATUS_LEN / sizeof(u32); + port_num++; + } + + query_cmd_param->out = out; + out->data_size = data_size; + out->data[0] = port_num; + + return ret; +} + +static int ubctl_query_iodie_info_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_PORT_NUM_DFX, UBCTL_IO_DIE_INFO_LEN, UBCTL_READ, NULL, 0 }, + }; + u32 port_bitmap; + int ret; + + ret = ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); + if (ret != 0) + return ret; + + if (query_cmd_param->out->data_size < sizeof(u32)) + return -ENOMEM; + port_bitmap = *query_cmd_param->out->data; + + return ubctl_query_port_infos(ucdev, query_cmd_param, query_func, port_bitmap); +} + static struct ubctl_func_dispatch g_ubctl_query_func[] = { { UTOOL_CMD_QUERY_DL_LINK_TRACE, ubctl_query_dl_trace_data, ubctl_trace_data_deal }, + { UTOOL_CMD_QUERY_SCC_VERSION, ubctl_query_scc_data, ubctl_scc_version_deal}, + { UTOOL_CMD_QUERY_SCC_LOG, ubctl_query_scc_data, ubctl_scc_log_deal }, + + { UTOOL_CMD_QUERY_IO_DIE_PORT_INFO, ubctl_query_iodie_info_data, + ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_MAX, NULL, NULL } }; diff --git a/drivers/fwctl/ub/ub_cmdq.h b/drivers/fwctl/ub/ub_cmdq.h index 32323a4c0bbb..be46f852ca0d 100644 --- a/drivers/fwctl/ub/ub_cmdq.h +++ b/drivers/fwctl/ub/ub_cmdq.h @@ -39,12 +39,14 @@ #define UBCTL_QUERY_QOS_DFX 0xA00D +#define UBCTL_QUERY_SCC_DFX 0xA00E #define UBCTL_QUERY_SCC_DEBUG_DFX 0xA011 #define UBCTL_QUERY_QUEUE_DFX 0xA01B #define UBCTL_QUERY_UBOMMU_DFX 0xA016 +#define UBCTL_QUERY_PORT_NUM_DFX 0xA017 #define UBCTL_QUERY_PORT_INFO_DFX 0xA018 #define UBCTL_QUERY_ECC_2B_DFX 0xA019 @@ -87,10 +89,13 @@ #define UBCTL_QOS_LEN 284 +#define UBCTL_SCC_LEN 24 #define UBCTL_SCC_DEBUG_EN_LEN 24 #define UBCTL_QUEUE_LEN 120 +#define UBCTL_IO_DIE_INFO_LEN 24 + #define UBCTL_PORT_INFO_LEN 56 #define UBCTL_UBOMMU_LEN 56 diff --git a/drivers/fwctl/ub/ub_common.h b/drivers/fwctl/ub/ub_common.h index cde0a09b85e2..5debf2f14134 100644 --- a/drivers/fwctl/ub/ub_common.h +++ b/drivers/fwctl/ub/ub_common.h @@ -26,6 +26,8 @@ dev_info(&ucdev->fwctl.dev, "PID %u: " format, current->pid, \ ##__VA_ARGS__) +#define UBCTL_GET_PHY_ADDR(high, low) ((((u64)(high)) << 32) | (low)) + struct ubctl_dev { struct fwctl_device fwctl; DECLARE_KFIFO_PTR(ioctl_fifo, unsigned long); diff --git a/include/uapi/fwctl/ub_fwctl.h b/include/uapi/fwctl/ub_fwctl.h index 411d8849d43b..e2d412212102 100644 --- a/include/uapi/fwctl/ub_fwctl.h +++ b/include/uapi/fwctl/ub_fwctl.h @@ -73,12 +73,15 @@ enum ub_fwctl_cmdrpc_type { UTOOL_CMD_QUERY_QOS = 0x0051, + UTOOL_CMD_QUERY_SCC_VERSION = 0x0061, + UTOOL_CMD_QUERY_SCC_LOG = 0x0062, UTOOL_CMD_QUERY_SCC_DEBUG_EN = 0x0063, UTOOL_CMD_CONF_SCC_DEBUG_EN = 0x0064, UTOOL_CMD_QUERY_QUEUE = 0x0073, UTOOL_CMD_QUERY_PORT_INFO = 0x0081, + UTOOL_CMD_QUERY_IO_DIE_PORT_INFO = 0x0082, UTOOL_CMD_QUERY_UBOMMU = 0x0091, @@ -109,4 +112,8 @@ struct fwctl_pkt_in_port { __u32 port_id; }; +struct fwctl_pkt_in_index { + __u32 index; +}; + #endif -- Gitee From 351519ea00d4313210bc103b93c109a14c4dd885 Mon Sep 17 00:00:00 2001 From: Jiaqi Cheng Date: Thu, 21 Aug 2025 19:54:00 +0800 Subject: [PATCH 037/103] ub: ub_fwctl: query the MSG queue information and entry details within UB. commit 7ed154d74ca3de460e8ba97cc133c90501ae9d81 openEuler Query the MSG(message) queue information and entry details within UB 1. The dump corresponds to the physical registers under MSGQ, including queue pointer, queue depth, status, interrupt status, and other registers. 2. The dump corresponds to a specified entry of MSGQ, where the entry idx falls within the queue depth range. The dump covers the complete entries of SQE and CQE. Signed-off-by: Jiaqi Cheng Signed-off-by: huwentao --- drivers/fwctl/ub/ub_cmd.c | 305 ++++++++++++++++++++++++++++++++++ drivers/fwctl/ub/ub_cmdq.h | 2 + drivers/fwctl/ub/ub_common.h | 2 + include/uapi/fwctl/ub_fwctl.h | 2 + 4 files changed, 311 insertions(+) diff --git a/drivers/fwctl/ub/ub_cmd.c b/drivers/fwctl/ub/ub_cmd.c index da37575bb36f..86fae2dfd82c 100644 --- a/drivers/fwctl/ub/ub_cmd.c +++ b/drivers/fwctl/ub/ub_cmd.c @@ -3,9 +3,12 @@ * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ +#include + #include "ub_cmdq.h" #include "ub_cmd.h" +#define UBCTL_CQE_SIZE 16 #define UBCTL_SCC_SZ_1M 0x100000 struct ubctl_query_trace { @@ -23,6 +26,69 @@ struct ubctl_scc_data { u32 rsv[3]; }; +struct ubctl_msgq_to_user { + u32 sq_pi; + u32 sq_ci; + u32 sq_dep; + u32 sq_status; + u32 sq_int_mask; + u32 sq_int_status; + u32 sq_int_ro; + + u32 rq_pi; + u32 rq_ci; + u32 rq_dep; + u32 rq_entry_block_size; + u32 rq_status; + + u32 cq_pi; + u32 cq_ci; + u32 cq_dep; + u32 cq_status; + u32 cq_int_mask; + u32 cq_int_status; + u32 cq_int_ro; + + u32 rsvd[5]; +}; + +struct ubctl_msgq { + u32 sq_base_addr_low; + u32 sq_base_addr_high; + u32 sq_pi; + u32 sq_ci; + u32 sq_dep; + u32 sq_status; + u32 sq_int_mask; + u32 sq_int_status; + u32 sq_int_ro; + + u32 rq_base_addr_low; + u32 rq_base_addr_high; + u32 rq_pi; + u32 rq_ci; + u32 rq_dep; + u32 rq_entry_block_size; + u32 rq_status; + + u32 cq_base_addr_low; + u32 cq_base_addr_high; + u32 cq_pi; + u32 cq_ci; + u32 cq_dep; + u32 cq_status; + u32 cq_int_mask; + u32 cq_int_status; + u32 cq_int_ro; + + u32 resv[5]; +}; + +struct ubctl_msgq_phy_addr { + u64 sq_entry_phy_addr; + u64 cq_entry_phy_addr; +}; + static int ubctl_trace_data_deal(struct ubctl_dev *ucdev, struct ubctl_query_cmd_param *query_cmd_param, struct ubctl_cmd *cmd, u32 out_len, u32 offset) @@ -347,6 +413,240 @@ static int ubctl_query_iodie_info_data(struct ubctl_dev *ucdev, return ubctl_query_port_infos(ucdev, query_cmd_param, query_func, port_bitmap); } +static int ubctl_msgq_que_data_deal(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_cmd *cmd, u32 out_len, u32 offset) +{ + struct ubctl_msgq *msgq_que_info = (struct ubctl_msgq *)cmd->out_data; + struct ubctl_msgq_to_user *user_msgq_info = NULL; + u32 msgq_que_size = query_cmd_param->out_len; + + if (cmd->out_len != out_len || + msgq_que_size != sizeof(struct ubctl_msgq_to_user)) + return -EINVAL; + + user_msgq_info = (struct ubctl_msgq_to_user *)(query_cmd_param->out->data); + + user_msgq_info->sq_pi = msgq_que_info->sq_pi; + user_msgq_info->sq_ci = msgq_que_info->sq_ci; + user_msgq_info->sq_dep = msgq_que_info->sq_dep; + user_msgq_info->sq_status = msgq_que_info->sq_status; + user_msgq_info->sq_int_mask = msgq_que_info->sq_int_mask; + user_msgq_info->sq_int_status = msgq_que_info->sq_int_status; + user_msgq_info->sq_int_ro = msgq_que_info->sq_int_ro; + + user_msgq_info->rq_pi = msgq_que_info->rq_pi; + user_msgq_info->rq_ci = msgq_que_info->rq_ci; + user_msgq_info->rq_dep = msgq_que_info->rq_dep; + user_msgq_info->rq_entry_block_size = msgq_que_info->rq_entry_block_size; + user_msgq_info->rq_status = msgq_que_info->rq_status; + + user_msgq_info->cq_pi = msgq_que_info->cq_pi; + user_msgq_info->cq_ci = msgq_que_info->cq_ci; + user_msgq_info->cq_dep = msgq_que_info->cq_dep; + user_msgq_info->cq_status = msgq_que_info->cq_status; + user_msgq_info->cq_int_mask = msgq_que_info->cq_int_mask; + user_msgq_info->cq_int_status = msgq_que_info->cq_int_status; + user_msgq_info->cq_int_ro = msgq_que_info->cq_int_ro; + + query_cmd_param->out->data_size = msgq_que_size; + + return 0; +} + +static int ubctl_msgq_is_dump(void __iomem *entry_addr) +{ +#define UBCTL_MSGQ_PROTOCOL_OPCODE 5 +#define UBCTL_MSGQ_OPCODE_START 9 +#define UBCTL_MSGQ_OPCODE_END 11 + + u32 first_data = readl(entry_addr); + u32 protocol_op_code = 0; + u32 task_type = 0; + + protocol_op_code = UBCTL_EXTRACT_BITS(first_data, + UBCTL_MSGQ_OPCODE_START, + UBCTL_MSGQ_OPCODE_END); + task_type = UBCTL_EXTRACT_BITS(first_data, 0, 1); + if (task_type == 0 && protocol_op_code == UBCTL_MSGQ_PROTOCOL_OPCODE) + return -EINVAL; + + return 0; +} + +static int ubctl_msgq_entry_move_data(struct ubctl_query_cmd_param *query_cmd_param, + u32 offset, u32 block_size, + void __iomem *entry_addr) +{ + u32 msgq_entry_data_size = block_size + offset * sizeof(u32); + u32 *data_offset = query_cmd_param->out->data + offset; + u32 i; + + if (msgq_entry_data_size > query_cmd_param->out_len) + return -EINVAL; + + for (i = 0; i < block_size / sizeof(u32); i++) + data_offset[i] = readl(entry_addr + i); + + return 0; +} + +static int ubctl_msgq_check_index(struct ubctl_dev *ucdev, u32 entry_index, + struct ubctl_msgq *entry_info) +{ + if (entry_index >= entry_info->sq_dep || + entry_index >= entry_info->cq_dep) { + ubctl_err(ucdev, "index is illegal, index = %u.\n", entry_index); + return -EINVAL; + } + + return 0; +} + +static int ubctl_msgq_all_get_phy_addr(struct ubctl_dev *ucdev, u32 entry_index, + struct ubctl_msgq_phy_addr *entry_phy_addr, + struct ubctl_msgq *entry_info) +{ +#define UBCTL_SQE_SIZE 16 + + u64 base_addr; + int ret; + + ret = ubctl_msgq_check_index(ucdev, entry_index, entry_info); + if (ret) + return ret; + + base_addr = UBCTL_GET_PHY_ADDR(entry_info->sq_base_addr_high, + entry_info->sq_base_addr_low); + if (!base_addr) { + ubctl_err(ucdev, "sqe msgq not initialized.\n"); + return -EINVAL; + } + + entry_phy_addr->sq_entry_phy_addr = base_addr + + entry_index * UBCTL_SQE_SIZE; + + base_addr = UBCTL_GET_PHY_ADDR(entry_info->cq_base_addr_high, + entry_info->cq_base_addr_low); + if (!base_addr) { + ubctl_err(ucdev, "cqe msgq not initialized.\n"); + return -EINVAL; + } + + entry_phy_addr->cq_entry_phy_addr = base_addr + + entry_index * UBCTL_CQE_SIZE; + + return 0; +} + +static int ubctl_msgq_sq_entry_data_deal(struct ubctl_dev *ucdev, + u64 sq_entry_phy_addr, + struct ubctl_query_cmd_param *query_cmd_param) +{ +#define UBCTL_SQE_TO_USER_SIZE 8 + + void __iomem *sq_entry_addr; + int ret = 0; + + sq_entry_addr = memremap(sq_entry_phy_addr, UBCTL_SQE_TO_USER_SIZE, MEMREMAP_WB); + if (!sq_entry_addr) + return -EFAULT; + + ret = ubctl_msgq_is_dump(sq_entry_addr); + if (ret) { + ubctl_err(ucdev, "this entry cannot be dumped, sqe is SPDM verified msg.\n"); + goto err_exec; + } + + ret = ubctl_msgq_entry_move_data(query_cmd_param, 0, + UBCTL_SQE_TO_USER_SIZE, sq_entry_addr); + if (ret) + ubctl_err(ucdev, "move sqe data failed.\n"); + +err_exec: + memunmap(sq_entry_addr); + return ret; +} + +static int ubctl_msgq_cq_entry_data_deal(struct ubctl_dev *ucdev, + u64 cq_entry_phy_addr, + struct ubctl_query_cmd_param *query_cmd_param) +{ +#define UBCTL_CQE_OFFSET 2 + + void __iomem *cq_entry_addr; + int ret = 0; + + cq_entry_addr = memremap(cq_entry_phy_addr, UBCTL_CQE_SIZE, MEMREMAP_WB); + if (!cq_entry_addr) + return -EFAULT; + + ret = ubctl_msgq_is_dump(cq_entry_addr); + if (ret) { + ubctl_err(ucdev, "this entry cannot be dumped, cqe is SPDM verified msg.\n"); + goto err_exec; + } + + ret = ubctl_msgq_entry_move_data(query_cmd_param, UBCTL_CQE_OFFSET, + UBCTL_CQE_SIZE, cq_entry_addr); + if (ret) + ubctl_err(ucdev, "move cqe data failed.\n"); + +err_exec: + memunmap(cq_entry_addr); + return ret; +} + +static int ubctl_msgq_entry_data_deal(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_cmd *cmd, u32 out_len, u32 offset) +{ + struct ubctl_msgq *entry_info = (struct ubctl_msgq *)cmd->out_data; + u32 msgq_entry_max_len = query_cmd_param->out_len; + struct ubctl_msgq_phy_addr entry_phy_addr = {}; + u32 entry_index = 0; + int ret = 0; + + if (query_cmd_param->in->data_size != sizeof(struct fwctl_pkt_in_index)) { + ubctl_err(ucdev, "user data of msgq is invalid.\n"); + return -EINVAL; + } + entry_index = ((struct fwctl_pkt_in_index *)query_cmd_param->in->data)->index; + + ret = ubctl_msgq_all_get_phy_addr(ucdev, entry_index, &entry_phy_addr, + entry_info); + if (ret) + return ret; + + ret = ubctl_msgq_sq_entry_data_deal(ucdev, + entry_phy_addr.sq_entry_phy_addr, + query_cmd_param); + if (ret) + return ret; + + ret = ubctl_msgq_cq_entry_data_deal(ucdev, + entry_phy_addr.cq_entry_phy_addr, + query_cmd_param); + if (ret) + return ret; + + query_cmd_param->out->data_size = msgq_entry_max_len; + + return ret; +} + +static int ubctl_query_msgq_que_stats_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ + struct ubctl_query_dp query_dp[] = { + { UBCTL_QUERY_MSGQ_DFX, UBCTL_MSGQ_LEN, UBCTL_READ, NULL, 0 }, + }; + + return ubctl_query_data(ucdev, query_cmd_param, query_func, + query_dp, ARRAY_SIZE(query_dp)); +} + static struct ubctl_func_dispatch g_ubctl_query_func[] = { { UTOOL_CMD_QUERY_DL_LINK_TRACE, ubctl_query_dl_trace_data, ubctl_trace_data_deal }, @@ -354,6 +654,11 @@ static struct ubctl_func_dispatch g_ubctl_query_func[] = { { UTOOL_CMD_QUERY_SCC_VERSION, ubctl_query_scc_data, ubctl_scc_version_deal}, { UTOOL_CMD_QUERY_SCC_LOG, ubctl_query_scc_data, ubctl_scc_log_deal }, + { UTOOL_CMD_QUERY_MSGQ_QUE_STATS, ubctl_query_msgq_que_stats_data, + ubctl_msgq_que_data_deal }, + { UTOOL_CMD_QUERY_MSGQ_ENTRY, ubctl_query_msgq_que_stats_data, + ubctl_msgq_entry_data_deal }, + { UTOOL_CMD_QUERY_IO_DIE_PORT_INFO, ubctl_query_iodie_info_data, ubctl_query_data_deal }, diff --git a/drivers/fwctl/ub/ub_cmdq.h b/drivers/fwctl/ub/ub_cmdq.h index be46f852ca0d..2855cb8dff00 100644 --- a/drivers/fwctl/ub/ub_cmdq.h +++ b/drivers/fwctl/ub/ub_cmdq.h @@ -42,6 +42,7 @@ #define UBCTL_QUERY_SCC_DFX 0xA00E #define UBCTL_QUERY_SCC_DEBUG_DFX 0xA011 +#define UBCTL_QUERY_MSGQ_DFX 0xA00F #define UBCTL_QUERY_QUEUE_DFX 0xA01B #define UBCTL_QUERY_UBOMMU_DFX 0xA016 @@ -92,6 +93,7 @@ #define UBCTL_SCC_LEN 24 #define UBCTL_SCC_DEBUG_EN_LEN 24 +#define UBCTL_MSGQ_LEN 120 #define UBCTL_QUEUE_LEN 120 #define UBCTL_IO_DIE_INFO_LEN 24 diff --git a/drivers/fwctl/ub/ub_common.h b/drivers/fwctl/ub/ub_common.h index 5debf2f14134..ab6761ffaad8 100644 --- a/drivers/fwctl/ub/ub_common.h +++ b/drivers/fwctl/ub/ub_common.h @@ -27,6 +27,8 @@ ##__VA_ARGS__) #define UBCTL_GET_PHY_ADDR(high, low) ((((u64)(high)) << 32) | (low)) +#define UBCTL_EXTRACT_BITS(value, start, end) \ + (((value) >> (start)) & ((1UL << ((end) - (start) + 1)) - 1)) struct ubctl_dev { struct fwctl_device fwctl; diff --git a/include/uapi/fwctl/ub_fwctl.h b/include/uapi/fwctl/ub_fwctl.h index e2d412212102..139a413bf94a 100644 --- a/include/uapi/fwctl/ub_fwctl.h +++ b/include/uapi/fwctl/ub_fwctl.h @@ -78,6 +78,8 @@ enum ub_fwctl_cmdrpc_type { UTOOL_CMD_QUERY_SCC_DEBUG_EN = 0x0063, UTOOL_CMD_CONF_SCC_DEBUG_EN = 0x0064, + UTOOL_CMD_QUERY_MSGQ_QUE_STATS = 0x0071, + UTOOL_CMD_QUERY_MSGQ_ENTRY = 0x0072, UTOOL_CMD_QUERY_QUEUE = 0x0073, UTOOL_CMD_QUERY_PORT_INFO = 0x0081, -- Gitee From 2d14d90e5109419b8774ccb523d51cdebbf393d8 Mon Sep 17 00:00:00 2001 From: Jiaqi Cheng Date: Thu, 21 Aug 2025 20:14:11 +0800 Subject: [PATCH 038/103] ub: ub_fwctl: support ummu data processing commit d44bcbc048ceacc0fdd3a4fb5bcb3b808c395582 openEuler ub_fwctl add ummu(UB Memory Management Unit) module cmd, support query all ummu register and support query or config sync_timeout_open register. Signed-off-by: Jiaqi Cheng Signed-off-by: huwentao --- drivers/fwctl/ub/ub_cmd.c | 428 ++++++++++++++++++++++++++++++++++ drivers/fwctl/ub/ub_cmdq.h | 126 ++++++++++ include/uapi/fwctl/ub_fwctl.h | 9 + 3 files changed, 563 insertions(+) diff --git a/drivers/fwctl/ub/ub_cmd.c b/drivers/fwctl/ub/ub_cmd.c index 86fae2dfd82c..5b3895107b31 100644 --- a/drivers/fwctl/ub/ub_cmd.c +++ b/drivers/fwctl/ub/ub_cmd.c @@ -4,6 +4,7 @@ */ #include +#include #include "ub_cmdq.h" #include "ub_cmd.h" @@ -11,6 +12,133 @@ #define UBCTL_CQE_SIZE 16 #define UBCTL_SCC_SZ_1M 0x100000 +static u32 g_ubctl_ummu_reg_addr[] = { + // KCMD + UBCTL_UMMU_SWIF_KCMDQ_DFX_KCMD_STATUS, + UBCTL_UMMU_SWIF_KCMDQ_DFX_KCMD_ERR_STATUS, + // CMD_CTRL + UBCTL_UMMU_SWIF_KCMDQ_DFX_SNP_ERR_CNT, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_0, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_1, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_2, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_3, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_4, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_5, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_6, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_7, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_8, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_9, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_10, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_11, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_12, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_13, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_14, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_15, + UBCTL_UMMU_SWIF_KCMDQ_DFX_SNP_STATUS, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_CTRL_STATUS1, + UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_CTRL_STATUS2, + UBCTL_UMMU_SYNC_TIMEOUT_INFO, + UBCTL_UMMU_DVM_RECEIVE_REQ_CNT, + UBCTL_UMMU_DVM_SEND_REQ_CNT, + UBCTL_UMMU_DVM_REQ_INFO0, + UBCTL_UMMU_DVM_REQ_INFO1, + // UCMD + UBCTL_UMMU_SWIF_UMCMD_DFX0, + UBCTL_UMMU_SWIF_UMCMD_DFX1, + UBCTL_UMMU_SWIF_UMCMD_DFX2, + UBCTL_UMMU_SWIF_UMCMD_DFX3, + UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_0, + UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_1, + UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_2, + UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_3, + UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_4, + UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_5, + UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_6, + UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX1, + UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX2, + UBCTL_UMMU_SWIF_UMCMD_CACHE_DFX1, + UBCTL_UMMU_SWIF_UMCMD_CACHE_DFX2, + UBCTL_UMMU_SWIF_UMCMD_CACHE_DFX3, + UBCTL_UMMU_SWIF_UMCMD_CACHE_DFX4, + UBCTL_UMMU_SWIF_UMCMD_CACHE_DFX5, + UBCTL_UMMU_SWIF_UMCMD_CACHE_DFX6, + // EVENT + UBCTL_UMMU_SWIF_EVENTQ_DFX_DROP_CNT, + UBCTL_UMMU_GLB_INT_EN, + UBCTL_UMMU_PMCG_INT_EN, + UBCTL_UMMU_INT_MASK, + UBCTL_UMMU_CTRL1, + UBCTL_UMMU_SPEC_DEF_DFX, + UBCTL_UMMU_TECT_BASE_CFG, + UBCTL_UMMU_ERR_STATUS_0, + UBCTL_UMMU_ROOT_GPF_FAR_L, + UBCTL_UMMU_ROOT_GPF_FAR_H, + UBCTL_UMMU_EVENT_QUE_PI, + UBCTL_UMMU_EVENT_QUE_CI, + // UBIF + UBCTL_UMMU_UBIF_DFX0, + UBCTL_UMMU_UBIF_DFX1, + UBCTL_UMMU_UBIF_DSTEID_DFX, + UBCTL_UMMU_UBIF_SYNC_DFX, + UBCTL_UMMU_UBIF_KV_CACHE_NS_NSE_MISMATCH_DFX0, + UBCTL_UMMU_UBIF_KV_CACHE_NS_NSE_MISMATCH_DFX1, + UBCTL_UMMU_UBIF_KV_CACHE_NS_NSE_MISMATCH_DFX2, + UBCTL_UMMU_UBIF_KV_CACHE_NS_NSE_MISMATCH_DFX3, + UBCTL_UMMU_UBIF_KV_CACHE_NS_NSE_MISMATCH_DFX4, + // TBU + UBCTL_UMMU_TBU_TLB_LKUP_PROC, + UBCTL_UMMU_TBU_TLB_STAT, + UBCTL_UMMU_TBU_TLB_FAULT_CNT, + UBCTL_UMMU_TBU_PLB_LKUP_PROC, + UBCTL_UMMU_TBU_PLB_STAT, + UBCTL_UMMU_TBU_PLB_FAULT_CNT, + UBCTL_UMMU_TBU_INVLD_MG_INFO, + UBCTL_UMMU_TBU_RAB_STAT, + UBCTL_UMMU_TBU_CNT, + UBCTL_UMMU_DFX_TBU_PERM_ERR_CNT, + UBCTL_UMMU_TBU_DFX0, + UBCTL_UMMU_TBU_DFX1, + UBCTL_UMMU_TBU_RAB_ENTRY_INFO_0_7_15, + // TCU + UBCTL_UMMU_TCU_PTW_QUEUE_STAT_0_47, + UBCTL_UMMU_TCU_PPTW_QUEUE_STAT_0_39, + // CFG + UBCTL_UMMU_DFX_ECC_MONITOR_0, + UBCTL_UMMU_DFX_ECC_MONITOR_1, + UBCTL_UMMU_CFG_DFX_CFGBUS_STATUS, + // GPC + UBCTL_UMMU_GPC_QUEUE_STAT_0_15, + // SKY + UBCTL_UMMU_SKY_QUEUE_STAT3_SP_0_63, + // MCMD + UBCTL_UMMU_MCMD_QUE_PI_0, + UBCTL_UMMU_MCMD_QUE_PI_1, + UBCTL_UMMU_MCMD_QUE_PI_2, + UBCTL_UMMU_MCMD_QUE_PI_3, + UBCTL_UMMU_MCMD_QUE_PI_4, + UBCTL_UMMU_MCMD_QUE_PI_5, + UBCTL_UMMU_MCMD_QUE_PI_6, + UBCTL_UMMU_MCMD_QUE_PI_7, + UBCTL_UMMU_MCMD_QUE_CI_0, + UBCTL_UMMU_MCMD_QUE_CI_1, + UBCTL_UMMU_MCMD_QUE_CI_2, + UBCTL_UMMU_MCMD_QUE_CI_3, + UBCTL_UMMU_MCMD_QUE_CI_4, + UBCTL_UMMU_MCMD_QUE_CI_5, + UBCTL_UMMU_MCMD_QUE_CI_6, + UBCTL_UMMU_MCMD_QUE_CI_7, + // UMMU_EN + UBCTL_UMMU_CTRL0, + // OTHER + UBCTL_UMMU_SYNC_TIMEOUT_OPEN, +}; + +struct ubctl_ummu_relation { + u32 reg_addr; + u32 reg_config_addr; + u32 reg_count; +}; + struct ubctl_query_trace { u32 port_id; u32 index; @@ -647,6 +775,302 @@ static int ubctl_query_msgq_que_stats_data(struct ubctl_dev *ucdev, query_dp, ARRAY_SIZE(query_dp)); } +static int compare_resources(const void *a, const void *b) +{ + const struct resource *ra = *(const struct resource **)a; + const struct resource *rb = *(const struct resource **)b; + + if (ra->start < rb->start) + return -1; + if (ra->start > rb->start) + return 1; + return 0; +} + +static struct resource *ubctl_find_and_sort_resources(struct ubctl_dev *ucdev, + struct resource *root, + const char *name_substr, + u32 ummu_id) +{ +#define UBCL_MAX_UMMU_NUM 32U + + struct resource *entry_arr[UBCL_MAX_UMMU_NUM] = {}; + struct resource *p; + u32 count = 0; + + /* + * To traverse the UMMU memory subtree, only need to traverse the child + * subtree of the root node. + */ + for (p = root->child; p; p = p->sibling) { + if (!p->name || !strstr(p->name, name_substr)) + continue; + if (count >= UBCL_MAX_UMMU_NUM) { + ubctl_err(ucdev, "ummu resources is more than max num = %u.\n", + UBCL_MAX_UMMU_NUM); + return NULL; + } + entry_arr[count] = p; + count++; + } + + if (ummu_id >= count) { + ubctl_err(ucdev, "ummuid = %u out of range, current count = %u\n", + ummu_id, count); + return NULL; + } + + sort(entry_arr, count, sizeof(struct resource *), compare_resources, NULL); + + return entry_arr[ummu_id]; +} + +static inline u32 ubctl_ummu_get_register_offset(u32 index) +{ + return g_ubctl_ummu_reg_addr[index] - UBCTL_UMMU_REGISTER_BASE; +} + +static inline u32 ubctl_ummu_get_reg_count(void) +{ +#define UBCTL_UMMU_REPEAT_REG_TYPE_COUNT 5U + + return ARRAY_SIZE(g_ubctl_ummu_reg_addr) + UBCTL_UMMU_GPC_QUEUE_COUNT + + UBCTL_UMMU_SKY_QUEUE_COUNT + UBCTL_UMMU_TCU_PTW_QUEUE_COUNT + + UBCTL_UMMU_TCU_PPTW_QUEUE_COUNT + UBCTL_UMMU_ENTRY_NUM * + UBCTL_UMMU_BANK_NUM - UBCTL_UMMU_REPEAT_REG_TYPE_COUNT; +} + +struct ubctl_reg_pro_cmd { + struct ubctl_dev *ucdev; + u32 reg_index; + void __iomem *map_addr; + u32 *ummu_data; + u32 map_length; + u32 *index_offset; +}; + +static int ubctl_ummu_normal_read(struct ubctl_reg_pro_cmd *cmd) +{ + u32 ummu_reg_cnt = ubctl_ummu_get_reg_count(); + u32 reg_addr_offset; + + reg_addr_offset = ubctl_ummu_get_register_offset(cmd->reg_index); + if ((reg_addr_offset >= cmd->map_length) || (*cmd->index_offset >= ummu_reg_cnt)) { + ubctl_err(cmd->ucdev, "ummu reg offset is bigger than map length, index=%u, reg offset=%u, map length=%u.\n", + *cmd->index_offset, reg_addr_offset, cmd->map_length); + return -EFAULT; + } + cmd->ummu_data[*cmd->index_offset] = readl(cmd->map_addr + reg_addr_offset); + (*cmd->index_offset)++; + + return 0; +} + +static int ubctl_ummu_process_repeat_reg(struct ubctl_reg_pro_cmd *cmd) +{ + static struct ubctl_ummu_relation ummu_relation[] = { + { UBCTL_UMMU_GPC_QUEUE_STAT_0_15, UBCTL_UMMU_GPC_QUEUE_POINTER, + UBCTL_UMMU_GPC_QUEUE_COUNT }, + { UBCTL_UMMU_SKY_QUEUE_STAT3_SP_0_63, UBCTL_UMMU_SKY_QUEUE_POINTER_SP, + UBCTL_UMMU_SKY_QUEUE_COUNT }, + { UBCTL_UMMU_TCU_PTW_QUEUE_STAT_0_47, UBCTL_UMMU_TCU_PTW_QUEUE_POINTER, + UBCTL_UMMU_TCU_PTW_QUEUE_COUNT }, + { UBCTL_UMMU_TCU_PPTW_QUEUE_STAT_0_39, UBCTL_UMMU_TCU_PPTW_QUEUE_POINTER, + UBCTL_UMMU_TCU_PPTW_QUEUE_COUNT } + }; + + u32 read_reg_offset, set_reg_offset, write_count, i, j; + u32 ummu_reg_cnt = ubctl_ummu_get_reg_count(); + + for (i = 0; i < ARRAY_SIZE(ummu_relation); i++) { + if (ummu_relation[i].reg_addr != g_ubctl_ummu_reg_addr[cmd->reg_index]) + continue; + write_count = ummu_relation[i].reg_count; + set_reg_offset = ummu_relation[i].reg_config_addr - + UBCTL_UMMU_REGISTER_BASE; + read_reg_offset = ummu_relation[i].reg_addr - + UBCTL_UMMU_REGISTER_BASE; + if ((set_reg_offset >= cmd->map_length) || + (read_reg_offset >= cmd->map_length)) { + ubctl_err(cmd->ucdev, "ummu set or read reg offset is bigger than map length, set offset=%u, read offset=%u, map length=%u.\n", + set_reg_offset, read_reg_offset, cmd->map_length); + return -EFAULT; + } + + for (j = 0; j < write_count; j++, (*cmd->index_offset)++) { + writel(j, cmd->map_addr + set_reg_offset); + if (*cmd->index_offset >= ummu_reg_cnt) { + ubctl_err(cmd->ucdev, "index offset is bigger than ummu reg count, index offset=%u, ummu reg count=%u.\n", + *cmd->index_offset, ummu_reg_cnt); + return -EFAULT; + } + cmd->ummu_data[*cmd->index_offset] = readl(cmd->map_addr + + read_reg_offset); + } + return 0; + } + + return ubctl_ummu_normal_read(cmd); +} + +static int ubctl_ummu_process_reg(struct ubctl_reg_pro_cmd *cmd) +{ +#define UBCTL_TBU_MASK 0xFFFFFC00U +#define UBCTL_BANK_OFFSET 6 + + u32 read_reg_offset, set_reg_offset, origin_value, value, i, j; + u32 ummu_reg_cnt = ubctl_ummu_get_reg_count(); + + if (g_ubctl_ummu_reg_addr[cmd->reg_index] != UBCTL_UMMU_TBU_RAB_ENTRY_INFO_0_7_15) + return ubctl_ummu_process_repeat_reg(cmd); + + set_reg_offset = UBCTL_UMMU_TBU_RAB_FUNC_EN - UBCTL_UMMU_REGISTER_BASE; + read_reg_offset = UBCTL_UMMU_TBU_RAB_ENTRY_INFO_0_7_15 - + UBCTL_UMMU_REGISTER_BASE; + if ((set_reg_offset >= cmd->map_length) || + (read_reg_offset >= cmd->map_length)) { + ubctl_err(cmd->ucdev, "ummu set or read reg offset is bigger than map length, set offset=%u, read offset=%u, map length=%u.\n", + set_reg_offset, read_reg_offset, cmd->map_length); + return -EFAULT; + } + + origin_value = readl(cmd->map_addr + set_reg_offset); + origin_value &= UBCTL_TBU_MASK; + for (i = 0; i < UBCTL_UMMU_BANK_NUM; i++) { + for (j = 0; j < UBCTL_UMMU_ENTRY_NUM; j++, (*cmd->index_offset)++) { + value = (i << UBCTL_BANK_OFFSET) | j | origin_value; + writel(value, cmd->map_addr + set_reg_offset); + if (*cmd->index_offset >= ummu_reg_cnt) { + ubctl_err(cmd->ucdev, "index offset is bigger than ummu reg count, index offset=%u, ummu reg count=%u.\n", + *cmd->index_offset, ummu_reg_cnt); + return -EFAULT; + } + cmd->ummu_data[*cmd->index_offset] = readl(cmd->map_addr + + read_reg_offset); + } + } + return 0; +} + +static int ubctl_ummu_copy_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + void __iomem *map_addr, u32 map_length) +{ + u32 ummu_array_cnt = ARRAY_SIZE(g_ubctl_ummu_reg_addr); + u32 ummu_reg_cnt = ubctl_ummu_get_reg_count(); + u32 *ummu_data = query_cmd_param->out->data; + u32 index_offset = 0; + int ret; + u32 i; + + struct ubctl_reg_pro_cmd reg_pro_cmd = { + .ucdev = ucdev, + .reg_index = 0, + .map_addr = map_addr, + .ummu_data = ummu_data, + .map_length = map_length, + .index_offset = &index_offset, + }; + + if (ummu_reg_cnt * sizeof(u32) > query_cmd_param->out_len) { + ubctl_err(ucdev, "ummu reg size is big than out len, reg sie=%lu, out len=%lu.\n", + ummu_reg_cnt * sizeof(u32), query_cmd_param->out_len); + return -EINVAL; + } + + for (i = 0; i < ummu_array_cnt; i++) { + reg_pro_cmd.reg_index = i; + ret = ubctl_ummu_process_reg(®_pro_cmd); + if (ret) { + ubctl_err(ucdev, "ummu process reg failed, ret=%d.\n", ret); + return ret; + } + } + query_cmd_param->out->data_size = ummu_reg_cnt * sizeof(u32); + + return 0; +} + +static int ubctl_ummu_proc_all_data(struct ubctl_dev *ucdev, struct resource *res, + struct ubctl_query_cmd_param *query_cmd_param) +{ + u32 map_length = UBCTL_UMMU_REGISTER_MAX_ADDR - UBCTL_UMMU_REGISTER_BASE; + void __iomem *vaddr; + int ret; + + vaddr = ioremap(res->start + UBCTL_UMMU_REGISTER_BASE, map_length); + if (!vaddr) { + ubctl_err(ucdev, "ioremap ummu reg base failed, map length = %u.\n", + map_length); + return -ENOMEM; + } + ret = ubctl_ummu_copy_data(ucdev, query_cmd_param, vaddr, map_length); + iounmap(vaddr); + + return ret; +} + +static int ubctl_ummu_proc_sync_data(struct resource *res, + struct ubctl_query_cmd_param *query_cmd_param, + struct fwctl_pkt_in_ummuid_value *ummu_data, + bool is_query) +{ + u32 *out_data = query_cmd_param->out->data; + u32 map_length = sizeof(u32); + void __iomem *vaddr; + + if (sizeof(u32) > query_cmd_param->out_len) + return -EINVAL; + + vaddr = ioremap(res->start + UBCTL_UMMU_SYNC_TIMEOUT_OPEN, map_length); + if (!vaddr) + return -ENOMEM; + + if (is_query) { + *out_data = readl(vaddr); + } else { + *out_data = ummu_data->value; + writel(*out_data, vaddr); + } + + query_cmd_param->out->data_size = sizeof(u32); + iounmap(vaddr); + + return 0; +} + +static int ubctl_ummu_process_data(struct ubctl_dev *ucdev, + struct ubctl_query_cmd_param *query_cmd_param, + struct ubctl_func_dispatch *query_func) +{ +#define UMMU_NAME_STR "ummu." + + struct fwctl_pkt_in_ummuid_value *ummu_data; + struct resource *root = &iomem_resource; + struct resource *res; + + if (query_cmd_param->in->data_size != sizeof(*ummu_data)) { + ubctl_err(ucdev, "invalid ummuid value size = %u.\n", + query_cmd_param->in->data_size); + return -EINVAL; + } + + ummu_data = (struct fwctl_pkt_in_ummuid_value *)(query_cmd_param->in->data); + res = ubctl_find_and_sort_resources(ucdev, root, UMMU_NAME_STR, + ummu_data->ummu_id); + if (!res) + return -EINVAL; + + if (query_func->rpc_cmd == UTOOL_CMD_QUERY_UMMU_ALL) + return ubctl_ummu_proc_all_data(ucdev, res, query_cmd_param); + if (query_func->rpc_cmd == UTOOL_CMD_QUERY_UMMU_SYNC) + return ubctl_ummu_proc_sync_data(res, query_cmd_param, ummu_data, true); + if (query_func->rpc_cmd == UTOOL_CMD_CONFIG_UMMU_SYNC) + return ubctl_ummu_proc_sync_data(res, query_cmd_param, ummu_data, false); + + return -EINVAL; +} + static struct ubctl_func_dispatch g_ubctl_query_func[] = { { UTOOL_CMD_QUERY_DL_LINK_TRACE, ubctl_query_dl_trace_data, ubctl_trace_data_deal }, @@ -662,6 +1086,10 @@ static struct ubctl_func_dispatch g_ubctl_query_func[] = { { UTOOL_CMD_QUERY_IO_DIE_PORT_INFO, ubctl_query_iodie_info_data, ubctl_query_data_deal }, + { UTOOL_CMD_QUERY_UMMU_ALL, ubctl_ummu_process_data, NULL }, + { UTOOL_CMD_QUERY_UMMU_SYNC, ubctl_ummu_process_data, NULL }, + { UTOOL_CMD_CONFIG_UMMU_SYNC, ubctl_ummu_process_data, NULL }, + { UTOOL_CMD_QUERY_MAX, NULL, NULL } }; diff --git a/drivers/fwctl/ub/ub_cmdq.h b/drivers/fwctl/ub/ub_cmdq.h index 2855cb8dff00..a8a4e63c42e3 100644 --- a/drivers/fwctl/ub/ub_cmdq.h +++ b/drivers/fwctl/ub/ub_cmdq.h @@ -106,4 +106,130 @@ #define UBCTL_QUERY_DEBUG_EN 24 +#define UBCTL_UMMU_CTRL0 0x0030 +#define UBCTL_UMMU_CTRL1 0x0038 +#define UBCTL_UMMU_TECT_BASE_CFG 0x0078 +#define UBCTL_UMMU_MCMD_QUE_PI_0 0x0108 +#define UBCTL_UMMU_MCMD_QUE_CI_0 0x010C +#define UBCTL_UMMU_MCMD_QUE_PI_1 0x0118 +#define UBCTL_UMMU_MCMD_QUE_CI_1 0x011C +#define UBCTL_UMMU_MCMD_QUE_PI_2 0x0128 +#define UBCTL_UMMU_MCMD_QUE_CI_2 0x012C +#define UBCTL_UMMU_MCMD_QUE_PI_3 0x0138 +#define UBCTL_UMMU_MCMD_QUE_CI_3 0x013C +#define UBCTL_UMMU_MCMD_QUE_PI_4 0x0148 +#define UBCTL_UMMU_MCMD_QUE_CI_4 0x014C +#define UBCTL_UMMU_MCMD_QUE_PI_5 0x0158 +#define UBCTL_UMMU_MCMD_QUE_CI_5 0x015C +#define UBCTL_UMMU_MCMD_QUE_PI_6 0x0168 +#define UBCTL_UMMU_MCMD_QUE_CI_6 0x016C +#define UBCTL_UMMU_MCMD_QUE_PI_7 0x0178 +#define UBCTL_UMMU_MCMD_QUE_CI_7 0x017C +#define UBCTL_UMMU_EVENT_QUE_PI 0x1108 +#define UBCTL_UMMU_EVENT_QUE_CI 0x110C +#define UBCTL_UMMU_EVENT_QUE_USI_ADDR0 0x1110 +#define UBCTL_UMMU_EVENT_QUE_USI_ADDR1 0x1114 +#define UBCTL_UMMU_GLB_INT_EN 0x1130 +#define UBCTL_UMMU_GLB_ERR_INT_USI_ADDR0 0x1140 +#define UBCTL_UMMU_GLB_ERR_INT_USI_ADDR1 0x1144 +#define UBCTL_UMMU_ERR_STATUS_0 0x2010 +#define UBCTL_UMMU_INT_MASK 0x3404 +#define UBCTL_UMMU_SYNC_TIMEOUT_OPEN 0x3410 +#define UBCTL_UMMU_SYNC_TIMEOUT_INFO 0x3418 +#define UBCTL_UMMU_SKY_QUEUE_STAT3_SP_0_63 0x4558 +#define UBCTL_UMMU_DFX_ECC_MONITOR_0 0x4D18 +#define UBCTL_UMMU_DFX_ECC_MONITOR_1 0x4D1C +#define UBCTL_UMMU_SPEC_DEF_DFX 0x4D60 +#define UBCTL_UMMU_DVM_RECEIVE_REQ_CNT 0x4D70 +#define UBCTL_UMMU_DVM_SEND_REQ_CNT 0x4D74 +#define UBCTL_UMMU_DVM_REQ_INFO0 0x4D78 +#define UBCTL_UMMU_DVM_REQ_INFO1 0x4D7C +#define UBCTL_UMMU_PMCG_INT_EN 0x5018 +#define UBCTL_UMMU_CFG_DFX_CFGBUS_STATUS 0x6000 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_SNP_ERR_CNT 0x6200 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_0 0x6204 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_1 0x6208 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_2 0x620C +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_3 0x6210 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_4 0x6214 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_5 0x6218 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_6 0x621C +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_7 0x6220 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_8 0x6224 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_9 0x6228 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_10 0x622C +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_11 0x6230 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_12 0x6234 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_13 0x6238 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_14 0x623C +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_ENTRY_STATUS_15 0x6240 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_SNP_STATUS 0x6280 +#define UBCTL_UMMU_SWIF_EVENTQ_DFX_DROP_CNT 0x6284 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_CTRL_STATUS1 0x6288 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_CMD_CTRL_STATUS2 0x628C +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_KCMD_STATUS 0x6290 +#define UBCTL_UMMU_SWIF_KCMDQ_DFX_KCMD_ERR_STATUS 0x6294 +#define UBCTL_UMMU_SWIF_UMCMD_DFX0 0x6300 +#define UBCTL_UMMU_SWIF_UMCMD_DFX1 0x6304 +#define UBCTL_UMMU_SWIF_UMCMD_DFX2 0x6308 +#define UBCTL_UMMU_SWIF_UMCMD_DFX3 0x630C +#define UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_0 0x6310 +#define UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_1 0x6314 +#define UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_2 0x6318 +#define UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_3 0x631C +#define UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_4 0x6320 +#define UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_5 0x6324 +#define UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX0_6 0x6328 +#define UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX1 0x632C +#define UBCTL_UMMU_SWIF_UMCMD_RR_WIN_DFX2 0x6330 +#define UBCTL_UMMU_SWIF_UMCMD_CACHE_DFX1 0x6334 +#define UBCTL_UMMU_SWIF_UMCMD_CACHE_DFX2 0x6338 +#define UBCTL_UMMU_SWIF_UMCMD_CACHE_DFX3 0x633C +#define UBCTL_UMMU_SWIF_UMCMD_CACHE_DFX4 0x6340 +#define UBCTL_UMMU_SWIF_UMCMD_CACHE_DFX5 0x6344 +#define UBCTL_UMMU_SWIF_UMCMD_CACHE_DFX6 0x6348 +#define UBCTL_UMMU_UBIF_DFX0 0x6400 +#define UBCTL_UMMU_UBIF_DFX1 0x6404 +#define UBCTL_UMMU_UBIF_DSTEID_DFX 0x640C +#define UBCTL_UMMU_UBIF_SYNC_DFX 0x6410 +#define UBCTL_UMMU_UBIF_KV_CACHE_NS_NSE_MISMATCH_DFX0 0x641C +#define UBCTL_UMMU_UBIF_KV_CACHE_NS_NSE_MISMATCH_DFX1 0x6420 +#define UBCTL_UMMU_UBIF_KV_CACHE_NS_NSE_MISMATCH_DFX2 0x6424 +#define UBCTL_UMMU_UBIF_KV_CACHE_NS_NSE_MISMATCH_DFX3 0x6428 +#define UBCTL_UMMU_UBIF_KV_CACHE_NS_NSE_MISMATCH_DFX4 0x642C +#define UBCTL_UMMU_TBU_TLB_LKUP_PROC 0x6600 +#define UBCTL_UMMU_TBU_TLB_STAT 0x6604 +#define UBCTL_UMMU_TBU_TLB_FAULT_CNT 0x6608 +#define UBCTL_UMMU_TBU_PLB_LKUP_PROC 0x660C +#define UBCTL_UMMU_TBU_PLB_STAT 0x6610 +#define UBCTL_UMMU_TBU_PLB_FAULT_CNT 0x6614 +#define UBCTL_UMMU_TBU_INVLD_MG_INFO 0x6618 +#define UBCTL_UMMU_TBU_RAB_STAT 0x661C +#define UBCTL_UMMU_TBU_RAB_ENTRY_INFO_0_7_15 0x6624 +#define UBCTL_UMMU_TBU_CNT 0x662C +#define UBCTL_UMMU_DFX_TBU_PERM_ERR_CNT 0x6634 +#define UBCTL_UMMU_TBU_DFX0 0x6638 +#define UBCTL_UMMU_TBU_DFX1 0x663C +#define UBCTL_UMMU_TCU_PTW_QUEUE_STAT_0_47 0x6804 +#define UBCTL_UMMU_TCU_PPTW_QUEUE_STAT_0_39 0x680C +#define UBCTL_UMMU_GPC_QUEUE_STAT_0_15 0x6814 +#define UBCTL_UMMU_ROOT_GPF_FAR_L 0x10028 +#define UBCTL_UMMU_ROOT_GPF_FAR_H 0x1002C + +#define UBCTL_UMMU_GPC_QUEUE_POINTER 0x6810 +#define UBCTL_UMMU_SKY_QUEUE_POINTER_SP 0x4540 +#define UBCTL_UMMU_TCU_PTW_QUEUE_POINTER 0x6800 +#define UBCTL_UMMU_TCU_PPTW_QUEUE_POINTER 0x6808 +#define UBCTL_UMMU_TBU_RAB_FUNC_EN 0x6620 + +#define UBCTL_UMMU_BANK_NUM 8 +#define UBCTL_UMMU_ENTRY_NUM 16 +#define UBCTL_UMMU_GPC_QUEUE_COUNT 16 +#define UBCTL_UMMU_TCU_PPTW_QUEUE_COUNT 40 +#define UBCTL_UMMU_TCU_PTW_QUEUE_COUNT 48 +#define UBCTL_UMMU_SKY_QUEUE_COUNT 64 + +#define UBCTL_UMMU_REGISTER_BASE 0 +#define UBCTL_UMMU_REGISTER_MAX_ADDR (UBCTL_UMMU_ROOT_GPF_FAR_H + 4U) + #endif diff --git a/include/uapi/fwctl/ub_fwctl.h b/include/uapi/fwctl/ub_fwctl.h index 139a413bf94a..05d7be4d7f8f 100644 --- a/include/uapi/fwctl/ub_fwctl.h +++ b/include/uapi/fwctl/ub_fwctl.h @@ -87,6 +87,10 @@ enum ub_fwctl_cmdrpc_type { UTOOL_CMD_QUERY_UBOMMU = 0x0091, + UTOOL_CMD_QUERY_UMMU_ALL = 0x00A1, + UTOOL_CMD_QUERY_UMMU_SYNC = 0x00A2, + UTOOL_CMD_CONFIG_UMMU_SYNC = 0x00A3, + UTOOL_CMD_QUERY_ECC_2B = 0x00B1, UTOOL_CMD_QUERY_LOOPBACK = 0x00D1, @@ -118,4 +122,9 @@ struct fwctl_pkt_in_index { __u32 index; }; +struct fwctl_pkt_in_ummuid_value { + __u32 ummu_id; + __u32 value; +}; + #endif -- Gitee From 2f3e214d24f1c6c96f01011c2d2493fd179dd038 Mon Sep 17 00:00:00 2001 From: Jiaqi Cheng Date: Wed, 19 Nov 2025 17:11:45 +0800 Subject: [PATCH 039/103] fwctl:Change the CONFIG_FWCTL in the config options to m commit 730e6c76af4ce310e9b3469b85a05b036bb61713 openEuler Change the CONFIG_FWCTL in the config optionsto m Fixes: aabc3d653349 ("ub: ub_fwctl: Add the ub_fwctl driver and its basic features.") Signed-off-by: Jiaqi Cheng Signed-off-by: huwentao --- arch/arm64/configs/tencent.config | 2 +- arch/x86/configs/tencent.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/configs/tencent.config b/arch/arm64/configs/tencent.config index d122f864bc43..9601389859b6 100644 --- a/arch/arm64/configs/tencent.config +++ b/arch/arm64/configs/tencent.config @@ -1865,7 +1865,7 @@ CONFIG_VFIO_DEVICE_CDEV=y # end of IOMMUFD # fwctl -CONFIG_FWCTL=y +CONFIG_FWCTL=m # UB_FWCTL CONFIG_FWCTL_UB=m diff --git a/arch/x86/configs/tencent.config b/arch/x86/configs/tencent.config index 126020c405a7..2444a388a8c1 100644 --- a/arch/x86/configs/tencent.config +++ b/arch/x86/configs/tencent.config @@ -2028,4 +2028,4 @@ CONFIG_TEST_BPF=m CONFIG_EXT4_FS=y # fwctl -CONFIG_FWCTL=y +CONFIG_FWCTL=m -- Gitee From 959cf5420cdb2fa32efb1cf90afa4be9ad49d7b2 Mon Sep 17 00:00:00 2001 From: Jiaqi Cheng Date: Wed, 19 Nov 2025 17:26:41 +0800 Subject: [PATCH 040/103] ub: ub_fwctl: Release rpc_out when kernel state return error commit d222718375d8c0deb1c74d3152c3662c0d49907d openEuler ub_fwctl encountered an error while executing in kernel mode and did not release rpc_out before returning to fwctl. Fix this issue now. Fixes: aabc3d653349 ("ub: ub_fwctl: Add the ub_fwctl driver and its basic features.") Signed-off-by: Jiaqi Cheng Signed-off-by: huwentao --- drivers/fwctl/ub/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/fwctl/ub/main.c b/drivers/fwctl/ub/main.c index e96ccf5afa55..6b1f619dc0a4 100644 --- a/drivers/fwctl/ub/main.c +++ b/drivers/fwctl/ub/main.c @@ -147,6 +147,11 @@ static void *ubctl_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope, ubctl_dbg(ucdev, "cmdif: opcode 0x%x retval %d\n", opcode, ret); + if (ret) { + kvfree(rpc_out); + return ERR_PTR(ret); + } + return rpc_out; } -- Gitee From 4fc9fd4158af64bce2683eb7859ba88618da404c Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Fri, 31 Oct 2025 15:33:14 +0800 Subject: [PATCH 041/103] ub: udma: Support loading and unloading driver. commit 05c3cda9c33a875b228a3f70b9f18f4346b68461 openEuler This patch adds the function of loading and unloading the driver. In driver loading process, udma queries the required hardware information from ubase and stores it in the internal structure of the driver. At the same time, udma also provides ubcore with ops for querying device status and create rc table. This patch also adds the function of mailbox and software table for udma driver. Signed-off-by: Wei Qin Signed-off-by: zhaoweibo Signed-off-by: zhaolichang <943677312@qq.com> --- arch/arm64/configs/tencent.config | 3 + drivers/ub/Kconfig | 1 + drivers/ub/Makefile | 1 + drivers/ub/urma/hw/udma/Kconfig | 12 + drivers/ub/urma/hw/udma/Makefile | 6 + drivers/ub/urma/hw/udma/udma_cmd.c | 208 ++++++ drivers/ub/urma/hw/udma/udma_cmd.h | 241 +++++++ drivers/ub/urma/hw/udma/udma_common.c | 125 ++++ drivers/ub/urma/hw/udma/udma_common.h | 28 + drivers/ub/urma/hw/udma/udma_ctrlq_tp.h | 16 + drivers/ub/urma/hw/udma/udma_def.h | 97 +++ drivers/ub/urma/hw/udma/udma_dev.h | 147 ++++ drivers/ub/urma/hw/udma/udma_main.c | 892 ++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_rct.c | 207 ++++++ drivers/ub/urma/hw/udma/udma_rct.h | 57 ++ 15 files changed, 2041 insertions(+) create mode 100644 drivers/ub/urma/hw/udma/Kconfig create mode 100644 drivers/ub/urma/hw/udma/Makefile create mode 100644 drivers/ub/urma/hw/udma/udma_cmd.c create mode 100644 drivers/ub/urma/hw/udma/udma_cmd.h create mode 100644 drivers/ub/urma/hw/udma/udma_common.c create mode 100644 drivers/ub/urma/hw/udma/udma_common.h create mode 100644 drivers/ub/urma/hw/udma/udma_ctrlq_tp.h create mode 100644 drivers/ub/urma/hw/udma/udma_def.h create mode 100644 drivers/ub/urma/hw/udma/udma_dev.h create mode 100644 drivers/ub/urma/hw/udma/udma_main.c create mode 100644 drivers/ub/urma/hw/udma/udma_rct.c create mode 100644 drivers/ub/urma/hw/udma/udma_rct.h diff --git a/arch/arm64/configs/tencent.config b/arch/arm64/configs/tencent.config index 9601389859b6..7ca1fa88f877 100644 --- a/arch/arm64/configs/tencent.config +++ b/arch/arm64/configs/tencent.config @@ -1837,6 +1837,9 @@ CONFIG_UB_UNIC_DCB=y # UB CDMA driver CONFIG_UB_CDMA=m + +# UB UDMA driver +CONFIG_UB_UDMA=m # end of unified bus # UMMU diff --git a/drivers/ub/Kconfig b/drivers/ub/Kconfig index 6197483bd71e..5aaa3bcc014a 100644 --- a/drivers/ub/Kconfig +++ b/drivers/ub/Kconfig @@ -19,6 +19,7 @@ source "drivers/ub/ubase/Kconfig" source "drivers/ub/cdma/Kconfig" source "drivers/ub/obmm/Kconfig" source "drivers/ub/sentry/Kconfig" +source "drivers/ub/urma/hw/udma/Kconfig" config UB_URMA tristate "Unified Bus (UB) urma support" default m diff --git a/drivers/ub/Makefile b/drivers/ub/Makefile index 2a40689dafac..1725f006d197 100644 --- a/drivers/ub/Makefile +++ b/drivers/ub/Makefile @@ -5,5 +5,6 @@ obj-y += ubfi/ obj-$(CONFIG_UB_URMA) += urma/ obj-$(CONFIG_UB_UBASE) += ubase/ obj-$(CONFIG_UB_CDMA) += cdma/ +obj-$(CONFIG_UB_UDMA) += urma/hw/udma/ obj-y += obmm/ obj-$(CONFIG_UB_SENTRY) += sentry/ diff --git a/drivers/ub/urma/hw/udma/Kconfig b/drivers/ub/urma/hw/udma/Kconfig new file mode 100644 index 000000000000..fd5d27ef9813 --- /dev/null +++ b/drivers/ub/urma/hw/udma/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. + +menuconfig UB_UDMA + default n + tristate "UB UDMA Driver" + depends on UB_UBASE && UB_URMA && UB_UMMU_CORE + help + UDMA driver support for Hisilicon UBUS engine + in Hisilicon SoC. To compile this driver, + choose Y here: if UB_UDMA is m, this module + will be called udma. diff --git a/drivers/ub/urma/hw/udma/Makefile b/drivers/ub/urma/hw/udma/Makefile new file mode 100644 index 000000000000..2cd71b916ec9 --- /dev/null +++ b/drivers/ub/urma/hw/udma/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ + +udma-$(CONFIG_UB_UDMA) := udma_main.o udma_cmd.o udma_common.o \ + udma_rct.o + +obj-m := udma.o diff --git a/drivers/ub/urma/hw/udma/udma_cmd.c b/drivers/ub/urma/hw/udma/udma_cmd.c new file mode 100644 index 000000000000..244646f86a42 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_cmd.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt + +#include +#include +#include +#include "udma_cmd.h" + +bool debug_switch = true; + +int udma_cmd_init(struct udma_dev *udma_dev) +{ + sema_init(&udma_dev->mb_cmd.poll_sem, 1); + udma_dev->mb_cmd.pool = dma_pool_create("udma_cmd", udma_dev->dev, + UDMA_MAILBOX_SIZE, + UDMA_MAILBOX_SIZE, 0); + if (!udma_dev->mb_cmd.pool) { + dev_err(udma_dev->dev, "failed to dma_pool_create.\n"); + return -ENOMEM; + } + + init_rwsem(&udma_dev->mb_cmd.udma_mb_rwsem); + + return 0; +} + +void udma_cmd_cleanup(struct udma_dev *udma_dev) +{ + down_write(&udma_dev->mb_cmd.udma_mb_rwsem); + dma_pool_destroy(udma_dev->mb_cmd.pool); + up_write(&udma_dev->mb_cmd.udma_mb_rwsem); +} + +struct ubase_cmd_mailbox *udma_alloc_cmd_mailbox(struct udma_dev *dev) +{ + struct ubase_cmd_mailbox *mailbox; + + mailbox = kzalloc(sizeof(*mailbox), GFP_KERNEL); + if (!mailbox) + goto failed_alloc_mailbox; + + down_read(&dev->mb_cmd.udma_mb_rwsem); + mailbox->buf = dma_pool_zalloc(dev->mb_cmd.pool, GFP_KERNEL, + &mailbox->dma); + if (!mailbox->buf) { + dev_err(dev->dev, "failed to alloc buffer of mailbox.\n"); + goto failed_alloc_mailbox_buf; + } + + return mailbox; + +failed_alloc_mailbox_buf: + up_read(&dev->mb_cmd.udma_mb_rwsem); + kfree(mailbox); +failed_alloc_mailbox: + return NULL; +} + +void udma_free_cmd_mailbox(struct udma_dev *dev, + struct ubase_cmd_mailbox *mailbox) +{ + if (!mailbox) { + dev_err(dev->dev, "Invalid mailbox.\n"); + return; + } + + dma_pool_free(dev->mb_cmd.pool, mailbox->buf, mailbox->dma); + up_read(&dev->mb_cmd.udma_mb_rwsem); + kfree(mailbox); +} + +static bool udma_op_ignore_eagain(uint8_t op, void *buf) +{ + struct udma_mbx_op_match matches[] = { + { UDMA_CMD_CREATE_JFS_CONTEXT, false }, + { UDMA_CMD_MODIFY_JFS_CONTEXT, true }, + { UDMA_CMD_DESTROY_JFS_CONTEXT, true }, + { UDMA_CMD_QUERY_JFS_CONTEXT, true }, + { UDMA_CMD_CREATE_JFC_CONTEXT, false }, + { UDMA_CMD_MODIFY_JFC_CONTEXT, true }, + { UDMA_CMD_DESTROY_JFC_CONTEXT, true }, + { UDMA_CMD_QUERY_JFC_CONTEXT, true }, + { UDMA_CMD_CREATE_JFR_CONTEXT, false }, + { UDMA_CMD_MODIFY_JFR_CONTEXT, true }, + { UDMA_CMD_DESTROY_JFR_CONTEXT, true }, + { UDMA_CMD_QUERY_JFR_CONTEXT, true }, + { UDMA_CMD_QUERY_TP_CONTEXT, true }, + { UDMA_CMD_CREATE_JETTY_GROUP_CONTEXT, false }, + { UDMA_CMD_MODIFY_JETTY_GROUP_CONTEXT, true }, + { UDMA_CMD_DESTROY_JETTY_GROUP_CONTEXT, true }, + { UDMA_CMD_QUERY_JETTY_GROUP_CONTEXT, true }, + { UDMA_CMD_CREATE_RC_CONTEXT, false }, + { UDMA_CMD_MODIFY_RC_CONTEXT, true }, + { UDMA_CMD_DESTROY_RC_CONTEXT, true }, + { UDMA_CMD_QUERY_RC_CONTEXT, true }, + { UDMA_CMD_READ_SEID_UPI, true }, + }; + uint32_t i; + + for (i = 0; i < ARRAY_SIZE(matches); i++) { + if (op == matches[i].op) + return matches[i].ignore_ret; + } + + return false; +} + +int udma_post_mbox(struct udma_dev *dev, struct ubase_cmd_mailbox *mailbox, + struct ubase_mbx_attr *attr) +{ + int ret; + + if (debug_switch) + dev_info_ratelimited(dev->dev, + "Send cmd mailbox, data: %08x %04x%04x.\n", + attr->tag, attr->op, attr->mbx_ue_id); + + ret = ubase_hw_upgrade_ctx_ex(dev->comdev.adev, attr, mailbox); + + return (ret == -EAGAIN && + udma_op_ignore_eagain(attr->op, mailbox->buf)) ? 0 : ret; +} + +int udma_config_ctx_buf_to_hw(struct udma_dev *udma_dev, + struct udma_buf *ctx_buf, + struct ubase_mbx_attr *attr) +{ + struct ubase_cmd_mailbox mailbox; + int ret; + + mailbox.dma = ctx_buf->addr; + ret = udma_post_mbox(udma_dev, &mailbox, attr); + if (ret) + dev_err(udma_dev->dev, + "failed to config ctx_buf to hw, ret = %d.\n", ret); + + return ret; +} + +int udma_cmd_query_hw_resource(struct udma_dev *udma_dev, void *out_addr) +{ + struct ubase_cmd_buf out = {}; + struct ubase_cmd_buf in = {}; + + udma_fill_buf(&in, UDMA_CMD_QUERY_UE_RES, true, 0, NULL); + udma_fill_buf(&out, UDMA_CMD_QUERY_UE_RES, true, + sizeof(struct udma_cmd_ue_resource), out_addr); + + return ubase_cmd_send_inout(udma_dev->comdev.adev, &in, &out); +} + +int post_mailbox_update_ctx(struct udma_dev *udma_dev, void *ctx, uint32_t size, + struct ubase_mbx_attr *attr) +{ + struct ubase_cmd_mailbox *mailbox; + int ret; + + mailbox = udma_alloc_cmd_mailbox(udma_dev); + if (!mailbox) { + dev_err(udma_dev->dev, + "failed to alloc mailbox for opcode 0x%x.\n", attr->op); + return -ENOMEM; + } + + if (ctx) + memcpy(mailbox->buf, ctx, size); + + ret = udma_post_mbox(udma_dev, mailbox, attr); + if (ret) + dev_err(udma_dev->dev, + "failed to post mailbox, opcode = 0x%x, ret = %d.\n", attr->op, + ret); + + udma_free_cmd_mailbox(udma_dev, mailbox); + + return ret; +} + +struct ubase_cmd_mailbox *udma_mailbox_query_ctx(struct udma_dev *udma_dev, + struct ubase_mbx_attr *attr) +{ + struct ubase_cmd_mailbox *mailbox; + int ret; + + mailbox = udma_alloc_cmd_mailbox(udma_dev); + if (!mailbox) { + dev_err(udma_dev->dev, + "failed to alloc mailbox query ctx, opcode = %u, id = %u.\n", + attr->op, attr->tag); + return NULL; + } + + ret = udma_post_mbox(udma_dev, mailbox, attr); + if (ret) { + dev_err(udma_dev->dev, + "failed to post mailbox query ctx, opcode = %u, id = %u, ret = %d.\n", + attr->op, attr->tag, ret); + udma_free_cmd_mailbox(udma_dev, mailbox); + return NULL; + } + + return mailbox; +} + +module_param(debug_switch, bool, 0444); +MODULE_PARM_DESC(debug_switch, "set debug print ON, default: true"); diff --git a/drivers/ub/urma/hw/udma/udma_cmd.h b/drivers/ub/urma/hw/udma/udma_cmd.h new file mode 100644 index 000000000000..3dd27765fb56 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_cmd.h @@ -0,0 +1,241 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_CMD_H__ +#define __UDMA_CMD_H__ + +#include +#include +#include +#include "udma_dev.h" + +extern bool debug_switch; + +#define UDMA_MAILBOX_SIZE 4096 + +#define SPEED_200G 200000 +#define SPEED_400G 400000 +#define SPEED_100G 100000 +#define SPEED_50G 50000 +#define SPEED_25G 25000 + +struct udma_ctrlq_eid_info { + uint32_t eid_idx; + union ubcore_eid eid; + uint32_t upi; +} __packed; + +enum udma_cmd_opcode_type { + UDMA_CMD_QUERY_UE_RES = 0x0002, + UDMA_CMD_QUERY_UE_INDEX = 0x241d, + UDMA_CMD_CFG_CONG_PARAM = 0x3003, + UDMA_CMD_CHANGE_ACTIVE_PORT = 0x3102, + UDMA_CMD_DEBUGFS_TP_INFO = 0x3110, + UDMA_CMD_DEBUGFS_TA_INFO = 0x4210, + UDMA_CMD_GET_CQE_AUX_INFO = 0x4213, + UDMA_CMD_GET_AE_AUX_INFO = 0x4214, + UDMA_CMD_QUERY_PORT_INFO = 0x6200, + UDMA_CMD_WQEBB_VA_INFO = 0xa01f, +}; + +struct udma_cmd { + uint32_t opcode; + void *in_buf; + uint32_t in_len; + void *out_buf; + uint32_t out_len; +}; + +enum { + /* JFS CMDS */ + UDMA_CMD_WRIET_JFS_CONTEXT_VA = 0x00, + UDMA_CMD_READ_JFS_CONTEXT_VA = 0x01, + UDMA_CMD_DESTROY_JFS_CONTEXT_VA = 0x02, + UDMA_CMD_CREATE_JFS_CONTEXT = 0x04, + UDMA_CMD_MODIFY_JFS_CONTEXT = 0x05, + UDMA_CMD_QUERY_JFS_CONTEXT = 0x06, + UDMA_CMD_DESTROY_JFS_CONTEXT = 0x07, + + /* RC CMDS */ + UDMA_CMD_WRITE_RC_CONTEXT_VA = 0x10, + UDMA_CMD_READ_RC_CONTEXT_VA = 0x11, + UDMA_CMD_DESTROY_RC_CONTEXT_VA = 0x12, + UDMA_CMD_CREATE_RC_CONTEXT = 0x14, + UDMA_CMD_MODIFY_RC_CONTEXT = 0x15, + UDMA_CMD_QUERY_RC_CONTEXT = 0X16, + UDMA_CMD_DESTROY_RC_CONTEXT = 0x17, + + /* JFC CMDS */ + UDMA_CMD_WRITE_JFC_CONTEXT_VA = 0x20, + UDMA_CMD_READ_JFC_CONTEXT_VA = 0x21, + UDMA_CMD_DESTROY_JFC_CONTEXT_VA = 0x22, + UDMA_CMD_CREATE_JFC_CONTEXT = 0x24, + UDMA_CMD_MODIFY_JFC_CONTEXT = 0x25, + UDMA_CMD_QUERY_JFC_CONTEXT = 0x26, + UDMA_CMD_DESTROY_JFC_CONTEXT = 0x27, + + /* CEQ CMDS */ + UDMA_CMD_CREATE_CEQ_CONTEXT = 0x44, + UDMA_CMD_MODIFY_CEQ_CONTEXT = 0x45, + UDMA_CMD_QUERY_CEQ_CONTEXT = 0x46, + UDMA_CMD_DESTROY_CEQ_CONTEXT = 0x47, + + /* JFR CMDS */ + UDMA_CMD_WRITE_JFR_CONTEXT_VA = 0x50, + UDMA_CMD_READ_JFR_CONTEXT_VA = 0x51, + UDMA_CMD_DESTROY_JFR_CONTEXT_VA = 0x52, + UDMA_CMD_CREATE_JFR_CONTEXT = 0x54, + UDMA_CMD_MODIFY_JFR_CONTEXT = 0x55, + UDMA_CMD_QUERY_JFR_CONTEXT = 0x56, + UDMA_CMD_DESTROY_JFR_CONTEXT = 0x57, + + /* JETTY CMDS */ + UDMA_CMD_WRITE_JETTY_GROUP_CONTEXT_VA = 0x60, + UDMA_CMD_READ_JETTY_GROUP_CONTEXT_VA = 0x61, + UDMA_CMD_DESTROY_JETTY_GROUP_CONTEXT_VA = 0x62, + UDMA_CMD_CREATE_JETTY_GROUP_CONTEXT = 0x64, + UDMA_CMD_MODIFY_JETTY_GROUP_CONTEXT = 0x65, + UDMA_CMD_QUERY_JETTY_GROUP_CONTEXT = 0x66, + UDMA_CMD_DESTROY_JETTY_GROUP_CONTEXT = 0x67, + + /* TP CMDS */ + UDMA_CMD_QUERY_TP_CONTEXT = 0x86, + + /* SEID_UPI CMDS */ + UDMA_CMD_READ_SEID_UPI = 0xb5, +}; + +struct udma_mbx_op_match { + uint32_t op; + bool ignore_ret; + uint32_t entry_size; +}; + +struct cap_info { + uint16_t ar_en : 1; + uint16_t jfc_per_wr : 1; + uint16_t stride_up : 1; + uint16_t load_store_op : 1; + uint16_t jfc_inline : 1; + uint16_t non_pin : 1; + uint16_t selective_retrans : 1; + uint16_t rsvd : 9; + uint16_t rsvd1; +}; + +struct udma_cmd_ue_resource { + /* BD0 */ + uint16_t jfs_num_shift : 4; + uint16_t jfr_num_shift : 4; + uint16_t jfc_num_shift : 4; + uint16_t jetty_num_shift : 4; + + uint16_t jetty_grp_num; + + uint16_t jfs_depth_shift : 4; + uint16_t jfr_depth_shift : 4; + uint16_t jfc_depth_shift : 4; + uint16_t cqe_size_shift : 4; + + uint16_t jfs_sge : 5; + uint16_t jfr_sge : 5; + uint16_t jfs_rsge : 6; + + uint16_t max_jfs_inline_sz; + uint16_t max_jfc_inline_sz; + uint32_t cap_info; + + uint16_t trans_mode : 5; + uint16_t ue_num : 8; + uint16_t virtualization : 1; + uint16_t dcqcn_sw_en : 1; + uint16_t rsvd0 : 1; + + uint16_t ue_cnt; + uint8_t ue_id; + uint8_t default_cong_alg; + uint8_t cons_ctrl_alg; + uint8_t cc_priority_cnt; + + /* BD1 */ + uint16_t src_addr_tbl_sz; + uint16_t src_addr_tbl_num; + uint16_t dest_addr_tbl_sz; + uint16_t dest_addr_tbl_num; + uint16_t seid_upi_tbl_sz; + uint16_t seid_upi_tbl_num; + uint16_t tpm_tbl_sz; + uint16_t tpm_tbl_num; + uint32_t tp_range; + uint8_t port_num; + uint8_t port_id; + uint8_t rsvd1[2]; + uint16_t rc_queue_num; + uint16_t rc_depth; + uint8_t rc_entry; + uint8_t rsvd2[3]; + + /* BD2 */ + uint16_t well_known_jetty_start; + uint16_t well_known_jetty_num; + uint16_t ccu_jetty_start; + uint16_t ccu_jetty_num; + uint16_t drv_jetty_start; + uint16_t drv_jetty_num; + uint16_t cache_lock_jetty_start; + uint16_t cache_lock_jetty_num; + uint16_t normal_jetty_start; + uint16_t normal_jetty_num; + uint16_t standard_jetty_start; + uint16_t standard_jetty_num; + uint32_t rsvd3[2]; + + /* BD3 */ + uint32_t max_write_size; + uint32_t max_read_size; + uint32_t max_cas_size; + uint32_t max_fetch_and_add_size; + uint32_t atomic_feat; + uint32_t rsvd4[3]; +}; + +struct udma_cmd_port_info { + uint32_t speed; + uint8_t rsv[10]; + uint8_t lanes; + uint8_t rsv2[9]; +}; + +struct udma_cmd_wqebb_va { + uint64_t va_start; + uint64_t va_size; + uint32_t die_num; + uint32_t ue_num; +}; + +static inline void udma_fill_buf(struct ubase_cmd_buf *buf, u16 opcode, + bool is_read, u32 data_size, void *data) +{ + buf->opcode = opcode; + buf->is_read = is_read; + buf->data_size = data_size; + buf->data = data; +} + +int udma_cmd_init(struct udma_dev *udma_dev); +void udma_cmd_cleanup(struct udma_dev *udma_dev); +struct ubase_cmd_mailbox *udma_alloc_cmd_mailbox(struct udma_dev *dev); +void udma_free_cmd_mailbox(struct udma_dev *dev, + struct ubase_cmd_mailbox *mailbox); +int udma_post_mbox(struct udma_dev *dev, struct ubase_cmd_mailbox *mailbox, + struct ubase_mbx_attr *attr); +int udma_cmd_query_hw_resource(struct udma_dev *udma_dev, void *out_addr); +int udma_config_ctx_buf_to_hw(struct udma_dev *udma_dev, + struct udma_buf *ctx_buf, + struct ubase_mbx_attr *attr); +int post_mailbox_update_ctx(struct udma_dev *udma_dev, void *ctx, uint32_t size, + struct ubase_mbx_attr *attr); +struct ubase_cmd_mailbox *udma_mailbox_query_ctx(struct udma_dev *udma_dev, + struct ubase_mbx_attr *attr); + +#endif /* __UDMA_CMD_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_common.c b/drivers/ub/urma/hw/udma/udma_common.c new file mode 100644 index 000000000000..cb8e6b6f4e90 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_common.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "udma_dev.h" +#include "udma_cmd.h" +#include "udma_common.h" + +static void udma_init_ida_table(struct udma_ida *ida_table, uint32_t max, uint32_t min) +{ + ida_init(&ida_table->ida); + spin_lock_init(&ida_table->lock); + ida_table->max = max; + ida_table->min = min; + ida_table->next = min; +} + +void udma_init_udma_table(struct udma_table *table, uint32_t max, uint32_t min) +{ + udma_init_ida_table(&table->ida_table, max, min); + xa_init(&table->xa); +} + +void udma_init_udma_table_mutex(struct xarray *table, struct mutex *udma_mutex) +{ + xa_init(table); + mutex_init(udma_mutex); +} + +void udma_destroy_udma_table(struct udma_dev *dev, struct udma_table *table, + const char *table_name) +{ + if (!ida_is_empty(&table->ida_table.ida)) + dev_err(dev->dev, "IDA not empty in clean up %s table.\n", + table_name); + ida_destroy(&table->ida_table.ida); + + if (!xa_empty(&table->xa)) + dev_err(dev->dev, "%s not empty.\n", table_name); + xa_destroy(&table->xa); +} + +static void udma_clear_eid_table(struct udma_dev *udma_dev) +{ + struct udma_ctrlq_eid_info *eid_entry = NULL; + unsigned long index = 0; + eid_t ummu_eid = 0; + guid_t guid = {}; + + if (!xa_empty(&udma_dev->eid_table)) { + xa_for_each(&udma_dev->eid_table, index, eid_entry) { + xa_erase(&udma_dev->eid_table, index); + if (!udma_dev->is_ue) { + (void)memcpy(&ummu_eid, eid_entry->eid.raw, sizeof(ummu_eid)); + ummu_core_del_eid(&guid, ummu_eid, EID_NONE); + } + kfree(eid_entry); + eid_entry = NULL; + } + } +} + +void udma_destroy_eid_table(struct udma_dev *udma_dev) +{ + udma_clear_eid_table(udma_dev); + xa_destroy(&udma_dev->eid_table); + mutex_destroy(&udma_dev->eid_mutex); +} + +void *udma_alloc_iova(struct udma_dev *udma_dev, size_t memory_size, dma_addr_t *addr) +{ + struct iova_slot *slot; + uint32_t npage; + size_t sizep; + int ret; + + slot = dma_alloc_iova(udma_dev->dev, memory_size, 0, addr, &sizep); + if (IS_ERR_OR_NULL(slot)) { + dev_err(udma_dev->dev, + "failed to dma alloc iova, size = %lu, ret = %ld.\n", + memory_size, PTR_ERR(slot)); + return NULL; + } + + npage = sizep >> PAGE_SHIFT; + ret = ummu_fill_pages(slot, *addr, npage); + if (ret) { + dev_err(udma_dev->dev, + "ummu fill pages failed, npage = %u, ret = %d", npage, ret); + dma_free_iova(slot); + return NULL; + } + + return (void *)slot; +} + +void udma_free_iova(struct udma_dev *udma_dev, size_t memory_size, void *kva_or_slot, + dma_addr_t addr) +{ + size_t aligned_memory_size; + struct iova_slot *slot; + uint32_t npage; + int ret; + + aligned_memory_size = PAGE_ALIGN(memory_size); + npage = aligned_memory_size >> PAGE_SHIFT; + slot = (struct iova_slot *)kva_or_slot; + ret = ummu_drain_pages(slot, addr, npage); + if (ret) + dev_err(udma_dev->dev, + "ummu drain pages failed, npage = %u, ret = %d.\n", + npage, ret); + + dma_free_iova(slot); +} diff --git a/drivers/ub/urma/hw/udma/udma_common.h b/drivers/ub/urma/hw/udma/udma_common.h new file mode 100644 index 000000000000..4f843356c755 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_common.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_COMM_H__ +#define __UDMA_COMM_H__ + +#include +#include +#include "udma_dev.h" + +struct udma_umem_param { + struct ubcore_device *ub_dev; + uint64_t va; + uint64_t len; + union ubcore_umem_flag flag; + bool is_kernel; +}; + +void udma_init_udma_table(struct udma_table *table, uint32_t max, uint32_t min); +void udma_init_udma_table_mutex(struct xarray *table, struct mutex *udma_mutex); +void udma_destroy_udma_table(struct udma_dev *dev, struct udma_table *table, + const char *table_name); +void udma_destroy_eid_table(struct udma_dev *udma_dev); +void *udma_alloc_iova(struct udma_dev *udma_dev, size_t memory_size, dma_addr_t *addr); +void udma_free_iova(struct udma_dev *udma_dev, size_t memory_size, void *kva_or_slot, + dma_addr_t addr); + +#endif /* __UDMA_COMM_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_ctrlq_tp.h b/drivers/ub/urma/hw/udma/udma_ctrlq_tp.h new file mode 100644 index 000000000000..93898a153a98 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_ctrlq_tp.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_CTRLQ_TP_H__ +#define __UDMA_CTRLQ_TP_H__ + +#include "udma_common.h" + +#define UDMA_UE_NUM 64 + +struct udma_ue_idx_table { + uint32_t num; + uint8_t ue_idx[UDMA_UE_NUM]; +}; + +#endif /* __UDMA_CTRLQ_TP_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_def.h b/drivers/ub/urma/hw/udma/udma_def.h new file mode 100644 index 000000000000..14d747c3fb8f --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_def.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_DEF_H__ +#define __UDMA_DEF_H__ + +#include +#include +#include +#include + +enum { + UDMA_CAP_FEATURE_AR = BIT(0), + UDMA_CAP_FEATURE_JFC_INLINE = BIT(4), + UDMA_CAP_FEATURE_DIRECT_WQE = BIT(11), + UDMA_CAP_FEATURE_CONG_CTRL = BIT(16), + UDMA_CAP_FEATURE_REDUCE = BIT(17), + UDMA_CAP_FEATURE_UE_RX_CLOSE = BIT(18), + UDMA_CAP_FEATURE_RNR_RETRY = BIT(19), +}; + +struct udma_res { + uint32_t max_cnt; + uint32_t start_idx; + uint32_t next_idx; + uint32_t depth; +}; + +struct udma_tbl { + uint32_t max_cnt; + uint32_t size; +}; + +struct udma_caps { + unsigned long init_flag; + struct udma_res jfs; + struct udma_res jfr; + struct udma_res jfc; + struct udma_res jetty; + struct udma_res jetty_grp; + uint32_t jetty_in_grp; + uint32_t jfs_sge; + uint32_t jfr_sge; + uint32_t jfs_rsge; + uint32_t jfs_inline_sz; + uint32_t comp_vector_cnt; + uint16_t ue_cnt; + uint8_t ue_id; + uint32_t trans_mode; + uint32_t max_msg_len; + uint32_t feature; + uint32_t rsvd_jetty_cnt; + uint32_t max_read_size; + uint32_t max_write_size; + uint32_t max_cas_size; + uint32_t max_fetch_and_add_size; + uint32_t atomic_feat; + struct udma_res ccu_jetty; + struct udma_res hdc_jetty; + struct udma_res stars_jetty; + struct udma_res public_jetty; + struct udma_res user_ctrl_normal_jetty; + uint16_t rc_queue_num; + uint16_t rc_queue_depth; + uint8_t rc_entry_size; + uint8_t ack_queue_num; + uint8_t port_num; + uint8_t cqe_size; + struct udma_tbl seid; +}; + +struct udma_buf { + dma_addr_t addr; + union { + void *kva; /* used for kernel mode */ + struct iova_slot *slot; + void *kva_or_slot; + }; + void *aligned_va; + struct ubcore_umem *umem; + uint32_t entry_size; + uint32_t entry_cnt; + uint32_t cnt_per_page_shift; + struct xarray id_table_xa; + struct mutex id_table_mutex; +}; + +enum num_elem_in_grp { + NUM_TP_PER_GROUP = 16, + NUM_JETTY_PER_GROUP = 32, +}; + +enum { + RCT_INIT_FLAG, +}; + +#endif /* __UDMA_DEF_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_dev.h b/drivers/ub/urma/hw/udma/udma_dev.h new file mode 100644 index 000000000000..941dd2a0540e --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_dev.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_DEV_H__ +#define __UDMA_DEV_H__ + +#include +#include +#include +#include "udma_def.h" + +#define UBCORE_MAX_DEV_NAME 64 + +#define MAX_JETTY_IN_JETTY_GRP 32 + +#define MAX_WQEBB_IN_SQE 4 + +#define UDMA_HW_PAGE_SHIFT 12 +#define UDMA_HW_PAGE_SIZE (1 << UDMA_HW_PAGE_SHIFT) + +#define UDMA_DEV_UE_NUM 47 + +#define UDMA_MAX_SL_NUM 16 +#define UDMA_DEFAULT_SL_NUM 0 + +#define UDMA_CQE_SIZE 64 + +#define UDMA_MAX_GRANT_SIZE 0xFFFFFFFFF000 + +enum udma_status { + UDMA_NORMAL, + UDMA_SUSPEND, +}; + +struct udma_ida { + struct ida ida; + uint32_t min; /* Lowest ID to allocate. */ + uint32_t max; /* Highest ID to allocate. */ + uint32_t next; /* Next ID to allocate. */ + spinlock_t lock; +}; + +struct udma_group_bitmap { + uint32_t min; + uint32_t max; + uint32_t grp_next; + uint32_t n_bits; + uint32_t *bit; + uint32_t bitmap_cnt; + spinlock_t lock; +}; + +struct udma_group_table { + struct xarray xa; + struct udma_group_bitmap bitmap_table; +}; + +struct udma_table { + struct xarray xa; + struct udma_ida ida_table; +}; + +struct udma_mailbox_cmd { + struct dma_pool *pool; + struct semaphore poll_sem; + struct rw_semaphore udma_mb_rwsem; +}; + +struct udma_dev { + struct ubase_adev_com comdev; + struct ubcore_device ub_dev; + struct device *dev; + struct udma_caps caps; + uint16_t adev_id; + uint32_t chip_id; + uint32_t die_id; + uint32_t port_id; + uint32_t port_logic_id; + bool is_ue; + char dev_name[UBCORE_MAX_DEV_NAME]; + struct udma_mailbox_cmd mb_cmd; + struct udma_table jfr_table; + struct udma_group_table jetty_table; + struct udma_table jfc_table; + struct udma_table jetty_grp_table; + struct udma_ida rsvd_jetty_ida_table; + struct udma_table rc_table; + struct xarray crq_nb_table; + struct xarray npu_nb_table; + struct mutex npu_nb_mutex; + struct xarray tpn_ue_idx_table; + resource_size_t db_base; + void __iomem *k_db_base; + struct xarray ksva_table; + struct mutex ksva_mutex; + struct xarray eid_table; + struct mutex eid_mutex; + uint32_t tid; + struct iommu_sva *ksva; + uint32_t status; + uint32_t ue_num; + uint32_t ue_id; + struct page *db_page; + u8 udma_tp_sl_num; + u8 udma_ctp_sl_num; + u8 unic_sl_num; + u8 udma_total_sl_num; + u8 udma_tp_resp_vl_off; + u8 udma_tp_sl[UDMA_MAX_SL_NUM]; + u8 udma_ctp_sl[UDMA_MAX_SL_NUM]; + u8 unic_sl[UDMA_MAX_SL_NUM]; + u8 udma_sl[UDMA_MAX_SL_NUM]; + int disable_ue_rx_count; + struct mutex disable_ue_rx_mutex; +}; + +#define UDMA_ERR_MSG_LEN 128 +struct udma_func_map { + char err_msg[UDMA_ERR_MSG_LEN]; + int (*init_func)(struct udma_dev *udma_dev); + void (*uninit_func)(struct udma_dev *udma_dev); +}; + +static inline struct udma_dev *get_udma_dev(struct auxiliary_device *adev) +{ + return (struct udma_dev *)dev_get_drvdata(&adev->dev); +} + +static inline struct udma_dev *to_udma_dev(struct ubcore_device *ub_device) +{ + return container_of(ub_device, struct udma_dev, ub_dev); +} + +static inline void udma_id_free(struct udma_ida *ida_table, int idx) +{ + ida_free(&ida_table->ida, idx); +} + +void udma_destroy_tables(struct udma_dev *udma_dev); +int udma_init_tables(struct udma_dev *udma_dev); +int udma_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id); +void udma_remove(struct auxiliary_device *adev); +void udma_reset_init(struct auxiliary_device *adev); +void udma_reset_uninit(struct auxiliary_device *adev); +void udma_reset_down(struct auxiliary_device *adev); + +#endif /* __UDMA_DEV_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c new file mode 100644 index 000000000000..0224b6d248d0 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -0,0 +1,892 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt +#define pr_fmt(fmt) "UDMA: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "udma_dev.h" +#include "udma_cmd.h" +#include "udma_rct.h" +#include "udma_common.h" +#include "udma_ctrlq_tp.h" + +bool is_rmmod; +static DEFINE_MUTEX(udma_reset_mutex); + +static const struct auxiliary_device_id udma_id_table[] = { + { + .name = UBASE_ADEV_NAME ".udma", + }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, udma_id_table); + +static int udma_set_eth_device_speed(struct ubcore_device *dev, + struct ubcore_device_status *dev_status, uint32_t speed) +{ + struct udma_dev *udma_dev = to_udma_dev(dev); + + switch (speed) { + case SPEED_400G: + dev_status->port_status[0].active_speed = UBCORE_SP_400G; + break; + case SPEED_200G: + dev_status->port_status[0].active_speed = UBCORE_SP_200G; + break; + case SPEED_100G: + dev_status->port_status[0].active_speed = UBCORE_SP_100G; + break; + case SPEED_50G: + dev_status->port_status[0].active_speed = UBCORE_SP_50G; + break; + case SPEED_25G: + dev_status->port_status[0].active_speed = UBCORE_SP_25G; + break; + default: + dev_err(udma_dev->dev, "invalid port speed(%u) in UBOE mode.\n", speed); + return -EINVAL; + } + + return 0; +} + +static int udma_query_device_status(struct ubcore_device *dev, + struct ubcore_device_status *dev_status) +{ + struct udma_dev *udma_dev = to_udma_dev(dev); + struct udma_cmd_port_info port_info; + struct ubase_cmd_buf in, out; + int ret; + + dev_status->port_status[0].state = UBCORE_PORT_ACTIVE; + dev_status->port_status[0].active_mtu = UBCORE_MTU_4096; + + udma_fill_buf(&in, UDMA_CMD_QUERY_PORT_INFO, true, 0, NULL); + udma_fill_buf(&out, UDMA_CMD_QUERY_PORT_INFO, true, + sizeof(port_info), (void *)&port_info); + ret = ubase_cmd_send_inout(udma_dev->comdev.adev, &in, &out); + if (ret) { + dev_err(udma_dev->dev, "failed to query speed, ret = %d.\n", ret); + return -EINVAL; + } + + dev_status->port_status[0].active_width = (enum ubcore_link_width)port_info.lanes; + + if (!ubase_adev_ubl_supported(udma_dev->comdev.adev)) + return udma_set_eth_device_speed(dev, dev_status, port_info.speed); + + if (port_info.speed == SPEED_200G) { + dev_status->port_status[0].active_speed = UBCORE_SP_200G; + } else if (port_info.speed == SPEED_400G) { + dev_status->port_status[0].active_speed = UBCORE_SP_400G; + } else { + dev_err(udma_dev->dev, "invalid port speed = %u.\n", port_info.speed); + ret = -EINVAL; + } + + return ret; +} + +static void udma_set_dev_caps(struct ubcore_device_attr *attr, struct udma_dev *udma_dev) +{ + attr->dev_cap.max_jfs_depth = udma_dev->caps.jfs.depth; + attr->dev_cap.max_jfr_depth = udma_dev->caps.jfr.depth; + attr->dev_cap.max_jfc_depth = udma_dev->caps.jfc.depth; + attr->dev_cap.max_jfs = udma_dev->caps.jfs.max_cnt + + udma_dev->caps.public_jetty.max_cnt + + udma_dev->caps.user_ctrl_normal_jetty.max_cnt; + attr->dev_cap.max_jfr = udma_dev->caps.jfr.max_cnt; + attr->dev_cap.max_jfc = udma_dev->caps.jfc.max_cnt; + attr->dev_cap.max_jetty = udma_dev->caps.jetty.max_cnt + + udma_dev->caps.public_jetty.max_cnt + + udma_dev->caps.user_ctrl_normal_jetty.max_cnt; + attr->dev_cap.max_jetty_grp = udma_dev->caps.jetty_grp.max_cnt; + attr->dev_cap.max_jetty_in_jetty_grp = udma_dev->caps.jetty_in_grp; + attr->dev_cap.max_jfs_rsge = udma_dev->caps.jfs_rsge; + attr->dev_cap.max_jfs_sge = udma_dev->caps.jfs_sge; + attr->dev_cap.max_jfs_inline_size = udma_dev->caps.jfs_inline_sz; + attr->dev_cap.max_jfr_sge = udma_dev->caps.jfr_sge; + attr->dev_cap.max_msg_size = udma_dev->caps.max_msg_len; + attr->dev_cap.trans_mode = udma_dev->caps.trans_mode; + attr->port_cnt = udma_dev->caps.port_num; + attr->dev_cap.ceq_cnt = udma_dev->caps.comp_vector_cnt; + attr->dev_cap.max_ue_cnt = udma_dev->caps.ue_cnt; + attr->dev_cap.max_rc = udma_dev->caps.rc_queue_num; + attr->dev_cap.max_rc_depth = udma_dev->caps.rc_queue_depth; + attr->dev_cap.max_eid_cnt = udma_dev->caps.seid.max_cnt; + attr->dev_cap.feature.bs.jfc_inline = (udma_dev->caps.feature & + UDMA_CAP_FEATURE_JFC_INLINE) ? 1 : 0; + attr->dev_cap.max_read_size = udma_dev->caps.max_read_size; + attr->dev_cap.max_write_size = udma_dev->caps.max_write_size; + attr->dev_cap.max_cas_size = udma_dev->caps.max_cas_size; + attr->dev_cap.max_fetch_and_add_size = udma_dev->caps.max_fetch_and_add_size; + attr->dev_cap.atomic_feat.value = udma_dev->caps.atomic_feat; +} + +static int udma_query_device_attr(struct ubcore_device *dev, + struct ubcore_device_attr *attr) +{ + struct udma_dev *udma_dev = to_udma_dev(dev); + + udma_set_dev_caps(attr, udma_dev); + attr->ue_idx = udma_dev->caps.ue_id; + attr->port_attr[0].max_mtu = UBCORE_MTU_4096; + attr->reserved_jetty_id_max = udma_dev->caps.public_jetty.max_cnt - 1; + + return 0; +} + +static struct ubcore_ops g_dev_ops = { + .owner = THIS_MODULE, + .abi_version = 0, + .query_device_attr = udma_query_device_attr, + .query_device_status = udma_query_device_status, + .config_device = udma_config_device, +}; + +static void udma_uninit_group_table(struct udma_dev *dev, struct udma_group_table *table) +{ + if (!xa_empty(&table->xa)) + dev_err(dev->dev, "table is not empty.\n"); + xa_destroy(&table->xa); + + vfree(table->bitmap_table.bit); + table->bitmap_table.bit = NULL; +} + +static void udma_destroy_tp_ue_idx_table(struct udma_dev *udma_dev) +{ + struct udma_ue_idx_table *tp_ue_idx_info; + unsigned long index = 0; + + xa_lock(&udma_dev->tpn_ue_idx_table); + if (!xa_empty(&udma_dev->tpn_ue_idx_table)) { + xa_for_each(&udma_dev->tpn_ue_idx_table, index, tp_ue_idx_info) { + __xa_erase(&udma_dev->tpn_ue_idx_table, index); + kfree(tp_ue_idx_info); + tp_ue_idx_info = NULL; + } + } + + xa_unlock(&udma_dev->tpn_ue_idx_table); + xa_destroy(&udma_dev->tpn_ue_idx_table); +} + +void udma_destroy_tables(struct udma_dev *udma_dev) +{ + udma_destroy_eid_table(udma_dev); + mutex_destroy(&udma_dev->disable_ue_rx_mutex); + if (!ida_is_empty(&udma_dev->rsvd_jetty_ida_table.ida)) + dev_err(udma_dev->dev, + "IDA not empty in clean up rsvd jetty id table.\n"); + ida_destroy(&udma_dev->rsvd_jetty_ida_table.ida); + + if (!xa_empty(&udma_dev->crq_nb_table)) + dev_err(udma_dev->dev, "crq nb table is not empty.\n"); + xa_destroy(&udma_dev->crq_nb_table); + + udma_destroy_tp_ue_idx_table(udma_dev); + + if (!xa_empty(&udma_dev->ksva_table)) + dev_err(udma_dev->dev, "ksva table is not empty.\n"); + xa_destroy(&udma_dev->ksva_table); + mutex_destroy(&udma_dev->ksva_mutex); + udma_destroy_udma_table(udma_dev, &udma_dev->jetty_grp_table, "JettyGroup"); + udma_destroy_udma_table(udma_dev, &udma_dev->jfc_table, "JFC"); + udma_destroy_udma_table(udma_dev, &udma_dev->jfr_table, "JFR"); + udma_uninit_group_table(udma_dev, &udma_dev->jetty_table); +} + +static int udma_init_group_table(struct udma_dev *udma_dev, struct udma_group_table *table, + uint32_t max, uint32_t min, uint32_t num_per_group) +{ + struct udma_group_bitmap *bitmap_table; + int i; + + bitmap_table = &table->bitmap_table; + if (max < min) { + dev_err(udma_dev->dev, + "max value is less than min value when init group bitmap.\n"); + return -EINVAL; + } + + bitmap_table->max = max; + bitmap_table->min = min; + bitmap_table->grp_next = min; + bitmap_table->n_bits = max - min + 1; + bitmap_table->bitmap_cnt = ALIGN(bitmap_table->n_bits, num_per_group) / + num_per_group; + bitmap_table->bit = vmalloc(bitmap_table->bitmap_cnt * sizeof(uint32_t)); + if (!bitmap_table->bit) { + dev_err(udma_dev->dev, "failed to alloc jetty bitmap.\n"); + return -ENOMEM; + } + + for (i = 0; i < bitmap_table->bitmap_cnt; ++i) + bitmap_table->bit[i] = ~(0U); + + spin_lock_init(&bitmap_table->lock); + xa_init(&table->xa); + + return 0; +} + +static void udma_init_managed_by_ctrl_cpu_table(struct udma_dev *udma_dev) +{ + mutex_init(&udma_dev->eid_mutex); + xa_init(&udma_dev->eid_table); +} + +int udma_init_tables(struct udma_dev *udma_dev) +{ + int ret; + + ret = udma_init_group_table(udma_dev, &udma_dev->jetty_table, + udma_dev->caps.jetty.max_cnt + + udma_dev->caps.jetty.start_idx - 1, + udma_dev->caps.jetty.start_idx, + NUM_JETTY_PER_GROUP); + if (ret) { + dev_err(udma_dev->dev, + "failed to init jetty table when start_idx = %u, and max_cnt = %u.\n", + udma_dev->caps.jetty.start_idx, udma_dev->caps.jetty.max_cnt); + return ret; + } + + udma_init_udma_table(&udma_dev->jfr_table, udma_dev->caps.jfr.max_cnt + + udma_dev->caps.jfr.start_idx - 1, udma_dev->caps.jfr.start_idx); + udma_init_udma_table(&udma_dev->jfc_table, udma_dev->caps.jfc.max_cnt + + udma_dev->caps.jfc.start_idx - 1, udma_dev->caps.jfc.start_idx); + udma_init_udma_table(&udma_dev->jetty_grp_table, udma_dev->caps.jetty_grp.max_cnt + + udma_dev->caps.jetty_grp.start_idx - 1, + udma_dev->caps.jetty_grp.start_idx); + udma_init_udma_table_mutex(&udma_dev->ksva_table, &udma_dev->ksva_mutex); + udma_init_udma_table_mutex(&udma_dev->npu_nb_table, &udma_dev->npu_nb_mutex); + xa_init(&udma_dev->tpn_ue_idx_table); + xa_init(&udma_dev->crq_nb_table); + ida_init(&udma_dev->rsvd_jetty_ida_table.ida); + mutex_init(&udma_dev->disable_ue_rx_mutex); + udma_init_managed_by_ctrl_cpu_table(udma_dev); + + return 0; +} + +static void udma_free_rct(struct udma_dev *udev) +{ + uint32_t min = udev->rc_table.ida_table.min; + uint32_t max = udev->rc_table.ida_table.max; + uint32_t i; + + if (test_and_clear_bit(RCT_INIT_FLAG, &udev->caps.init_flag)) + for (i = min; i < max; i++) + udma_free_rc_queue(udev, i); +} + +static void udma_unset_ubcore_dev(struct udma_dev *udma_dev) +{ + struct ubcore_device *ub_dev = &udma_dev->ub_dev; + + ubcore_unregister_device(ub_dev); + udma_free_rct(udma_dev); +} + +static int udma_set_ubcore_dev(struct udma_dev *udma_dev) +{ + struct ubcore_device *ub_dev = &udma_dev->ub_dev; + int ret; + + ub_dev->transport_type = UBCORE_TRANSPORT_UB; + ub_dev->ops = &g_dev_ops; + ub_dev->dev.parent = udma_dev->dev; + ub_dev->dma_dev = ub_dev->dev.parent; + ub_dev->attr.dev_cap.feature.value = udma_dev->caps.feature; + + scnprintf(udma_dev->dev_name, UBCORE_MAX_DEV_NAME, "udma%hu", udma_dev->adev_id); + strscpy(ub_dev->dev_name, udma_dev->dev_name, UBCORE_MAX_DEV_NAME); + scnprintf(ub_dev->ops->driver_name, UBCORE_MAX_DRIVER_NAME, "udma"); + + ret = ubcore_register_device(ub_dev); + if (ret) + dev_err(udma_dev->dev, "failed to register udma_dev to ubcore, ret is %d.\n", ret); + + return ret; +} + +static void udma_dump_jetty_id_range(struct udma_dev *udma_dev) +{ +#define UDMA_JETTY_CNT 6 + const char *jetty_name[UDMA_JETTY_CNT] = { + "public", + "ccu", + "hdc", + "cache_lock", + "user_ctrl_normal", + "urma_normal", + }; + struct udma_res *jetty_res_list[UDMA_JETTY_CNT] = { + &udma_dev->caps.public_jetty, + &udma_dev->caps.ccu_jetty, + &udma_dev->caps.hdc_jetty, + &udma_dev->caps.stars_jetty, + &udma_dev->caps.user_ctrl_normal_jetty, + &udma_dev->caps.jetty, + }; + uint32_t i; + + for (i = 0; i < UDMA_JETTY_CNT; i++) + dev_info(udma_dev->dev, "%s jetty start_idx=%u, max_cnt=%u\n", + jetty_name[i], jetty_res_list[i]->start_idx, + jetty_res_list[i]->max_cnt); +} + +static void udma_get_jetty_id_range(struct udma_dev *udma_dev, + struct udma_cmd_ue_resource *cmd) +{ + udma_dev->caps.public_jetty.start_idx = cmd->well_known_jetty_start; + udma_dev->caps.public_jetty.max_cnt = cmd->well_known_jetty_num; + + udma_dev->caps.ccu_jetty.start_idx = cmd->ccu_jetty_start; + udma_dev->caps.ccu_jetty.max_cnt = cmd->ccu_jetty_num; + udma_dev->caps.ccu_jetty.next_idx = udma_dev->caps.ccu_jetty.start_idx; + + udma_dev->caps.hdc_jetty.start_idx = cmd->drv_jetty_start; + udma_dev->caps.hdc_jetty.max_cnt = cmd->drv_jetty_num; + + udma_dev->caps.stars_jetty.start_idx = cmd->cache_lock_jetty_start; + udma_dev->caps.stars_jetty.max_cnt = cmd->cache_lock_jetty_num; + udma_dev->caps.stars_jetty.next_idx = udma_dev->caps.stars_jetty.start_idx; + + udma_dev->caps.user_ctrl_normal_jetty.start_idx = cmd->normal_jetty_start; + udma_dev->caps.user_ctrl_normal_jetty.max_cnt = cmd->normal_jetty_num; + udma_dev->caps.user_ctrl_normal_jetty.next_idx = + udma_dev->caps.user_ctrl_normal_jetty.start_idx; + + udma_dev->caps.jetty.start_idx = cmd->standard_jetty_start; + udma_dev->caps.jetty.max_cnt = cmd->standard_jetty_num; + + udma_dev->caps.rsvd_jetty_cnt = udma_dev->caps.public_jetty.max_cnt + + udma_dev->caps.ccu_jetty.max_cnt + + udma_dev->caps.hdc_jetty.max_cnt + + udma_dev->caps.stars_jetty.max_cnt + + udma_dev->caps.user_ctrl_normal_jetty.max_cnt; + + if (debug_switch) + udma_dump_jetty_id_range(udma_dev); +} + +static int query_caps_from_firmware(struct udma_dev *udma_dev) +{ +#define RC_QUEUE_ENTRY_SIZE 128 + struct udma_cmd_ue_resource cmd = {}; + int ret; + + ret = udma_cmd_query_hw_resource(udma_dev, (void *)&cmd); + if (ret) { + dev_err(udma_dev->dev, "fail to query hw resource from FW %d\n", ret); + return ret; + } + + udma_dev->caps.jfs_sge = cmd.jfs_sge; + udma_dev->caps.jfs_rsge = cmd.jfs_rsge; + udma_dev->caps.jfr_sge = cmd.jfr_sge; + udma_dev->caps.jfs_inline_sz = cmd.max_jfs_inline_sz; + udma_dev->caps.jetty_grp.max_cnt = cmd.jetty_grp_num; + udma_dev->caps.trans_mode = cmd.trans_mode; + udma_dev->caps.seid.size = cmd.seid_upi_tbl_sz; + udma_dev->caps.seid.max_cnt = cmd.seid_upi_tbl_num; + udma_dev->caps.port_num = cmd.port_num; + udma_dev->caps.max_read_size = cmd.max_read_size; + udma_dev->caps.max_write_size = cmd.max_write_size; + udma_dev->caps.max_cas_size = cmd.max_cas_size; + udma_dev->caps.max_fetch_and_add_size = cmd.max_fetch_and_add_size; + udma_dev->caps.atomic_feat = cmd.atomic_feat; + + udma_get_jetty_id_range(udma_dev, &cmd); + + udma_dev->caps.rc_queue_num = cmd.rc_queue_num; + udma_dev->caps.rc_queue_depth = cmd.rc_depth; + udma_dev->caps.rc_entry_size = RC_QUEUE_ENTRY_SIZE; + + udma_dev->caps.feature = cmd.cap_info; + udma_dev->caps.ue_cnt = cmd.ue_cnt >= UDMA_DEV_UE_NUM ? + UDMA_DEV_UE_NUM - 1 : cmd.ue_cnt; + udma_dev->caps.ue_id = cmd.ue_id; + udma_dev->is_ue = !!(cmd.ue_id); + + return 0; +} + +static void get_dev_caps_from_ubase(struct udma_dev *udma_dev) +{ + struct ubase_caps *ubase_caps; + + ubase_caps = ubase_get_dev_caps(udma_dev->comdev.adev); + + udma_dev->caps.comp_vector_cnt = ubase_caps->num_ceq_vectors; + udma_dev->caps.ack_queue_num = ubase_caps->ack_queue_num; + + udma_dev->chip_id = ubase_caps->chip_id; + udma_dev->die_id = ubase_caps->die_id; + udma_dev->port_id = ubase_caps->io_port_id; + udma_dev->port_logic_id = ubase_caps->io_port_logic_id; + udma_dev->ue_id = ubase_caps->ue_id; +} + +static int udma_construct_qos_param(struct udma_dev *dev) +{ + struct ubase_adev_qos *qos_info; + uint8_t i; + + qos_info = ubase_get_adev_qos(dev->comdev.adev); + if (!qos_info) { + dev_err(dev->dev, "cannot get qos information from ubase.\n"); + return -EINVAL; + } + + dev->udma_tp_sl_num = qos_info->tp_sl_num; + dev->udma_ctp_sl_num = qos_info->ctp_sl_num; + dev->unic_sl_num = qos_info->nic_sl_num; + dev->udma_tp_resp_vl_off = qos_info->tp_resp_vl_offset; + dev->udma_total_sl_num = dev->udma_tp_sl_num + dev->udma_ctp_sl_num; + if (dev->udma_total_sl_num > UDMA_MAX_SL_NUM) { + dev_err(dev->dev, + "total sl num is invalid, tp sl num is %u, ctp sl num is %u.\n", + dev->udma_tp_sl_num, dev->udma_ctp_sl_num); + return -EINVAL; + } + + (void)memcpy(dev->udma_tp_sl, + qos_info->tp_sl, sizeof(u8) * qos_info->tp_sl_num); + (void)memcpy(dev->udma_ctp_sl, + qos_info->ctp_sl, sizeof(u8) * qos_info->ctp_sl_num); + (void)memcpy(dev->unic_sl, + qos_info->nic_sl, sizeof(u8) * qos_info->nic_sl_num); + (void)memcpy(dev->udma_sl, + qos_info->tp_sl, sizeof(u8) * qos_info->tp_sl_num); + + for (i = 0; i < qos_info->ctp_sl_num; i++) + dev->udma_sl[qos_info->tp_sl_num + i] = qos_info->ctp_sl[i]; + + return 0; +} + +static int udma_set_hw_caps(struct udma_dev *udma_dev) +{ +#define MAX_MSG_LEN 0x10000 + struct ubase_adev_caps *a_caps; + uint32_t jetty_grp_cnt; + int ret; + + get_dev_caps_from_ubase(udma_dev); + + ret = query_caps_from_firmware(udma_dev); + if (ret) + return ret; + + a_caps = ubase_get_udma_caps(udma_dev->comdev.adev); + udma_dev->caps.jfs.max_cnt = a_caps->jfs.max_cnt; + udma_dev->caps.jfs.depth = a_caps->jfs.depth / MAX_WQEBB_IN_SQE; + udma_dev->caps.jfs.start_idx = a_caps->jfs.start_idx; + udma_dev->caps.jfr.max_cnt = a_caps->jfr.max_cnt; + udma_dev->caps.jfr.depth = a_caps->jfr.depth; + udma_dev->caps.jfr.start_idx = a_caps->jfr.start_idx; + udma_dev->caps.jfc.max_cnt = a_caps->jfc.max_cnt; + udma_dev->caps.jfc.depth = a_caps->jfc.depth; + udma_dev->caps.jfc.start_idx = a_caps->jfc.start_idx; + udma_dev->caps.jetty.max_cnt = a_caps->jfs.max_cnt; + udma_dev->caps.jetty.depth = a_caps->jfs.depth; + udma_dev->caps.jetty.start_idx = a_caps->jfs.start_idx; + udma_dev->caps.jetty.next_idx = udma_dev->caps.jetty.start_idx; + udma_dev->caps.cqe_size = UDMA_CQE_SIZE; + ret = udma_construct_qos_param(udma_dev); + if (ret) + return ret; + + udma_dev->caps.max_msg_len = MAX_MSG_LEN; + udma_dev->caps.jetty_in_grp = MAX_JETTY_IN_JETTY_GRP; + + if (udma_dev->caps.jetty_in_grp) { + jetty_grp_cnt = udma_dev->caps.jetty.max_cnt / udma_dev->caps.jetty_in_grp; + udma_dev->caps.jetty_grp.max_cnt = + jetty_grp_cnt < udma_dev->caps.jetty_grp.max_cnt ? + jetty_grp_cnt : udma_dev->caps.jetty_grp.max_cnt; + } + + return 0; +} + +static int udma_init_dev_param(struct udma_dev *udma_dev) +{ + struct auxiliary_device *adev = udma_dev->comdev.adev; + struct ubase_resource_space *mem_base = ubase_get_mem_base(adev); + int ret; + + udma_dev->dev = adev->dev.parent; + udma_dev->db_base = mem_base->addr_unmapped; + udma_dev->k_db_base = mem_base->addr; + udma_dev->adev_id = udma_dev->comdev.adev->id; + + ret = udma_set_hw_caps(udma_dev); + if (ret) { + dev_err(udma_dev->dev, "failed to query hw caps, ret = %d\n", ret); + return ret; + } + + ret = udma_init_tables(udma_dev); + if (ret) { + dev_err(udma_dev->dev, + "Failed to init tables, ret = %d\n", ret); + return ret; + } + + dev_set_drvdata(&adev->dev, udma_dev); + + return 0; +} + +static void udma_uninit_dev_param(struct udma_dev *udma_dev) +{ + dev_set_drvdata(&udma_dev->comdev.adev->dev, NULL); + udma_destroy_tables(udma_dev); +} + +static int udma_alloc_dev_tid(struct udma_dev *udma_dev) +{ + struct ummu_seg_attr seg_attr = {.token = NULL, .e_bit = UMMU_EBIT_ON}; + struct ummu_param param = {.mode = MAPT_MODE_TABLE}; + int ret; + + ret = iommu_dev_enable_feature(udma_dev->dev, IOMMU_DEV_FEAT_KSVA); + if (ret) { + dev_err(udma_dev->dev, "enable ksva failed, ret = %d.\n", ret); + return ret; + } + + ret = iommu_dev_enable_feature(udma_dev->dev, IOMMU_DEV_FEAT_SVA); + if (ret) { + dev_err(udma_dev->dev, "enable sva failed, ret = %d.\n", ret); + goto err_sva_enable_dev; + } + + udma_dev->ksva = ummu_ksva_bind_device(udma_dev->dev, ¶m); + if (!udma_dev->ksva) { + dev_err(udma_dev->dev, "ksva bind device failed.\n"); + ret = -EINVAL; + goto err_ksva_bind_device; + } + + ret = ummu_get_tid(udma_dev->dev, udma_dev->ksva, &udma_dev->tid); + if (ret) { + dev_err(udma_dev->dev, "Failed to get tid for udma device.\n"); + goto err_get_tid; + } + + ret = ummu_sva_grant_range(udma_dev->ksva, 0, UDMA_MAX_GRANT_SIZE, + UMMU_DEV_WRITE | UMMU_DEV_READ, &seg_attr); + if (ret) { + dev_err(udma_dev->dev, "Failed to sva grant range for udma device.\n"); + goto err_sva_grant_range; + } + + return ret; + +err_sva_grant_range: +err_get_tid: + ummu_ksva_unbind_device(udma_dev->ksva); +err_ksva_bind_device: + if (iommu_dev_disable_feature(udma_dev->dev, IOMMU_DEV_FEAT_SVA)) + dev_warn(udma_dev->dev, "disable sva failed.\n"); +err_sva_enable_dev: + if (iommu_dev_disable_feature(udma_dev->dev, IOMMU_DEV_FEAT_KSVA)) + dev_warn(udma_dev->dev, "disable ksva failed.\n"); + return ret; +} + +static void udma_free_dev_tid(struct udma_dev *udma_dev) +{ + struct iommu_sva *ksva = NULL; + size_t token_id; + int ret; + + ret = ummu_sva_ungrant_range(udma_dev->ksva, 0, UDMA_MAX_GRANT_SIZE, NULL); + if (ret) + dev_warn(udma_dev->dev, + "sva ungrant range for udma device failed, ret = %d.\n", + ret); + + mutex_lock(&udma_dev->ksva_mutex); + xa_for_each(&udma_dev->ksva_table, token_id, ksva) { + __xa_erase(&udma_dev->ksva_table, token_id); + ummu_ksva_unbind_device(ksva); + } + mutex_unlock(&udma_dev->ksva_mutex); + + ummu_ksva_unbind_device(udma_dev->ksva); + + ret = iommu_dev_disable_feature(udma_dev->dev, IOMMU_DEV_FEAT_SVA); + if (ret) + dev_warn(udma_dev->dev, "disable sva failed, ret = %d.\n", ret); + + ret = iommu_dev_disable_feature(udma_dev->dev, IOMMU_DEV_FEAT_KSVA); + if (ret) + dev_warn(udma_dev->dev, "disable ksva failed, ret = %d.\n", ret); +} + +static int udma_create_db_page(struct udma_dev *udev) +{ + udev->db_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!udev->db_page) + return -ENOMEM; + + return 0; +} + +static void udma_destroy_db_page(struct udma_dev *udev) +{ + put_page(udev->db_page); + udev->db_page = NULL; +} + +static const struct udma_func_map udma_dev_func_map[] = { + {"dev param", udma_init_dev_param, udma_uninit_dev_param}, + {"cmd", udma_cmd_init, udma_cmd_cleanup}, + {"dev tid", udma_alloc_dev_tid, udma_free_dev_tid}, + {"db page", udma_create_db_page, udma_destroy_db_page}, +}; + +static void udma_destroy_dev(struct udma_dev *udev) +{ + int i; + + for (i = ARRAY_SIZE(udma_dev_func_map) - 1; i >= 0; i--) + if (udma_dev_func_map[i].uninit_func) + udma_dev_func_map[i].uninit_func(udev); + kfree(udev); +} + +static struct udma_dev *udma_create_dev(struct auxiliary_device *adev) +{ + struct udma_dev *udma_dev; + int ret, i; + + udma_dev = kzalloc((sizeof(struct udma_dev)), GFP_KERNEL); + if (udma_dev == NULL) + return NULL; + + udma_dev->comdev.adev = adev; + + for (i = 0; i < ARRAY_SIZE(udma_dev_func_map); i++) { + if (!udma_dev_func_map[i].init_func) + continue; + + ret = udma_dev_func_map[i].init_func(udma_dev); + if (ret) { + dev_err(udma_dev->dev, "Failed to init %s, ret = %d\n", + udma_dev_func_map[i].err_msg, ret); + goto err_init; + } + } + + return udma_dev; + +err_init: + for (i -= 1; i >= 0; i--) + if (udma_dev_func_map[i].uninit_func) + udma_dev_func_map[i].uninit_func(udma_dev); + + kfree(udma_dev); + return NULL; +} + +static bool udma_is_need_probe(struct auxiliary_device *adev) +{ + struct udma_dev *udma_dev; + + if (is_rmmod) { + dev_info(&adev->dev, + "udma drv is uninstalling, not allowed to create dev(%s.%u).\n", + adev->name, adev->id); + return false; + } + + udma_dev = get_udma_dev(adev); + if (udma_dev) { + dev_info(&adev->dev, + "dev(%s.%u) is exist, bypass probe.\n", + adev->name, adev->id); + return false; + } + + return true; +} + +static void udma_reset_handler(struct auxiliary_device *adev, + enum ubase_reset_stage stage) +{ + switch (stage) { + case UBASE_RESET_STAGE_DOWN: + udma_reset_down(adev); + break; + case UBASE_RESET_STAGE_UNINIT: + udma_reset_uninit(adev); + break; + case UBASE_RESET_STAGE_INIT: + udma_reset_init(adev); + break; + default: + break; + } +} + +static int udma_init_dev(struct auxiliary_device *adev) +{ + struct udma_dev *udma_dev; + int ret; + + mutex_lock(&udma_reset_mutex); + dev_info(&adev->dev, "udma init dev called, matched aux dev(%s.%u).\n", + adev->name, adev->id); + if (!udma_is_need_probe(adev)) { + mutex_unlock(&udma_reset_mutex); + return 0; + } + + udma_dev = udma_create_dev(adev); + if (!udma_dev) + goto err_create; + + ret = udma_set_ubcore_dev(udma_dev); + if (ret) { + dev_err(udma_dev->dev, "failed to set ubcore dev, ret is %d.\n", ret); + goto err_create; + } + + udma_dev->status = UDMA_NORMAL; + mutex_unlock(&udma_reset_mutex); + dev_info(udma_dev->dev, "init udma successfully.\n"); + + return 0; + +err_create: + mutex_unlock(&udma_reset_mutex); + + return -EINVAL; +} + +void udma_reset_down(struct auxiliary_device *adev) +{ + struct udma_dev *udma_dev; + + mutex_lock(&udma_reset_mutex); + udma_dev = get_udma_dev(adev); + if (!udma_dev) { + mutex_unlock(&udma_reset_mutex); + dev_info(&adev->dev, "udma device is not exist.\n"); + return; + } + + if (udma_dev->status != UDMA_NORMAL) { + mutex_unlock(&udma_reset_mutex); + dev_info(&adev->dev, "udma device status(%u).\n", udma_dev->status); + return; + } + + udma_dev->status = UDMA_SUSPEND; + + udma_unset_ubcore_dev(udma_dev); + mutex_unlock(&udma_reset_mutex); +} + +void udma_reset_uninit(struct auxiliary_device *adev) +{ + struct udma_dev *udma_dev; + + mutex_lock(&udma_reset_mutex); + udma_dev = get_udma_dev(adev); + if (!udma_dev) { + dev_info(&adev->dev, "udma device is not exist.\n"); + mutex_unlock(&udma_reset_mutex); + return; + } + + if (udma_dev->status != UDMA_SUSPEND) { + dev_info(&adev->dev, "udma device status(%u).\n", udma_dev->status); + mutex_unlock(&udma_reset_mutex); + return; + } + + udma_destroy_dev(udma_dev); + mutex_unlock(&udma_reset_mutex); +} + +void udma_reset_init(struct auxiliary_device *adev) +{ + udma_init_dev(adev); +} + +int udma_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + if (udma_init_dev(adev)) + return -EINVAL; + + ubase_reset_register(adev, udma_reset_handler); + return 0; +} + +void udma_remove(struct auxiliary_device *adev) +{ + struct udma_dev *udma_dev; + + udma_dev = get_udma_dev(adev); + if (!udma_dev) { + dev_info(&adev->dev, "udma device is not exist.\n"); + ubase_reset_unregister(adev); + return; + } + + udma_reset_down(adev); + udma_reset_uninit(adev); + + ubase_reset_unregister(adev); +} + +static struct auxiliary_driver udma_drv = { + .name = "udma", + .probe = udma_probe, + .remove = udma_remove, + .id_table = udma_id_table, +}; + +static int __init udma_init(void) +{ + int ret; + + ret = auxiliary_driver_register(&udma_drv); + if (ret) + pr_err("failed to register auxiliary_driver\n"); + + return ret; +} + +static void __exit udma_exit(void) +{ + is_rmmod = true; + auxiliary_driver_unregister(&udma_drv); +} + +module_init(udma_init); +module_exit(udma_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/ub/urma/hw/udma/udma_rct.c b/drivers/ub/urma/hw/udma/udma_rct.c new file mode 100644 index 000000000000..149b9b6f27b4 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_rct.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt + +#include +#include "udma_cmd.h" +#include "udma_rct.h" + +static int udma_create_rc_queue_ctx(struct udma_dev *dev, struct udma_rc_queue *rcq) +{ + struct ubase_mbx_attr attr = {}; + struct udma_rc_ctx ctx = {}; + + ctx.type = RC_TYPE; + ctx.state = RC_READY_STATE; + ctx.rce_token_id_l = dev->tid & (uint32_t)RCE_TOKEN_ID_L_MASK; + ctx.rce_token_id_h = dev->tid >> RCE_TOKEN_ID_H_OFFSET; + ctx.rce_base_addr_l = (rcq->buf.addr >> RCE_ADDR_L_OFFSET) & + (uint32_t)RCE_ADDR_L_MASK; + ctx.rce_base_addr_h = rcq->buf.addr >> RCE_ADDR_H_OFFSET; + ctx.rce_shift = ilog2(roundup_pow_of_two(rcq->buf.entry_cnt)); + ctx.avail_sgmt_ost = RC_AVAIL_SGMT_OST; + + attr.tag = rcq->id; + attr.op = UDMA_CMD_CREATE_RC_CONTEXT; + + return post_mailbox_update_ctx(dev, &ctx, sizeof(ctx), &attr); +} + +static int udma_destroy_rc_queue_ctx(struct udma_dev *dev, struct udma_rc_queue *rcq) +{ + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + int ret; + + mailbox = udma_alloc_cmd_mailbox(dev); + if (!mailbox) { + dev_err(dev->dev, "failed to alloc mailbox for rc queue.\n"); + return -ENOMEM; + } + + mbox_attr.tag = rcq->id; + mbox_attr.op = UDMA_CMD_DESTROY_RC_CONTEXT; + ret = udma_post_mbox(dev, mailbox, &mbox_attr); + if (ret) + dev_err(dev->dev, "failed to destroy rc queue ctx, ret = %d.\n", ret); + + udma_free_cmd_mailbox(dev, mailbox); + + return ret; +} + +static int udma_alloc_rc_queue(struct udma_dev *dev, + struct ubcore_device_cfg *cfg, int rc_queue_id) +{ + uint32_t rcq_entry_size = dev->caps.rc_entry_size; + uint32_t rcq_entry_num = cfg->rc_cfg.depth; + struct udma_rc_queue *rcq; + uint32_t size; + int ret; + + rcq = kzalloc(sizeof(struct udma_rc_queue), GFP_KERNEL); + if (!rcq) + return -ENOMEM; + rcq->id = rc_queue_id; + + size = rcq_entry_size * rcq_entry_num; + rcq->buf.kva_or_slot = udma_alloc_iova(dev, size, &rcq->buf.addr); + if (!rcq->buf.kva_or_slot) { + ret = -ENOMEM; + dev_err(dev->dev, "failed to alloc rc queue buffer.\n"); + goto err_alloc_rcq; + } + rcq->buf.entry_size = rcq_entry_size; + rcq->buf.entry_cnt = rcq_entry_num; + + ret = udma_create_rc_queue_ctx(dev, rcq); + if (ret) { + dev_err(dev->dev, + "failed to create rc queue ctx, rcq id %u, ret = %d.\n", + rcq->id, ret); + goto err_create_rcq_ctx; + } + + ret = xa_err(xa_store(&dev->rc_table.xa, rcq->id, rcq, GFP_KERNEL)); + if (ret) { + dev_err(dev->dev, + "failed to stored rcq id to rc table, rcq id %d.\n", + rc_queue_id); + goto err_store_rcq_id; + } + + return ret; + +err_store_rcq_id: + if (udma_destroy_rc_queue_ctx(dev, rcq)) + dev_err(dev->dev, + "udma destroy rc queue ctx failed when alloc rc queue.\n"); +err_create_rcq_ctx: + udma_free_iova(dev, size, rcq->buf.kva_or_slot, rcq->buf.addr); + rcq->buf.kva_or_slot = NULL; + rcq->buf.addr = 0; +err_alloc_rcq: + kfree(rcq); + + return ret; +} + +void udma_free_rc_queue(struct udma_dev *dev, int rc_queue_id) +{ + struct udma_rc_queue *rcq; + int ret; + + rcq = (struct udma_rc_queue *)xa_load(&dev->rc_table.xa, rc_queue_id); + if (!rcq) { + dev_warn(dev->dev, + "failed to find rcq, id = %d.\n", rc_queue_id); + return; + } + + xa_erase(&dev->rc_table.xa, rc_queue_id); + ret = udma_destroy_rc_queue_ctx(dev, rcq); + if (ret) + dev_err(dev->dev, + "udma destroy rc queue ctx failed, ret = %d.\n", ret); + + udma_free_iova(dev, rcq->buf.entry_size * rcq->buf.entry_cnt, + rcq->buf.kva_or_slot, rcq->buf.addr); + rcq->buf.kva_or_slot = NULL; + rcq->buf.addr = 0; + kfree(rcq); +} + +static int udma_config_rc_table(struct udma_dev *dev, struct ubcore_device_cfg *cfg) +{ + uint32_t rc_ctx_num = cfg->rc_cfg.rc_cnt; + int ret = 0; + int i; + + for (i = 0; i < rc_ctx_num; i++) { + ret = udma_alloc_rc_queue(dev, cfg, i); + if (ret) { + dev_err(dev->dev, "failed to alloc rc queue.\n"); + goto err_alloc_rc_queue; + } + } + dev->rc_table.ida_table.min = 0; + dev->rc_table.ida_table.max = rc_ctx_num; + + return ret; + +err_alloc_rc_queue: + for (i -= 1; i >= 0; i--) + udma_free_rc_queue(dev, i); + + return ret; +} + +static int check_and_config_rc_table(struct udma_dev *dev, struct ubcore_device_cfg *cfg) +{ + int ret = 0; + + if (!cfg->mask.bs.rc_cnt && !cfg->mask.bs.rc_depth) + return 0; + + if (!cfg->mask.bs.rc_cnt || !cfg->mask.bs.rc_depth) { + dev_err(dev->dev, "Invalid rc mask, mask = %u.\n", cfg->mask.value); + return -EINVAL; + } + + if (!cfg->rc_cfg.rc_cnt || !cfg->rc_cfg.depth || + cfg->rc_cfg.rc_cnt > dev->caps.rc_queue_num || + cfg->rc_cfg.rc_cnt <= dev->caps.ack_queue_num) { + dev_err(dev->dev, + "Invalid rc param, rc cnt = %u, rc depth = %u, rc num = %u, ack queue num = %u.\n", + cfg->rc_cfg.rc_cnt, cfg->rc_cfg.depth, + dev->caps.rc_queue_num, dev->caps.ack_queue_num); + return -EINVAL; + } + + if (!test_and_set_bit_lock(RCT_INIT_FLAG, &dev->caps.init_flag)) + ret = udma_config_rc_table(dev, cfg); + + return ret; +} + +int udma_config_device(struct ubcore_device *ubcore_dev, + struct ubcore_device_cfg *cfg) +{ + struct udma_dev *dev = to_udma_dev(ubcore_dev); + int ret; + + if ((cfg->mask.bs.reserved_jetty_id_min && cfg->reserved_jetty_id_min != 0) || + (cfg->mask.bs.reserved_jetty_id_max && cfg->reserved_jetty_id_max != + dev->caps.public_jetty.max_cnt - 1)) { + dev_err(dev->dev, "public jetty range must 0-%u.\n", + dev->caps.public_jetty.max_cnt - 1); + return -EINVAL; + } + + ret = check_and_config_rc_table(dev, cfg); + if (ret) + dev_err(dev->dev, "failed to check device cfg, ret = %d.\n", ret); + + return ret; +} diff --git a/drivers/ub/urma/hw/udma/udma_rct.h b/drivers/ub/urma/hw/udma/udma_rct.h new file mode 100644 index 000000000000..fc1e47d95043 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_rct.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_RCT_H__ +#define __UDMA_RCT_H__ + +#include "udma_common.h" + +#define RC_TYPE 2U +#define RC_READY_STATE 1U +#define RC_AVAIL_SGMT_OST 512U + +#define RCE_TOKEN_ID_L_MASK GENMASK(11, 0) +#define RCE_TOKEN_ID_H_OFFSET 12U +#define RCE_ADDR_L_OFFSET 12U +#define RCE_ADDR_L_MASK GENMASK(19, 0) +#define RCE_ADDR_H_OFFSET 32U + +struct udma_rc_queue { + uint32_t id; + struct udma_buf buf; +}; + +struct udma_rc_ctx { + /* DW0 */ + uint32_t rsv0 : 5; + uint32_t type : 3; + uint32_t rce_shift : 4; + uint32_t rsv1 : 4; + uint32_t state : 3; + uint32_t rsv2 : 1; + uint32_t rce_token_id_l : 12; + /* DW1 */ + uint32_t rce_token_id_h : 8; + uint32_t rsv3 : 4; + uint32_t rce_base_addr_l : 20; + /* DW2 */ + uint32_t rce_base_addr_h; + /* DW3~DW31 */ + uint32_t rsv4[28]; + uint32_t avail_sgmt_ost : 10; + uint32_t rsv5 : 22; + /* DW32~DW63 */ + uint32_t rsv6[32]; +}; + +struct udma_vir_cap { + uint8_t ue_idx; + uint8_t virtualization : 1; + uint8_t rsv : 7; +}; + +int udma_config_device(struct ubcore_device *ubcore_dev, + struct ubcore_device_cfg *cfg); +void udma_free_rc_queue(struct udma_dev *dev, int rc_queue_id); + +#endif /* __UDMA_RCT_H__ */ -- Gitee From 761c49d2e3a78fbfaf3667ea14e74d041a6306ec Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Thu, 18 Sep 2025 09:56:27 +0800 Subject: [PATCH 042/103] ub: udma: Create and destroy u-context. commit a1bbc9c41db4be60b93519f2146c09da30eb3298 openEuler This patch supports create and destroy u-context. At the same time, this patch also added function related to tid and doorbell during the driver loading process.In addition, this patch also adds basic functionalities such as applying for IDs and pin memory. Signed-off-by: Wei Qin Signed-off-by: Shengming Shu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/Makefile | 4 +- drivers/ub/urma/hw/udma/udma_common.c | 455 ++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_common.h | 39 +++ drivers/ub/urma/hw/udma/udma_ctl.h | 213 ++++++++++++ drivers/ub/urma/hw/udma/udma_ctx.c | 178 ++++++++++ drivers/ub/urma/hw/udma/udma_ctx.h | 42 +++ drivers/ub/urma/hw/udma/udma_db.c | 176 ++++++++++ drivers/ub/urma/hw/udma/udma_db.h | 16 + drivers/ub/urma/hw/udma/udma_def.h | 38 +++ drivers/ub/urma/hw/udma/udma_dev.h | 19 ++ drivers/ub/urma/hw/udma/udma_jetty.h | 30 ++ drivers/ub/urma/hw/udma/udma_jfs.h | 30 ++ drivers/ub/urma/hw/udma/udma_main.c | 23 ++ drivers/ub/urma/hw/udma/udma_tid.c | 142 ++++++++ drivers/ub/urma/hw/udma/udma_tid.h | 25 ++ include/uapi/ub/urma/udma/udma_abi.h | 178 ++++++++++ include/ub/urma/udma/udma_ctl.h | 213 ++++++++++++ 17 files changed, 1819 insertions(+), 2 deletions(-) create mode 100644 drivers/ub/urma/hw/udma/udma_ctl.h create mode 100644 drivers/ub/urma/hw/udma/udma_ctx.c create mode 100644 drivers/ub/urma/hw/udma/udma_ctx.h create mode 100644 drivers/ub/urma/hw/udma/udma_db.c create mode 100644 drivers/ub/urma/hw/udma/udma_db.h create mode 100644 drivers/ub/urma/hw/udma/udma_jetty.h create mode 100644 drivers/ub/urma/hw/udma/udma_jfs.h create mode 100644 drivers/ub/urma/hw/udma/udma_tid.c create mode 100644 drivers/ub/urma/hw/udma/udma_tid.h create mode 100644 include/uapi/ub/urma/udma/udma_abi.h create mode 100644 include/ub/urma/udma/udma_ctl.h diff --git a/drivers/ub/urma/hw/udma/Makefile b/drivers/ub/urma/hw/udma/Makefile index 2cd71b916ec9..0561b3f85191 100644 --- a/drivers/ub/urma/hw/udma/Makefile +++ b/drivers/ub/urma/hw/udma/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0+ -udma-$(CONFIG_UB_UDMA) := udma_main.o udma_cmd.o udma_common.o \ - udma_rct.o +udma-$(CONFIG_UB_UDMA) := udma_main.o udma_cmd.o udma_common.o udma_ctx.o udma_db.o \ + udma_rct.o udma_tid.o obj-m := udma.o diff --git a/drivers/ub/urma/hw/udma/udma_common.c b/drivers/ub/urma/hw/udma/udma_common.c index cb8e6b6f4e90..d313e1d17443 100644 --- a/drivers/ub/urma/hw/udma/udma_common.c +++ b/drivers/ub/urma/hw/udma/udma_common.c @@ -12,10 +12,403 @@ #include #include #include +#include #include "udma_dev.h" #include "udma_cmd.h" #include "udma_common.h" +static int udma_verify_input(struct udma_umem_param *param) +{ + struct udma_dev *udma_dev = to_udma_dev(param->ub_dev); + + if (((param->va + param->len) < param->va) || + PAGE_ALIGN(param->va + param->len) < (param->va + param->len)) { + dev_err(udma_dev->dev, "invalid pin_page param, len=%llu.\n", + param->len); + return -EINVAL; + } + return 0; +} + +static void udma_fill_umem(struct ubcore_umem *umem, struct udma_umem_param *param) +{ + umem->ub_dev = param->ub_dev; + umem->va = param->va; + umem->length = param->len; + umem->flag = param->flag; +} + +static struct scatterlist *udma_sg_set_page(struct scatterlist *sg_start, + int pinned, struct page **page_list) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sg_start, sg, pinned, i) + sg_set_page(sg, page_list[i], PAGE_SIZE, 0); + + return sg; +} + +static int udma_pin_pages(uint64_t cur_base, uint64_t npages, + uint32_t gup_flags, struct page **page_list) +{ + return pin_user_pages_fast(cur_base, min_t(unsigned long, (unsigned long)npages, + PAGE_SIZE / sizeof(struct page *)), + gup_flags | FOLL_LONGTERM, page_list); +} + +static uint64_t udma_pin_all_pages(struct udma_dev *udma_dev, struct ubcore_umem *umem, + uint64_t npages, uint32_t gup_flags, + struct page **page_list) +{ + struct scatterlist *sg_list_start = umem->sg_head.sgl; + uint64_t cur_base = umem->va & PAGE_MASK; + uint64_t page_count = npages; + int pinned; + + while (page_count != 0) { + cond_resched(); + pinned = udma_pin_pages(cur_base, page_count, gup_flags, page_list); + if (pinned <= 0) { + dev_err(udma_dev->dev, "failed to pin_user_pages_fast, page_count: %llu, pinned: %d.\n", + page_count, pinned); + return npages - page_count; + } + cur_base += (uint64_t)pinned * PAGE_SIZE; + page_count -= (uint64_t)pinned; + sg_list_start = udma_sg_set_page(sg_list_start, pinned, page_list); + } + return npages; +} + +static uint64_t udma_k_pin_pages(struct udma_dev *dev, struct ubcore_umem *umem, + uint64_t npages) +{ + struct scatterlist *sg_cur = umem->sg_head.sgl; + uint64_t cur_base = umem->va & PAGE_MASK; + struct page *pg; + uint64_t pinned; + + for (pinned = 0; pinned < npages; pinned++) { + if (is_vmalloc_addr((void *)(uintptr_t)cur_base)) + pg = vmalloc_to_page((void *)(uintptr_t)cur_base); + else + pg = kmap_to_page((void *)(uintptr_t)cur_base); + if (!pg) { + dev_err(dev->dev, "vmalloc or kmap to page failed.\n"); + break; + } + get_page(pg); + + cur_base += PAGE_SIZE; + + sg_set_page(sg_cur, pg, PAGE_SIZE, 0); + sg_cur = sg_next(sg_cur); + } + + return pinned; +} + +static void udma_unpin_pages(struct ubcore_umem *umem, uint64_t nents, bool is_kernel) +{ + struct scatterlist *sg; + uint32_t i; + + for_each_sg(umem->sg_head.sgl, sg, nents, i) { + struct page *page = sg_page(sg); + + if (is_kernel) + put_page(page); + else + unpin_user_page(page); + } +} + +static struct ubcore_umem *udma_get_target_umem(struct udma_umem_param *param, + struct page **page_list) +{ + struct udma_dev *udma_dev = to_udma_dev(param->ub_dev); + struct ubcore_umem *umem; + uint32_t gup_flags; + uint64_t npages; + uint64_t pinned; + int ret = 0; + + umem = kzalloc(sizeof(*umem), GFP_KERNEL); + if (umem == 0) { + ret = -ENOMEM; + goto out; + } + + udma_fill_umem(umem, param); + + npages = udma_cal_npages(umem->va, umem->length); + if (npages == 0 || npages > UINT_MAX) { + dev_err(udma_dev->dev, + "Invalid npages %llu in getting target umem process.\n", npages); + ret = -EINVAL; + goto umem_kfree; + } + + ret = sg_alloc_table(&umem->sg_head, (unsigned int)npages, GFP_KERNEL); + if (ret) + goto umem_kfree; + + if (param->is_kernel) { + pinned = udma_k_pin_pages(udma_dev, umem, npages); + } else { + gup_flags = (param->flag.bs.writable == 1) ? FOLL_WRITE : 0; + pinned = udma_pin_all_pages(udma_dev, umem, npages, gup_flags, page_list); + } + if (pinned != npages) { + ret = -ENOMEM; + goto umem_release; + } + + goto out; + +umem_release: + udma_unpin_pages(umem, pinned, param->is_kernel); + sg_free_table(&umem->sg_head); +umem_kfree: + kfree(umem); +out: + return ret != 0 ? ERR_PTR(ret) : umem; +} + +struct ubcore_umem *udma_umem_get(struct udma_umem_param *param) +{ + struct ubcore_umem *umem; + struct page **page_list; + int ret; + + ret = udma_verify_input(param); + if (ret < 0) + return ERR_PTR(ret); + + page_list = (struct page **) __get_free_page(GFP_KERNEL); + if (page_list == 0) + return ERR_PTR(-ENOMEM); + + umem = udma_get_target_umem(param, page_list); + + free_page((uintptr_t)page_list); + + return umem; +} + +int pin_queue_addr(struct udma_dev *dev, uint64_t addr, uint32_t len, + struct udma_buf *buf) +{ + struct ubcore_device *ub_dev = &dev->ub_dev; + struct udma_umem_param param; + + param.ub_dev = ub_dev; + param.va = addr; + param.len = len; + param.flag.bs.writable = 1; + param.flag.bs.non_pin = 0; + param.is_kernel = false; + + buf->umem = udma_umem_get(¶m); + if (IS_ERR(buf->umem)) { + dev_err(dev->dev, "failed to pin queue addr.\n"); + return PTR_ERR(buf->umem); + } + + buf->addr = addr; + + return 0; +} + +void unpin_queue_addr(struct ubcore_umem *umem) +{ + udma_umem_release(umem, false); +} + +void udma_umem_release(struct ubcore_umem *umem, bool is_kernel) +{ + if (IS_ERR_OR_NULL(umem)) + return; + + udma_unpin_pages(umem, umem->sg_head.nents, is_kernel); + sg_free_table(&umem->sg_head); + kfree(umem); +} + +int udma_id_alloc_auto_grow(struct udma_dev *udma_dev, struct udma_ida *ida_table, + uint32_t *idx) +{ + int id; + + spin_lock(&ida_table->lock); + id = ida_alloc_range(&ida_table->ida, ida_table->next, ida_table->max, + GFP_ATOMIC); + if (id < 0) { + id = ida_alloc_range(&ida_table->ida, ida_table->min, ida_table->max, + GFP_ATOMIC); + if (id < 0) { + dev_err(udma_dev->dev, "failed to alloc id, ret = %d.\n", id); + spin_unlock(&ida_table->lock); + return id; + } + } + + ida_table->next = (uint32_t)id + 1 > ida_table->max ? + ida_table->min : (uint32_t)id + 1; + + *idx = (uint32_t)id; + spin_unlock(&ida_table->lock); + + return 0; +} + +int udma_id_alloc(struct udma_dev *udma_dev, struct udma_ida *ida_table, + uint32_t *idx) +{ + int id; + + id = ida_alloc_range(&ida_table->ida, ida_table->min, ida_table->max, + GFP_ATOMIC); + if (id < 0) { + dev_err(udma_dev->dev, "failed to alloc id, ret = %d.\n", id); + return id; + } + + *idx = (uint32_t)id; + + return 0; +} + +int udma_specify_adv_id(struct udma_dev *udma_dev, struct udma_group_bitmap *bitmap_table, + uint32_t user_id) +{ + uint32_t id_bit_idx = (user_id - bitmap_table->min); + uint32_t bit_idx = id_bit_idx % NUM_JETTY_PER_GROUP; + uint32_t block = id_bit_idx / NUM_JETTY_PER_GROUP; + uint32_t *bit = bitmap_table->bit; + + spin_lock(&bitmap_table->lock); + if ((bit[block] & (1U << bit_idx)) == 0) { + dev_err(udma_dev->dev, + "user specify id %u been used.\n", user_id); + spin_unlock(&bitmap_table->lock); + return -ENOMEM; + } + + bit[block] &= ~(1U << bit_idx); + spin_unlock(&bitmap_table->lock); + + return 0; +} + +static int udma_adv_jetty_id_alloc(struct udma_dev *udma_dev, uint32_t *bit, + uint32_t next_bit, uint32_t start_idx, + struct udma_group_bitmap *bitmap_table) +{ + uint32_t bit_idx; + + bit_idx = find_next_bit((unsigned long *)bit, NUM_JETTY_PER_GROUP, next_bit); + if (bit_idx == NUM_JETTY_PER_GROUP) { + dev_err(udma_dev->dev, + "jid is larger than n_bits, bit=0x%x.\n", *bit); + return -ENOMEM; + } + + start_idx += bit_idx; + if (start_idx >= bitmap_table->n_bits) { + dev_err(udma_dev->dev, + "jid is larger than n_bits, id=%u, n_bits=%u.\n", + start_idx, bitmap_table->n_bits); + return -ENOMEM; + } + + *bit &= ~(1U << bit_idx); + return start_idx + bitmap_table->min; +} + +int udma_adv_id_alloc(struct udma_dev *udma_dev, struct udma_group_bitmap *bitmap_table, + uint32_t *start_idx, bool is_grp, uint32_t next) +{ + uint32_t next_block = (next - bitmap_table->min) / NUM_JETTY_PER_GROUP; + uint32_t next_bit = (next - bitmap_table->min) % NUM_JETTY_PER_GROUP; + uint32_t bitmap_cnt = bitmap_table->bitmap_cnt; + uint32_t *bit = bitmap_table->bit; + uint32_t i; + int ret; + + spin_lock(&bitmap_table->lock); + + for (i = next_block; + (i < bitmap_cnt && bit[i] == 0) || + (i == next_block && + ((bit[i] & GENMASK(NUM_JETTY_PER_GROUP - 1, next_bit)) == 0)); ++i) + ; + + if (i == bitmap_cnt) { + dev_err(udma_dev->dev, + "all bitmaps have been used, bitmap_cnt = %u.\n", + bitmap_cnt); + spin_unlock(&bitmap_table->lock); + return -ENOMEM; + } + + if (!is_grp) { + ret = udma_adv_jetty_id_alloc(udma_dev, bit + i, next_bit, + i * NUM_JETTY_PER_GROUP, bitmap_table); + + spin_unlock(&bitmap_table->lock); + if (ret >= 0) { + *start_idx = (uint32_t)ret; + return 0; + } + return ret; + } + + for (; i < bitmap_cnt && ~bit[i] != 0; ++i) + ; + if (i == bitmap_cnt || + (i + 1) * NUM_JETTY_PER_GROUP > bitmap_table->n_bits) { + dev_err(udma_dev->dev, + "no completely bitmap for Jetty group.\n"); + spin_unlock(&bitmap_table->lock); + return -ENOMEM; + } + + bit[i] = 0; + *start_idx = i * NUM_JETTY_PER_GROUP + bitmap_table->min; + + spin_unlock(&bitmap_table->lock); + + return 0; +} + +void udma_adv_id_free(struct udma_group_bitmap *bitmap_table, uint32_t start_idx, + bool is_grp) +{ + uint32_t bitmap_num; + uint32_t bit_num; + + start_idx -= bitmap_table->min; + spin_lock(&bitmap_table->lock); + + bitmap_num = start_idx / NUM_JETTY_PER_GROUP; + if (bitmap_num >= bitmap_table->bitmap_cnt) { + spin_unlock(&bitmap_table->lock); + return; + } + + if (is_grp) { + bitmap_table->bit[bitmap_num] = ~0U; + } else { + bit_num = start_idx % NUM_JETTY_PER_GROUP; + bitmap_table->bit[bitmap_num] |= (1U << bit_num); + } + + spin_unlock(&bitmap_table->lock); +} + static void udma_init_ida_table(struct udma_ida *ida_table, uint32_t max, uint32_t min) { ida_init(&ida_table->ida); @@ -77,6 +470,68 @@ void udma_destroy_eid_table(struct udma_dev *udma_dev) mutex_destroy(&udma_dev->eid_mutex); } +static struct ubcore_umem *udma_pin_k_addr(struct ubcore_device *ub_dev, uint64_t va, + uint64_t len) +{ + struct udma_umem_param param; + + param.ub_dev = ub_dev; + param.va = va; + param.len = len; + param.flag.bs.writable = true; + param.flag.bs.non_pin = 0; + param.is_kernel = true; + + return udma_umem_get(¶m); +} + +static void udma_unpin_k_addr(struct ubcore_umem *umem) +{ + udma_umem_release(umem, true); +} + +int udma_k_alloc_buf(struct udma_dev *udma_dev, size_t memory_size, + struct udma_buf *buf) +{ + size_t aligned_memory_size; + int ret; + + aligned_memory_size = memory_size + UDMA_HW_PAGE_SIZE - 1; + buf->aligned_va = vmalloc(aligned_memory_size); + if (!buf->aligned_va) { + dev_err(udma_dev->dev, + "failed to vmalloc kernel buf, size = %lu.", + aligned_memory_size); + return -ENOMEM; + } + + memset(buf->aligned_va, 0, aligned_memory_size); + buf->umem = udma_pin_k_addr(&udma_dev->ub_dev, (uint64_t)buf->aligned_va, + aligned_memory_size); + if (IS_ERR(buf->umem)) { + ret = PTR_ERR(buf->umem); + vfree(buf->aligned_va); + dev_err(udma_dev->dev, "pin kernel buf failed, ret = %d.\n", ret); + return ret; + } + + buf->addr = ((uint64_t)buf->aligned_va + UDMA_HW_PAGE_SIZE - 1) & + ~(UDMA_HW_PAGE_SIZE - 1); + buf->kva = (void *)(uintptr_t)buf->addr; + + return 0; +} + +void udma_k_free_buf(struct udma_dev *udma_dev, size_t memory_size, + struct udma_buf *buf) +{ + udma_unpin_k_addr(buf->umem); + vfree(buf->aligned_va); + buf->aligned_va = NULL; + buf->kva = NULL; + buf->addr = 0; +} + void *udma_alloc_iova(struct udma_dev *udma_dev, size_t memory_size, dma_addr_t *addr) { struct iova_slot *slot; diff --git a/drivers/ub/urma/hw/udma/udma_common.h b/drivers/ub/urma/hw/udma/udma_common.h index 4f843356c755..f3f32862db0a 100644 --- a/drivers/ub/urma/hw/udma/udma_common.h +++ b/drivers/ub/urma/hw/udma/udma_common.h @@ -8,6 +8,37 @@ #include #include "udma_dev.h" +struct udma_jetty_queue { + struct udma_buf buf; + void *kva_curr; + uint32_t id; + void __iomem *db_addr; + void __iomem *dwqe_addr; + uint32_t pi; + uint32_t ci; + uintptr_t *wrid; + spinlock_t lock; + uint32_t max_inline_size; + uint32_t max_sge_num; + uint32_t tid; + bool flush_flag; + uint32_t old_entry_idx; + enum ubcore_transport_mode trans_mode; + struct ubcore_tjetty *rc_tjetty; + bool is_jetty; + uint32_t sqe_bb_cnt; + uint32_t lock_free; /* Support kernel mode lock-free mode */ + uint32_t ta_timeout; /* ms */ + enum ubcore_jetty_state state; + bool non_pin; + struct udma_jetty_grp *jetty_grp; + enum udma_jetty_type jetty_type; +}; + +int pin_queue_addr(struct udma_dev *dev, uint64_t addr, + uint32_t len, struct udma_buf *buf); +void unpin_queue_addr(struct ubcore_umem *umem); + struct udma_umem_param { struct ubcore_device *ub_dev; uint64_t va; @@ -16,13 +47,21 @@ struct udma_umem_param { bool is_kernel; }; +struct ubcore_umem *udma_umem_get(struct udma_umem_param *param); +void udma_umem_release(struct ubcore_umem *umem, bool is_kernel); void udma_init_udma_table(struct udma_table *table, uint32_t max, uint32_t min); void udma_init_udma_table_mutex(struct xarray *table, struct mutex *udma_mutex); void udma_destroy_udma_table(struct udma_dev *dev, struct udma_table *table, const char *table_name); void udma_destroy_eid_table(struct udma_dev *udma_dev); +int udma_k_alloc_buf(struct udma_dev *udma_dev, size_t memory_size, struct udma_buf *buf); +void udma_k_free_buf(struct udma_dev *udma_dev, size_t memory_size, struct udma_buf *buf); void *udma_alloc_iova(struct udma_dev *udma_dev, size_t memory_size, dma_addr_t *addr); void udma_free_iova(struct udma_dev *udma_dev, size_t memory_size, void *kva_or_slot, dma_addr_t addr); +static inline uint64_t udma_cal_npages(uint64_t va, uint64_t len) +{ + return (ALIGN(va + len, PAGE_SIZE) - ALIGN_DOWN(va, PAGE_SIZE)) / PAGE_SIZE; +} #endif /* __UDMA_COMM_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_ctl.h b/drivers/ub/urma/hw/udma/udma_ctl.h new file mode 100644 index 000000000000..da1d082aeec4 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_ctl.h @@ -0,0 +1,213 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef _UB_UMDK_URMA_UDMA_UDMA_CTL_H_ +#define _UB_UMDK_URMA_UDMA_UDMA_CTL_H_ + +#include + +#define UDMA_BUS_INSTANCE_SEID_SIZE 4 +#define UDMA_EID_PAIRS_COUNT 8 + +union udma_k_jfs_flag { + struct { + uint32_t sq_cstm : 1; + uint32_t db_cstm : 1; + uint32_t db_ctl_cstm : 1; + uint32_t reserved : 29; + } bs; + uint32_t value; +}; + +struct udma_que_cfg_ex { + uint32_t buff_size; + void *buff; +}; + +struct udma_jfs_cstm_cfg { + struct udma_que_cfg_ex sq; /* PA; should be converted by phys_to_virt. */ +}; + +struct udma_jfs_cfg_ex { + struct ubcore_jfs_cfg base_cfg; + struct ubcore_udata udata; + struct udma_jfs_cstm_cfg cstm_cfg; + ubcore_event_callback_t jfae_handler; +}; + +struct udma_jfc_cstm_cfg { + struct udma_que_cfg_ex cq; /* PA; should be using stars hw register addr. */ +}; + +struct udma_jfc_cfg_ex { + struct ubcore_jfc_cfg base_cfg; + struct ubcore_udata udata; + struct udma_jfc_cstm_cfg cstm_cfg; + ubcore_comp_callback_t jfce_handler; + ubcore_event_callback_t jfae_handler; +}; + +enum udma_jfc_type { + UDMA_NORMAL_JFC_TYPE, + UDMA_STARS_JFC_TYPE, + UDMA_CCU_JFC_TYPE, + UDMA_KERNEL_STARS_JFC_TYPE, + UDMA_JFC_TYPE_NUM, +}; + +struct udma_set_cqe_ex { + uint64_t addr; + uint32_t len; + enum udma_jfc_type jfc_type; +}; + +struct udma_ue_info_ex { + uint16_t ue_id; + uint32_t chip_id; + uint32_t die_id; + uint32_t offset_len; + resource_size_t db_base_addr; + resource_size_t dwqe_addr; + resource_size_t register_base_addr; +}; + +struct udma_tp_sport_in { + uint32_t tpn; +}; + +struct udma_tp_sport_out { + uint32_t data_udp_srcport; + uint32_t ack_udp_srcport; +}; + +struct udma_cqe_info_in { + enum ubcore_cr_status status; + uint8_t s_r; +}; + +enum udma_cqe_aux_info_type { + TPP2TQEM_WR_CNT, + DEVICE_RAS_STATUS_2, + RXDMA_WR_PAYL_AXI_ERR, + RXDMA_HEAD_SPLIT_ERR_FLAG0, + RXDMA_HEAD_SPLIT_ERR_FLAG1, + RXDMA_HEAD_SPLIT_ERR_FLAG2, + RXDMA_HEAD_SPLIT_ERR_FLAG3, + TP_RCP_INNER_ALM_FOR_CQE, + TWP_AE_DFX_FOR_CQE, + PA_OUT_PKT_ERR_CNT, + TP_DAM_AXI_ALARM, + TP_DAM_VFT_BT_ALARM, + TP_EUM_AXI_ALARM, + TP_EUM_VFT_BT_ALARM, + TP_TPMM_AXI_ALARM, + TP_TPMM_VFT_BT_ALARM, + TP_TPGCM_AXI_ALARM, + TP_TPGCM_VFT_BT_ALARM, + TWP_ALM, + TP_RWP_INNER_ALM_FOR_CQE, + TWP_DFX21, + LQC_TA_RNR_TANACK_CNT, + FVT, + RQMT0, + RQMT1, + RQMT2, + RQMT3, + RQMT4, + RQMT5, + RQMT6, + RQMT7, + RQMT8, + RQMT9, + RQMT10, + RQMT11, + RQMT12, + RQMT13, + RQMT14, + RQMT15, + PROC_ERROR_ALM, + LQC_TA_TIMEOUT_TAACK_CNT, + TP_RRP_ERR_FLG_0_FOR_CQE, + MAX_CQE_AUX_INFO_TYPE_NUM +}; + +struct udma_cqe_aux_info_out { + enum udma_cqe_aux_info_type *aux_info_type; + uint32_t *aux_info_value; + uint32_t aux_info_num; +}; + +struct udma_ae_info_in { + uint32_t event_type; +}; + +enum udma_ae_aux_info_type { + TP_RRP_FLUSH_TIMER_PKT_CNT, + TPP_DFX5, + TWP_AE_DFX_FOR_AE, + TP_RRP_ERR_FLG_0_FOR_AE, + TP_RRP_ERR_FLG_1, + TP_RWP_INNER_ALM_FOR_AE, + TP_RCP_INNER_ALM_FOR_AE, + LQC_TA_TQEP_WQE_ERR, + LQC_TA_CQM_CQE_INNER_ALARM, + MAX_AE_AUX_INFO_TYPE_NUM +}; + +struct udma_ae_aux_info_out { + enum udma_ae_aux_info_type *aux_info_type; + uint32_t *aux_info_value; + uint32_t aux_info_num; +}; + +enum udma_user_ctl_opcode { + UDMA_USER_CTL_CREATE_JFS_EX, + UDMA_USER_CTL_DELETE_JFS_EX, + UDMA_USER_CTL_CREATE_JFC_EX, + UDMA_USER_CTL_DELETE_JFC_EX, + UDMA_USER_CTL_SET_CQE_ADDR, + UDMA_USER_CTL_QUERY_UE_INFO, + UDMA_USER_CTL_GET_DEV_RES_RATIO, + UDMA_USER_CTL_NPU_REGISTER_INFO_CB, + UDMA_USER_CTL_NPU_UNREGISTER_INFO_CB, + UDMA_USER_CTL_QUERY_TP_SPORT, + UDMA_USER_CTL_QUERY_CQE_AUX_INFO, + UDMA_USER_CTL_QUERY_AE_AUX_INFO, + UDMA_USER_CTL_QUERY_UBMEM_INFO, + UDMA_USER_CTL_QUERY_PAIR_DEVNUM, + UDMA_USER_CTL_MAX, +}; + +struct udma_ctrlq_event_nb { + uint8_t opcode; + int (*crq_handler)(struct ubcore_device *dev, void *data, uint16_t len); +}; + +struct udma_dev_pair_info { + uint32_t peer_dev_id; + uint32_t slot_id; + uint32_t pair_num; + struct { + uint32_t local_eid[UDMA_BUS_INSTANCE_SEID_SIZE]; + uint32_t remote_eid[UDMA_BUS_INSTANCE_SEID_SIZE]; + uint32_t flag : 16; + uint32_t hop : 4; + uint32_t rsv : 12; + } eid_pairs[UDMA_EID_PAIRS_COUNT]; +}; + +static inline bool udma_check_base_param(uint64_t addr, uint32_t in_len, uint32_t len) +{ + return (addr == 0 || in_len != len); +} + +typedef int (*udma_user_ctl_ops)(struct ubcore_device *dev, struct ubcore_ucontext *uctx, + struct ubcore_user_ctl_in *in, struct ubcore_user_ctl_out *out); + +int udma_user_ctl(struct ubcore_device *dev, struct ubcore_user_ctl *k_user_ctl); +int udma_query_cqe_aux_info(struct ubcore_device *dev, struct ubcore_ucontext *uctx, + struct ubcore_user_ctl_in *in, struct ubcore_user_ctl_out *out); +int udma_query_ae_aux_info(struct ubcore_device *dev, struct ubcore_ucontext *uctx, + struct ubcore_user_ctl_in *in, struct ubcore_user_ctl_out *out); + +#endif /* _UB_UMDK_URMA_UDMA_UDMA_CTL_H_ */ diff --git a/drivers/ub/urma/hw/udma/udma_ctx.c b/drivers/ub/urma/hw/udma/udma_ctx.c new file mode 100644 index 000000000000..985abb19929a --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_ctx.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt + +#include +#include +#include "udma_jfs.h" +#include "udma_jetty.h" +#include "udma_ctrlq_tp.h" +#include "udma_ctx.h" + +static int udma_init_ctx_resp(struct udma_dev *dev, struct ubcore_udrv_priv *udrv_data) +{ + struct udma_create_ctx_resp resp; + unsigned long byte; + + if (!udrv_data->out_addr || + udrv_data->out_len < sizeof(resp)) { + dev_err(dev->dev, + "Invalid ctx resp out: len %d or addr is invalid.\n", + udrv_data->out_len); + return -EINVAL; + } + + resp.cqe_size = dev->caps.cqe_size; + resp.dwqe_enable = !!(dev->caps.feature & UDMA_CAP_FEATURE_DIRECT_WQE); + resp.reduce_enable = !!(dev->caps.feature & UDMA_CAP_FEATURE_REDUCE); + resp.ue_id = dev->ue_id; + resp.chip_id = dev->chip_id; + resp.die_id = dev->die_id; + resp.dump_aux_info = dump_aux_info; + resp.jfr_sge = dev->caps.jfr_sge; + + byte = copy_to_user((void *)(uintptr_t)udrv_data->out_addr, &resp, + (uint32_t)sizeof(resp)); + if (byte) { + dev_err(dev->dev, + "copy ctx resp to user failed, byte = %lu.\n", byte); + return -EFAULT; + } + + return 0; +} + +struct ubcore_ucontext *udma_alloc_ucontext(struct ubcore_device *ub_dev, + uint32_t eid_index, + struct ubcore_udrv_priv *udrv_data) +{ + struct udma_dev *dev = to_udma_dev(ub_dev); + struct udma_context *ctx; + int ret; + + ctx = kzalloc(sizeof(struct udma_context), GFP_KERNEL); + if (ctx == NULL) + return NULL; + + ctx->sva = ummu_sva_bind_device(dev->dev, current->mm, NULL); + if (!ctx->sva) { + dev_err(dev->dev, "SVA failed to bind device.\n"); + goto err_free_ctx; + } + + ret = ummu_get_tid(dev->dev, ctx->sva, &ctx->tid); + if (ret) { + dev_err(dev->dev, "Failed to get tid.\n"); + goto err_unbind_dev; + } + + ctx->dev = dev; + INIT_LIST_HEAD(&ctx->pgdir_list); + mutex_init(&ctx->pgdir_mutex); + + ret = udma_init_ctx_resp(dev, udrv_data); + if (ret) { + dev_err(dev->dev, "Init ctx resp failed.\n"); + goto err_init_ctx_resp; + } + + return &ctx->base; + +err_init_ctx_resp: + mutex_destroy(&ctx->pgdir_mutex); +err_unbind_dev: + ummu_sva_unbind_device(ctx->sva); +err_free_ctx: + kfree(ctx); + return NULL; +} + +int udma_free_ucontext(struct ubcore_ucontext *ucontext) +{ + struct udma_dev *udma_dev = to_udma_dev(ucontext->ub_dev); + struct udma_context *ctx; + int ret; + + ctx = to_udma_context(ucontext); + + ret = ummu_core_invalidate_cfg_table(ctx->tid); + if (ret) + dev_err(udma_dev->dev, "invalidate cfg_table failed, ret=%d.\n", ret); + + mutex_destroy(&ctx->pgdir_mutex); + ummu_sva_unbind_device(ctx->sva); + + kfree(ctx); + + return 0; +} + +int udma_mmap(struct ubcore_ucontext *uctx, struct vm_area_struct *vma) +{ +#define JFC_DB_UNMAP_BOUND 1 + struct udma_dev *udma_dev = to_udma_dev(uctx->ub_dev); + struct ubcore_ucontext *jetty_uctx; + struct udma_jetty_queue *sq; + resource_size_t db_addr; + uint64_t address; + uint64_t j_id; + uint32_t cmd; + + if (((vma->vm_end - vma->vm_start) % PAGE_SIZE) != 0) { + dev_err(udma_dev->dev, + "mmap failed, unexpected vm area size.\n"); + return -EINVAL; + } + + db_addr = udma_dev->db_base; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + cmd = get_mmap_cmd(vma); + switch (cmd) { + case UDMA_MMAP_JFC_PAGE: + if (io_remap_pfn_range(vma, vma->vm_start, + jfc_arm_mode > JFC_DB_UNMAP_BOUND ? + (uint64_t)db_addr >> PAGE_SHIFT : + page_to_pfn(udma_dev->db_page), + PAGE_SIZE, vma->vm_page_prot)) + return -EAGAIN; + break; + case UDMA_MMAP_JETTY_DSQE: + j_id = get_mmap_idx(vma); + xa_lock(&udma_dev->jetty_table.xa); + sq = xa_load(&udma_dev->jetty_table.xa, j_id); + if (!sq) { + dev_err(udma_dev->dev, + "mmap failed, j_id: %llu not exist\n", j_id); + xa_unlock(&udma_dev->jetty_table.xa); + return -EINVAL; + } + + if (sq->is_jetty) + jetty_uctx = to_udma_jetty_from_queue(sq)->ubcore_jetty.uctx; + else + jetty_uctx = to_udma_jfs_from_queue(sq)->ubcore_jfs.uctx; + + if (jetty_uctx != uctx) { + dev_err(udma_dev->dev, + "mmap failed, j_id: %llu, uctx invalid\n", j_id); + xa_unlock(&udma_dev->jetty_table.xa); + return -EINVAL; + } + xa_unlock(&udma_dev->jetty_table.xa); + + address = (uint64_t)db_addr + JETTY_DSQE_OFFSET + j_id * UDMA_HW_PAGE_SIZE; + + if (io_remap_pfn_range(vma, vma->vm_start, address >> PAGE_SHIFT, + PAGE_SIZE, vma->vm_page_prot)) + return -EAGAIN; + break; + default: + dev_err(udma_dev->dev, + "mmap failed, cmd(%u) not support\n", cmd); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/ub/urma/hw/udma/udma_ctx.h b/drivers/ub/urma/hw/udma/udma_ctx.h new file mode 100644 index 000000000000..a93aab94c1e9 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_ctx.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_CTX_H__ +#define __UDMA_CTX_H__ + +#include +#include +#include "udma_dev.h" + +struct udma_context { + struct ubcore_ucontext base; + struct udma_dev *dev; + uint32_t uasid; + struct list_head pgdir_list; + struct mutex pgdir_mutex; + struct iommu_sva *sva; + uint32_t tid; +}; + +static inline struct udma_context *to_udma_context(struct ubcore_ucontext *uctx) +{ + return container_of(uctx, struct udma_context, base); +} + +static inline uint64_t get_mmap_idx(struct vm_area_struct *vma) +{ + return (vma->vm_pgoff >> MAP_INDEX_SHIFT) & MAP_INDEX_MASK; +} + +static inline int get_mmap_cmd(struct vm_area_struct *vma) +{ + return (vma->vm_pgoff & MAP_COMMAND_MASK); +} + +struct ubcore_ucontext *udma_alloc_ucontext(struct ubcore_device *ub_dev, + uint32_t eid_index, + struct ubcore_udrv_priv *udrv_data); +int udma_free_ucontext(struct ubcore_ucontext *ucontext); +int udma_mmap(struct ubcore_ucontext *uctx, struct vm_area_struct *vma); + +#endif /* __UDMA_CTX_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_db.c b/drivers/ub/urma/hw/udma/udma_db.c new file mode 100644 index 000000000000..ea7b5d98ee6b --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_db.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt + +#include +#include +#include "udma_common.h" +#include "udma_db.h" + +int udma_pin_sw_db(struct udma_context *ctx, struct udma_sw_db *db) +{ + uint64_t page_addr = db->db_addr & PAGE_MASK; + struct udma_sw_db_page *page; + struct udma_umem_param param; + uint32_t offset = 0; + int ret = 0; + + param.ub_dev = &ctx->dev->ub_dev; + param.va = page_addr; + param.len = PAGE_SIZE; + param.flag.bs.writable = 1; + param.flag.bs.non_pin = 0; + param.is_kernel = false; + offset = db->db_addr - page_addr; + + mutex_lock(&ctx->pgdir_mutex); + + list_for_each_entry(page, &ctx->pgdir_list, list) { + if (page->user_virt == page_addr) + goto found; + } + + page = kmalloc(sizeof(*page), GFP_KERNEL); + if (!page) { + ret = -ENOMEM; + goto out; + } + + refcount_set(&page->refcount, 1); + page->user_virt = page_addr; + page->umem = udma_umem_get(¶m); + if (IS_ERR(page->umem)) { + ret = PTR_ERR(page->umem); + dev_err(ctx->dev->dev, "Failed to get umem, ret: %d.\n", ret); + kfree(page); + goto out; + } + + list_add(&page->list, &ctx->pgdir_list); + db->page = page; + db->virt_addr = (char *)sg_virt(page->umem->sg_head.sgl) + offset; + mutex_unlock(&ctx->pgdir_mutex); + return 0; +found: + db->page = page; + db->virt_addr = (char *)sg_virt(page->umem->sg_head.sgl) + offset; + refcount_inc(&page->refcount); +out: + mutex_unlock(&ctx->pgdir_mutex); + return ret; +} + +void udma_unpin_sw_db(struct udma_context *ctx, struct udma_sw_db *db) +{ + mutex_lock(&ctx->pgdir_mutex); + + if (refcount_dec_and_test(&db->page->refcount)) { + list_del(&db->page->list); + udma_umem_release(db->page->umem, false); + kfree(db->page); + } + + mutex_unlock(&ctx->pgdir_mutex); +} + +static int udma_alloc_db_from_page(struct udma_k_sw_db_page *page, + struct udma_sw_db *db, enum udma_db_type type) +{ + uint32_t index; + + index = find_first_bit(page->bitmap, page->num_db); + if (index >= page->num_db) + return -ENOMEM; + + clear_bit(index, page->bitmap); + + db->index = index; + db->kpage = page; + db->type = type; + db->db_addr = page->db_buf.addr + db->index * UDMA_DB_SIZE; + db->db_record = page->db_buf.kva + db->index * UDMA_DB_SIZE; + *db->db_record = 0; + + return 0; +} + +static struct udma_k_sw_db_page *udma_alloc_db_page(struct udma_dev *dev, + enum udma_db_type type) +{ + struct udma_k_sw_db_page *page; + int ret; + + page = kzalloc(sizeof(*page), GFP_KERNEL); + if (!page) + return NULL; + + page->num_db = PAGE_SIZE / UDMA_DB_SIZE; + + page->bitmap = bitmap_alloc(page->num_db, GFP_KERNEL); + if (!page->bitmap) { + dev_err(dev->dev, "Failed alloc db bitmap, db type is %u.\n", type); + goto err_bitmap; + } + + bitmap_fill(page->bitmap, page->num_db); + + ret = udma_k_alloc_buf(dev, PAGE_SIZE, &page->db_buf); + if (ret) { + dev_err(dev->dev, "Failed alloc db page buf, ret is %d.\n", ret); + goto err_kva; + } + + return page; +err_kva: + bitmap_free(page->bitmap); +err_bitmap: + kfree(page); + return NULL; +} + +int udma_alloc_sw_db(struct udma_dev *dev, struct udma_sw_db *db, + enum udma_db_type type) +{ + struct udma_k_sw_db_page *page; + int ret = 0; + + mutex_lock(&dev->db_mutex); + + list_for_each_entry(page, &dev->db_list[type], list) + if (!udma_alloc_db_from_page(page, db, type)) + goto out; + + page = udma_alloc_db_page(dev, type); + if (!page) { + ret = -ENOMEM; + dev_err(dev->dev, "Failed alloc sw db page db_type = %u\n", type); + goto out; + } + + list_add(&page->list, &dev->db_list[type]); + + /* This should never fail */ + (void)udma_alloc_db_from_page(page, db, type); +out: + mutex_unlock(&dev->db_mutex); + + return ret; +} + +void udma_free_sw_db(struct udma_dev *dev, struct udma_sw_db *db) +{ + mutex_lock(&dev->db_mutex); + + set_bit(db->index, db->kpage->bitmap); + + if (bitmap_full(db->kpage->bitmap, db->kpage->num_db)) { + udma_k_free_buf(dev, PAGE_SIZE, &db->kpage->db_buf); + bitmap_free(db->kpage->bitmap); + list_del(&db->kpage->list); + kfree(db->kpage); + db->kpage = NULL; + } + + mutex_unlock(&dev->db_mutex); +} diff --git a/drivers/ub/urma/hw/udma/udma_db.h b/drivers/ub/urma/hw/udma/udma_db.h new file mode 100644 index 000000000000..0fe018304149 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_db.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_DB_H__ +#define __UDMA_DB_H__ + +#include "udma_ctx.h" +#include "udma_dev.h" + +int udma_pin_sw_db(struct udma_context *ctx, struct udma_sw_db *db); +void udma_unpin_sw_db(struct udma_context *ctx, struct udma_sw_db *db); +int udma_alloc_sw_db(struct udma_dev *dev, struct udma_sw_db *db, + enum udma_db_type type); +void udma_free_sw_db(struct udma_dev *dev, struct udma_sw_db *db); + +#endif /* __UDMA_DB_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_def.h b/drivers/ub/urma/hw/udma/udma_def.h index 14d747c3fb8f..c45c69cd0271 100644 --- a/drivers/ub/urma/hw/udma/udma_def.h +++ b/drivers/ub/urma/hw/udma/udma_def.h @@ -69,6 +69,13 @@ struct udma_caps { struct udma_tbl seid; }; +struct udma_sw_db_page { + struct list_head list; + struct ubcore_umem *umem; + uint64_t user_virt; + refcount_t refcount; +}; + struct udma_buf { dma_addr_t addr; union { @@ -85,6 +92,37 @@ struct udma_buf { struct mutex id_table_mutex; }; +struct udma_k_sw_db_page { + struct list_head list; + uint32_t num_db; + unsigned long *bitmap; + struct udma_buf db_buf; +}; + +struct udma_sw_db { + struct udma_sw_db_page *page; + struct udma_k_sw_db_page *kpage; + uint32_t index; + uint32_t type; + uint64_t db_addr; + uint32_t *db_record; + void *virt_addr; +}; + +struct udma_req_msg { + uint8_t dst_ue_idx; + uint8_t resp_code; + uint16_t rsv; + struct ubcore_req req; +}; + +struct udma_resp_msg { + uint8_t dst_ue_idx; + uint8_t resp_code; + uint16_t rsv; + struct ubcore_resp resp; +}; + enum num_elem_in_grp { NUM_TP_PER_GROUP = 16, NUM_JETTY_PER_GROUP = 32, diff --git a/drivers/ub/urma/hw/udma/udma_dev.h b/drivers/ub/urma/hw/udma/udma_dev.h index 941dd2a0540e..a4df1f114d23 100644 --- a/drivers/ub/urma/hw/udma/udma_dev.h +++ b/drivers/ub/urma/hw/udma/udma_dev.h @@ -8,6 +8,11 @@ #include #include #include "udma_def.h" +#include +#include + +extern uint32_t jfc_arm_mode; +extern bool dump_aux_info; #define UBCORE_MAX_DEV_NAME 64 @@ -15,6 +20,8 @@ #define MAX_WQEBB_IN_SQE 4 +#define JETTY_DSQE_OFFSET 0x1000 + #define UDMA_HW_PAGE_SHIFT 12 #define UDMA_HW_PAGE_SIZE (1 << UDMA_HW_PAGE_SHIFT) @@ -97,6 +104,8 @@ struct udma_dev { struct mutex eid_mutex; uint32_t tid; struct iommu_sva *ksva; + struct list_head db_list[UDMA_DB_TYPE_NUM]; + struct mutex db_mutex; uint32_t status; uint32_t ue_num; uint32_t ue_id; @@ -136,6 +145,16 @@ static inline void udma_id_free(struct udma_ida *ida_table, int idx) ida_free(&ida_table->ida, idx); } +int udma_id_alloc_auto_grow(struct udma_dev *udma_dev, struct udma_ida *ida_table, + uint32_t *idx); +int udma_id_alloc(struct udma_dev *udma_dev, struct udma_ida *ida_table, + uint32_t *idx); +int udma_adv_id_alloc(struct udma_dev *udma_dev, struct udma_group_bitmap *bitmap_table, + uint32_t *start_idx, bool is_grp, uint32_t next); +void udma_adv_id_free(struct udma_group_bitmap *bitmap_table, uint32_t start_idx, + bool is_grp); +int udma_specify_adv_id(struct udma_dev *udma_dev, struct udma_group_bitmap *bitmap_table, + uint32_t user_id); void udma_destroy_tables(struct udma_dev *udma_dev); int udma_init_tables(struct udma_dev *udma_dev); int udma_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id); diff --git a/drivers/ub/urma/hw/udma/udma_jetty.h b/drivers/ub/urma/hw/udma/udma_jetty.h new file mode 100644 index 000000000000..e213278bcca3 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_jetty.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_JETTY_H__ +#define __UDMA_JETTY_H__ + +#include "udma_common.h" + +struct udma_jetty { + struct ubcore_jetty ubcore_jetty; + struct udma_jfr *jfr; + struct udma_jetty_queue sq; + uint64_t jetty_addr; + refcount_t ae_refcount; + struct completion ae_comp; + bool pi_type; + bool ue_rx_closed; +}; + +static inline struct udma_jetty *to_udma_jetty(struct ubcore_jetty *jetty) +{ + return container_of(jetty, struct udma_jetty, ubcore_jetty); +} + +static inline struct udma_jetty *to_udma_jetty_from_queue(struct udma_jetty_queue *queue) +{ + return container_of(queue, struct udma_jetty, sq); +} + +#endif /* __UDMA_JETTY_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_jfs.h b/drivers/ub/urma/hw/udma/udma_jfs.h new file mode 100644 index 000000000000..39a7b5d1bfc4 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_jfs.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_JFS_H__ +#define __UDMA_JFS_H__ + +#include "udma_common.h" + +struct udma_jfs { + struct ubcore_jfs ubcore_jfs; + struct udma_jetty_queue sq; + uint64_t jfs_addr; + refcount_t ae_refcount; + struct completion ae_comp; + uint32_t mode; + bool pi_type; + bool ue_rx_closed; +}; + +static inline struct udma_jfs *to_udma_jfs(struct ubcore_jfs *jfs) +{ + return container_of(jfs, struct udma_jfs, ubcore_jfs); +} + +static inline struct udma_jfs *to_udma_jfs_from_queue(struct udma_jetty_queue *queue) +{ + return container_of(queue, struct udma_jfs, sq); +} + +#endif /* __UDMA_JFS_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 0224b6d248d0..77ade2c69f4a 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -18,12 +18,16 @@ #include #include "udma_dev.h" #include "udma_cmd.h" +#include "udma_ctx.h" #include "udma_rct.h" +#include "udma_tid.h" #include "udma_common.h" #include "udma_ctrlq_tp.h" bool is_rmmod; static DEFINE_MUTEX(udma_reset_mutex); +uint32_t jfc_arm_mode; +bool dump_aux_info; static const struct auxiliary_device_id udma_id_table[] = { { @@ -154,6 +158,11 @@ static struct ubcore_ops g_dev_ops = { .query_device_attr = udma_query_device_attr, .query_device_status = udma_query_device_status, .config_device = udma_config_device, + .alloc_ucontext = udma_alloc_ucontext, + .free_ucontext = udma_free_ucontext, + .mmap = udma_mmap, + .alloc_token_id = udma_alloc_tid, + .free_token_id = udma_free_tid, }; static void udma_uninit_group_table(struct udma_dev *dev, struct udma_group_table *table) @@ -532,6 +541,7 @@ static int udma_init_dev_param(struct udma_dev *udma_dev) struct auxiliary_device *adev = udma_dev->comdev.adev; struct ubase_resource_space *mem_base = ubase_get_mem_base(adev); int ret; + int i; udma_dev->dev = adev->dev.parent; udma_dev->db_base = mem_base->addr_unmapped; @@ -553,11 +563,16 @@ static int udma_init_dev_param(struct udma_dev *udma_dev) dev_set_drvdata(&adev->dev, udma_dev); + mutex_init(&udma_dev->db_mutex); + for (i = 0; i < UDMA_DB_TYPE_NUM; i++) + INIT_LIST_HEAD(&udma_dev->db_list[i]); + return 0; } static void udma_uninit_dev_param(struct udma_dev *udma_dev) { + mutex_destroy(&udma_dev->db_mutex); dev_set_drvdata(&udma_dev->comdev.adev->dev, NULL); udma_destroy_tables(udma_dev); } @@ -890,3 +905,11 @@ static void __exit udma_exit(void) module_init(udma_init); module_exit(udma_exit); MODULE_LICENSE("GPL"); + +module_param(jfc_arm_mode, uint, 0444); +MODULE_PARM_DESC(jfc_arm_mode, + "Set the ARM mode of the JFC, default: 0(0:Always ARM, other: NO ARM."); + +module_param(dump_aux_info, bool, 0644); +MODULE_PARM_DESC(dump_aux_info, + "Set whether dump aux info, default: false(false:not print, true:print)"); diff --git a/drivers/ub/urma/hw/udma/udma_tid.c b/drivers/ub/urma/hw/udma/udma_tid.c new file mode 100644 index 000000000000..c5b5b9037162 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_tid.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt + +#include +#include "udma_tid.h" + +static int udma_get_key_id_from_user(struct udma_dev *udma_dev, + struct ubcore_udata *udata, + struct udma_tid *udma_tid) +{ + unsigned long byte; + uint32_t tid; + + if (!udata->udrv_data || !udata->udrv_data->in_addr) { + dev_err(udma_dev->dev, "udrv_data or in_addr is null.\n"); + return -EINVAL; + } + + byte = copy_from_user(&tid, (void *)(uintptr_t)udata->udrv_data->in_addr, + min(udata->udrv_data->in_len, + (uint32_t)sizeof(tid))); + if (byte) { + dev_err(udma_dev->dev, "get user data failed, byte = %lu.\n", byte); + return -EFAULT; + } + + udma_tid->core_key_id.token_id = tid; + udma_tid->tid = tid >> UDMA_TID_SHIFT; + + return 0; +} + +static int udma_alloc_k_tid(struct udma_dev *udma_dev, + struct udma_tid *udma_tid) +{ + struct ummu_param param = {.mode = MAPT_MODE_TABLE}; + struct iommu_sva *ksva; + uint32_t tid; + int ret; + + ksva = ummu_ksva_bind_device(udma_dev->dev, ¶m); + if (!ksva) { + dev_err(udma_dev->dev, "ksva bind device failed.\n"); + return -ENOMEM; + } + + ret = ummu_get_tid(udma_dev->dev, ksva, &tid); + if (ret) { + dev_err(udma_dev->dev, "get tid from ummu failed, ret = %d.\n", ret); + goto err_get_tid; + } + + if (tid > UDMA_MAX_TID) { + dev_err(udma_dev->dev, "tid is overflow.\n"); + ret = -EINVAL; + goto err_get_tid; + } + + mutex_lock(&udma_dev->ksva_mutex); + ret = xa_err(__xa_store(&udma_dev->ksva_table, tid, ksva, GFP_KERNEL)); + mutex_unlock(&udma_dev->ksva_mutex); + if (ret) { + dev_err(udma_dev->dev, "save ksva failed, ret = %d.\n", ret); + goto err_get_tid; + } + + udma_tid->core_key_id.token_id = tid << UDMA_TID_SHIFT; + udma_tid->tid = tid; + udma_tid->kernel_mode = true; + + return ret; + +err_get_tid: + ummu_ksva_unbind_device(ksva); + + return ret; +} + +struct ubcore_token_id *udma_alloc_tid(struct ubcore_device *ub_dev, + union ubcore_token_id_flag flag, + struct ubcore_udata *udata) +{ + struct udma_dev *udma_dev = to_udma_dev(ub_dev); + struct udma_tid *udma_tid; + int ret; + + udma_tid = kzalloc(sizeof(*udma_tid), GFP_KERNEL); + if (!udma_tid) + return NULL; + + if (udata) { + ret = udma_get_key_id_from_user(udma_dev, udata, udma_tid); + if (ret) { + dev_err(udma_dev->dev, "get user key id failed, ret = %d.\n", ret); + goto err_get_key_id; + } + return &udma_tid->core_key_id; + } + + if (udma_alloc_k_tid(udma_dev, udma_tid)) + goto err_get_key_id; + + return &udma_tid->core_key_id; + +err_get_key_id: + kfree(udma_tid); + return NULL; +} + +int udma_free_tid(struct ubcore_token_id *token_id) +{ + struct udma_dev *udma_dev = to_udma_dev(token_id->ub_dev); + struct udma_tid *udma_tid = to_udma_tid(token_id); + struct iommu_sva *ksva; + int ret; + + ret = ummu_core_invalidate_cfg_table(udma_tid->tid); + if (ret) + dev_err(udma_dev->dev, "invalidate cfg_table failed, ret=%d.\n", ret); + + if (!udma_tid->kernel_mode) + goto out; + + mutex_lock(&udma_dev->ksva_mutex); + ksva = (struct iommu_sva *)xa_load(&udma_dev->ksva_table, udma_tid->tid); + if (!ksva) { + mutex_unlock(&udma_dev->ksva_mutex); + dev_warn(udma_dev->dev, + "unable to get ksva while free tid, token maybe is free.\n"); + goto out; + } + ummu_ksva_unbind_device(ksva); + __xa_erase(&udma_dev->ksva_table, udma_tid->tid); + mutex_unlock(&udma_dev->ksva_mutex); + +out: + kfree(udma_tid); + + return 0; +} diff --git a/drivers/ub/urma/hw/udma/udma_tid.h b/drivers/ub/urma/hw/udma/udma_tid.h new file mode 100644 index 000000000000..72bf436fc23f --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_tid.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_TID_H__ +#define __UDMA_TID_H__ + +#include "udma_dev.h" + +struct udma_tid { + struct ubcore_token_id core_key_id; + bool kernel_mode; + uint32_t tid; +}; + +static inline struct udma_tid *to_udma_tid(struct ubcore_token_id *token_id) +{ + return container_of(token_id, struct udma_tid, core_key_id); +} + +struct ubcore_token_id *udma_alloc_tid(struct ubcore_device *dev, + union ubcore_token_id_flag flag, + struct ubcore_udata *udata); +int udma_free_tid(struct ubcore_token_id *token_id); + +#endif /* __UDMA_TID_H__ */ diff --git a/include/uapi/ub/urma/udma/udma_abi.h b/include/uapi/ub/urma/udma/udma_abi.h new file mode 100644 index 000000000000..02440d162c8d --- /dev/null +++ b/include/uapi/ub/urma/udma/udma_abi.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef _UAPI_UB_UMDK_URMA_UDMA_UDMA_ABI_H_ +#define _UAPI_UB_UMDK_URMA_UDMA_UDMA_ABI_H_ + +#include + +#define MAP_COMMAND_MASK 0xff +#define MAP_INDEX_MASK 0xffffff +#define MAP_INDEX_SHIFT 8 + +#define UDMA_SEGMENT_ACCESS_GUARD (1UL << 5) + +#define UDMA_CQE_COALESCE_SHIFT 10 +#define UDMA_CQE_COALESCE_CNT_MAX (1 << UDMA_CQE_COALESCE_SHIFT) + +#define UDMA_CQE_PERIOD_0 0 +#define UDMA_CQE_PERIOD_4 4 +#define UDMA_CQE_PERIOD_16 16 +#define UDMA_CQE_PERIOD_64 64 +#define UDMA_CQE_PERIOD_256 256 +#define UDMA_CQE_PERIOD_1024 1024 +#define UDMA_CQE_PERIOD_4096 4096 +#define UDMA_CQE_PERIOD_16384 16384 + +#define UDMA_JFC_HW_DB_OFFSET 0x40 + +#define UDMA_DOORBELL_OFFSET 0x80 + +#define UDMA_JETTY_DSQE_OFFSET 0x1000 + +#define UDMA_DB_SIZE 64U + +#define UDMA_SRC_IDX_SHIFT 16 +#define UDMA_IMM_DATA_SHIFT 32 +#define UDMA_JFC_DB_VALID_OWNER_M 1 +#define UDMA_ADDR_SHIFT 32 + +#define UDMA_INTER_ERR 1 +#define UDMA_CQE_DEFAULT_SUBSTATUS 0 + +#define UDMA_MAX_GRANT_SIZE 0xFFFFFFFFF000 + +#define UDMA_TID_SHIFT 8U +#define UDMA_MAX_TID 0xFFFFFU + +enum udma_jetty_type { + UDMA_CACHE_LOCK_DWQE_JETTY_TYPE, + UDMA_CCU_JETTY_TYPE, + UDMA_NORMAL_JETTY_TYPE, + UDMA_URMA_NORMAL_JETTY_TYPE, + UDMA_JETTY_TYPE_MAX +}; + +enum cr_direct { + CR_SEND, + CR_RECV, +}; + +enum cr_jetty { + CR_IS_NOT_JETTY, + CR_IS_JETTY, +}; + +struct udma_create_jetty_ucmd { + __aligned_u64 buf_addr; + __u32 buf_len; + __u32 jfr_id; + __aligned_u64 db_addr; + __aligned_u64 idx_addr; + __u32 idx_len; + __u32 sqe_bb_cnt; + __aligned_u64 jetty_addr; + __u32 pi_type : 1; + __u32 non_pin : 1; + __u32 rsv : 30; + __u32 jetty_type; + __aligned_u64 jfr_sleep_buf; + __u32 jfs_id; + __u32 rsv1; +}; + +struct udma_create_jfc_ucmd { + __aligned_u64 buf_addr; + __u32 buf_len; + __u32 mode; /* 0: normal, 1: user stars, 2: kernel stars */ + __aligned_u64 db_addr; +}; + +struct udma_create_ctx_resp { + __u32 cqe_size : 8; + __u32 dwqe_enable : 1; + __u32 reduce_enable : 1; + __u32 dump_aux_info : 1; + __u32 rsv : 21; + __u32 ue_id; + __u32 chip_id; + __u32 die_id; + __u32 jfr_sge; + __u32 rsv1; +}; + +struct udma_create_jfr_resp { + __u32 jfr_caps; + __u32 rsv; +}; + +enum db_mmap_type { + UDMA_MMAP_JFC_PAGE, + UDMA_MMAP_JETTY_DSQE, +}; + +enum { + UDMA_CQ_DB, + UDMA_CQ_ARM_DB, +}; + +struct udma_jfc_db { + __u32 ci : 24; + __u32 notify : 1; + __u32 arm_sn : 2; + __u32 type : 1; + __u32 rsv1 : 4; + __u32 jfcn : 20; + __u32 rsv2 : 12; +}; + +enum udma_db_type { + UDMA_JFR_TYPE_DB, + UDMA_JFC_TYPE_DB, + UDMA_JFR_PAYLOAD, + UDMA_DB_TYPE_NUM, +}; + +enum jfc_poll_state { + JFC_OK, + JFC_EMPTY, + JFC_POLL_ERR, +}; + +enum { + CQE_FOR_SEND, + CQE_FOR_RECEIVE, +}; + +enum { + UDMA_CQE_SUCCESS = 0x00, + UDMA_CQE_UNSUPPORTED_OPCODE = 0x01, + UDMA_CQE_LOCAL_OP_ERR = 0x02, + UDMA_CQE_REMOTE_OP_ERR = 0x03, + UDMA_CQE_TRANSACTION_RETRY_COUNTER_ERR = 0x04, + UDMA_CQE_TRANSACTION_ACK_TIMEOUT_ERR = 0x05, + UDMA_JETTY_WORK_REQUEST_FLUSH = 0x06, +}; + +enum { + UDMA_CQE_LOCAL_LENGTH_ERR = 0x01, + UDMA_CQE_LOCAL_ACCESS_ERR = 0x02, + UDMA_CQE_REM_RSP_LENGTH_ERR = 0x03, + UDMA_CQE_LOCAL_DATA_POISON = 0x04, +}; + +enum { + UDMA_CQE_REM_UNSUPPORTED_REQ_ERR = 0x01, + UDMA_CQE_REM_ACCESS_ERR = 0x02, + UDMA_CQE_REM_DATA_POISON = 0x04, +}; + +enum hw_cqe_opcode { + HW_CQE_OPC_SEND = 0x00, + HW_CQE_OPC_SEND_WITH_IMM = 0x01, + HW_CQE_OPC_SEND_WITH_INV = 0x02, + HW_CQE_OPC_WRITE_WITH_IMM = 0x03, + HW_CQE_OPC_ERR = 0xff, +}; + +#endif /* _UAPI_UB_UMDK_URMA_UDMA_UDMA_ABI_H_ */ diff --git a/include/ub/urma/udma/udma_ctl.h b/include/ub/urma/udma/udma_ctl.h new file mode 100644 index 000000000000..19898d33c14b --- /dev/null +++ b/include/ub/urma/udma/udma_ctl.h @@ -0,0 +1,213 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef _UB_UMDK_URMA_UDMA_UDMA_CTL_H_ +#define _UB_UMDK_URMA_UDMA_UDMA_CTL_H_ + +#include + +#define UDMA_BUS_INSTANCE_SEID_SIZE 4 +#define UDMA_EID_PAIRS_COUNT 8 + +union udma_k_jfs_flag { + struct { + uint32_t sq_cstm : 1; + uint32_t db_cstm : 1; + uint32_t db_ctl_cstm : 1; + uint32_t reserved : 29; + } bs; + uint32_t value; +}; + +struct udma_que_cfg_ex { + uint32_t buff_size; + void *buff; +}; + +struct udma_jfs_cstm_cfg { + struct udma_que_cfg_ex sq; /* PA; should be converted by phys_to_virt. */ +}; + +struct udma_jfs_cfg_ex { + struct ubcore_jfs_cfg base_cfg; + struct ubcore_udata udata; + struct udma_jfs_cstm_cfg cstm_cfg; + ubcore_event_callback_t jfae_handler; +}; + +struct udma_jfc_cstm_cfg { + struct udma_que_cfg_ex cq; /* PA; should be using stars hw register addr. */ +}; + +struct udma_jfc_cfg_ex { + struct ubcore_jfc_cfg base_cfg; + struct ubcore_udata udata; + struct udma_jfc_cstm_cfg cstm_cfg; + ubcore_comp_callback_t jfce_handler; + ubcore_event_callback_t jfae_handler; +}; + +enum udma_jfc_type { + UDMA_NORMAL_JFC_TYPE, + UDMA_STARS_JFC_TYPE, + UDMA_CCU_JFC_TYPE, + UDMA_KERNEL_STARS_JFC_TYPE, + UDMA_JFC_TYPE_NUM, +}; + +struct udma_set_cqe_ex { + uint64_t addr; + uint32_t len; + enum udma_jfc_type jfc_type; +}; + +struct udma_ue_info_ex { + uint16_t ue_id; + uint32_t chip_id; + uint32_t die_id; + uint32_t offset_len; + resource_size_t db_base_addr; + resource_size_t dwqe_addr; + resource_size_t register_base_addr; +}; + +struct udma_tp_sport_in { + uint32_t tpn; +}; + +struct udma_tp_sport_out { + uint32_t data_udp_srcport; + uint32_t ack_udp_srcport; +}; + +struct udma_cqe_info_in { + enum ubcore_cr_status status; + uint8_t s_r; +}; + +enum udma_cqe_aux_info_type { + TPP2TQEM_WR_CNT, + DEVICE_RAS_STATUS_2, + RXDMA_WR_PAYL_AXI_ERR, + RXDMA_HEAD_SPLIT_ERR_FLAG0, + RXDMA_HEAD_SPLIT_ERR_FLAG1, + RXDMA_HEAD_SPLIT_ERR_FLAG2, + RXDMA_HEAD_SPLIT_ERR_FLAG3, + TP_RCP_INNER_ALM_FOR_CQE, + TWP_AE_DFX_FOR_CQE, + PA_OUT_PKT_ERR_CNT, + TP_DAM_AXI_ALARM, + TP_DAM_VFT_BT_ALARM, + TP_EUM_AXI_ALARM, + TP_EUM_VFT_BT_ALARM, + TP_TPMM_AXI_ALARM, + TP_TPMM_VFT_BT_ALARM, + TP_TPGCM_AXI_ALARM, + TP_TPGCM_VFT_BT_ALARM, + TWP_ALM, + TP_RWP_INNER_ALM_FOR_CQE, + TWP_DFX21, + LQC_TA_RNR_TANACK_CNT, + FVT, + RQMT0, + RQMT1, + RQMT2, + RQMT3, + RQMT4, + RQMT5, + RQMT6, + RQMT7, + RQMT8, + RQMT9, + RQMT10, + RQMT11, + RQMT12, + RQMT13, + RQMT14, + RQMT15, + PROC_ERROR_ALM, + LQC_TA_TIMEOUT_TAACK_CNT, + TP_RRP_ERR_FLG_0_FOR_CQE, + MAX_CQE_AUX_INFO_TYPE_NUM +}; + +struct udma_cqe_aux_info_out { + enum udma_cqe_aux_info_type *aux_info_type; + uint32_t *aux_info_value; + uint32_t aux_info_num; +}; + +struct udma_ae_info_in { + uint32_t event_type; +}; + +enum udma_ae_aux_info_type { + TP_RRP_FLUSH_TIMER_PKT_CNT, + TPP_DFX5, + TWP_AE_DFX_FOR_AE, + TP_RRP_ERR_FLG_0_FOR_AE, + TP_RRP_ERR_FLG_1, + TP_RWP_INNER_ALM_FOR_AE, + TP_RCP_INNER_ALM_FOR_AE, + LQC_TA_TQEP_WQE_ERR, + LQC_TA_CQM_CQE_INNER_ALARM, + MAX_AE_AUX_INFO_TYPE_NUM +}; + +struct udma_ae_aux_info_out { + enum udma_ae_aux_info_type *aux_info_type; + uint32_t *aux_info_value; + uint32_t aux_info_num; +}; + +enum udma_user_ctl_opcode { + UDMA_USER_CTL_CREATE_JFS_EX, + UDMA_USER_CTL_DELETE_JFS_EX, + UDMA_USER_CTL_CREATE_JFC_EX, + UDMA_USER_CTL_DELETE_JFC_EX, + UDMA_USER_CTL_SET_CQE_ADDR, + UDMA_USER_CTL_QUERY_UE_INFO, + UDMA_USER_CTL_GET_DEV_RES_RATIO, + UDMA_USER_CTL_NPU_REGISTER_INFO_CB, + UDMA_USER_CTL_NPU_UNREGISTER_INFO_CB, + UDMA_USER_CTL_QUERY_TP_SPORT, + UDMA_USER_CTL_QUERY_CQE_AUX_INFO, + UDMA_USER_CTL_QUERY_AE_AUX_INFO, + UDMA_USER_CTL_QUERY_UBMEM_INFO, + UDMA_USER_CTL_QUERY_PAIR_DEVNUM, + UDMA_USER_CTL_MAX, +}; + +struct udma_ctrlq_event_nb { + uint8_t opcode; + int (*crq_handler)(struct ubcore_device *dev, void *data, uint16_t len); +}; + +struct udma_dev_pair_info { + uint32_t peer_dev_id; + uint32_t slot_id; + uint32_t pair_num; + struct { + uint32_t local_eid[UDMA_BUS_INSTANCE_SEID_SIZE]; + uint32_t remote_eid[UDMA_BUS_INSTANCE_SEID_SIZE]; + uint32_t flag : 16; + uint32_t hop : 4; + uint32_t rsv : 12; + } eid_pairs[UDMA_EID_PAIRS_COUNT]; +}; + +static inline bool udma_check_base_param(uint64_t addr, uint32_t in_len, uint32_t len) +{ + return (addr == 0 || in_len != len); +} + +typedef int (*udma_user_ctl_ops)(struct ubcore_device *dev, struct ubcore_ucontext *uctx, + struct ubcore_user_ctl_in *in, struct ubcore_user_ctl_out *out); + +int udma_user_ctl(struct ubcore_device *dev, struct ubcore_user_ctl *k_user_ctl); +int udma_query_cqe_aux_info(struct ubcore_device *dev, struct ubcore_ucontext *uctx, + struct ubcore_user_ctl_in *in, struct ubcore_user_ctl_out *out); +int udma_query_ae_aux_info(struct ubcore_device *dev, struct ubcore_ucontext *uctx, + struct ubcore_user_ctl_in *in, struct ubcore_user_ctl_out *out); + +#endif /* _UB_UMDK_URMA_UDMA_UDMA_CTL_H_ */ -- Gitee From fef27a3d1407ec2a40ee7efa9ff05ac950073c97 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Thu, 18 Sep 2025 10:17:46 +0800 Subject: [PATCH 043/103] ub: udma: Register and unregister debugfs. commit a94ef92be17600ecdaa3f210265523a2b9049847 openEuler This patch adds the ability to register and unregister debugfs. In driver loading process, UDMA will register debugfs function. In driver unloading process, UDMA will unregister debugfs function. Signed-off-by: Wei Qin Signed-off-by: Chunzhi Hu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/Makefile | 2 +- drivers/ub/urma/hw/udma/udma_debugfs.c | 262 +++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_debugfs.h | 83 ++++++++ drivers/ub/urma/hw/udma/udma_dev.h | 1 + drivers/ub/urma/hw/udma/udma_main.c | 9 +- 5 files changed, 355 insertions(+), 2 deletions(-) create mode 100644 drivers/ub/urma/hw/udma/udma_debugfs.c create mode 100644 drivers/ub/urma/hw/udma/udma_debugfs.h diff --git a/drivers/ub/urma/hw/udma/Makefile b/drivers/ub/urma/hw/udma/Makefile index 0561b3f85191..416fff14aa6a 100644 --- a/drivers/ub/urma/hw/udma/Makefile +++ b/drivers/ub/urma/hw/udma/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0+ udma-$(CONFIG_UB_UDMA) := udma_main.o udma_cmd.o udma_common.o udma_ctx.o udma_db.o \ - udma_rct.o udma_tid.o + udma_rct.o udma_tid.o udma_debugfs.o obj-m := udma.o diff --git a/drivers/ub/urma/hw/udma/udma_debugfs.c b/drivers/ub/urma/hw/udma/udma_debugfs.c new file mode 100644 index 000000000000..efc94a3d7e9e --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_debugfs.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt +#define pr_fmt(fmt) "UDMA: " fmt + +#include +#include +#include +#include +#include "udma_cmd.h" +#include "udma_debugfs.h" + +static struct dentry *g_udma_dbgfs_root; + +static struct udma_debugfs_file_info g_ta_dfx_mod[TA_MAX_SIZE] = { + {"mrd", RDONLY, UDMA_CMD_DEBUGFS_TA_INFO, UDMA_TA_MRD}, +}; + +static struct udma_debugfs_file_info g_tp_dfx_mod[TP_MAX_SIZE] = { + {"rxtx", RDONLY, UDMA_CMD_DEBUGFS_TP_INFO, UDMA_TP_RXTX}, +}; + +static void show_ta_mrd_dfx(struct udma_query_mrd_dfx *data) +{ + pr_info("****************** ta_mrd_dfx ******************\n"); + pr_info("mrd_dsqe_issue_cnt\t0x%08x\n", data->mrd_dsqe_issue_cnt); + pr_info("mrd_dsqe_exec_cnt\t0x%08x\n", data->mrd_dsqe_exec_cnt); + pr_info("mrd_dsqe_drop_cnt\t0x%08x\n", data->mrd_dsqe_drop_cnt); + pr_info("mrd_jfsdb_issue_cnt\t0x%08x\n", data->mrd_jfsdb_issue_cnt); + pr_info("mrd_jfsdb_exec_cnt\t0x%08x\n", data->mrd_jfsdb_exec_cnt); + pr_info("mrd_mb_issue_cnt\t\t0x%08x\n", data->mrd_mb_issue_cnt); + pr_info("mrd_mb_exec_cnt\t\t0x%08x\n", data->mrd_mb_exec_cnt); + pr_info("mrd_eqdb_issue_cnt\t0x%08x\n", data->mrd_eqdb_issue_cnt); + pr_info("mrd_mb_buff_full\t\t0x%08x\n", data->mrd_mb_buff_full); + pr_info("mrd_mb_buff_empty\t0x%08x\n", data->mrd_mb_buff_empty); + pr_info("mrd_mem_ecc_err_1b\t0x%08x\n", data->mrd_mem_ecc_err_1b); + pr_info("mrd_mem_ecc_1b_info\t0x%08x\n", data->mrd_mem_ecc_1b_info); + pr_info("mrd_mb_state\t\t0x%08x\n", data->mrd_mb_state); + pr_info("mrd_eqdb_exec_cnt\t0x%08x\n", data->mrd_eqdb_exec_cnt); + pr_info("****************** ta_mrd_dfx ******************\n"); +} + +static void show_tp_rxtx_dfx(struct udma_query_rxtx_dfx *data) +{ + pr_info("****************** tp_rxtx_dfx ******************\n"); + pr_info("tpp2_txdma_hdr_um_pkt_cnt\t0x%016llx\n", data->tpp2_txdma_hdr_um_pkt_cnt); + pr_info("tpp2_txdma_ctp_rm_pkt_cnt\t0x%016llx\n", data->tpp2_txdma_ctp_rm_pkt_cnt); + pr_info("tpp2_txdma_ctp_rc_pkt_cnt\t0x%016llx\n", data->tpp2_txdma_ctp_rc_pkt_cnt); + pr_info("tpp2_txdma_tp_rm_pkt_cnt\t\t0x%016llx\n", data->tpp2_txdma_tp_rm_pkt_cnt); + pr_info("tpp2_txdma_tp_rc_pkt_cnt\t\t0x%016llx\n", data->tpp2_txdma_tp_rc_pkt_cnt); + pr_info("rhp_glb_rm_pkt_cnt\t\t0x%016llx\n", data->rhp_glb_rm_pkt_cnt); + pr_info("rhp_glb_rc_pkt_cnt\t\t0x%016llx\n", data->rhp_glb_rc_pkt_cnt); + pr_info("rhp_clan_rm_pkt_cnt\t\t0x%016llx\n", data->rhp_clan_rm_pkt_cnt); + pr_info("rhp_clan_rc_pkt_cnt\t\t0x%016llx\n", data->rhp_clan_rc_pkt_cnt); + pr_info("rhp_ud_pkt_cnt\t\t\t0x%016llx\n", data->rhp_ud_pkt_cnt); + pr_info("****************** tp_rxtx_dfx ******************\n"); +} + +static int udma_query_mrd_dfx(struct file_private_data *private_data) +{ + struct udma_query_mrd_dfx out_regs; + struct ubase_cmd_buf in, out; + int ret; + + out_regs.sub_module = private_data->sub_opcode; + udma_fill_buf(&in, private_data->opcode, true, + sizeof(struct udma_query_mrd_dfx), &out_regs); + udma_fill_buf(&out, private_data->opcode, true, + sizeof(struct udma_query_mrd_dfx), &out_regs); + + ret = ubase_cmd_send_inout(private_data->udma_dev->comdev.adev, &in, &out); + if (ret) { + dev_err(private_data->udma_dev->dev, "failed to query mrd DFX, ret = %d.\n", ret); + return ret; + } + + show_ta_mrd_dfx(&out_regs); + + return 0; +} + +static int udma_query_rxtx_dfx(struct file_private_data *private_data) +{ + struct udma_query_rxtx_dfx out_regs; + struct ubase_cmd_buf in, out; + int ret; + + out_regs.sub_module = private_data->sub_opcode; + udma_fill_buf(&in, private_data->opcode, true, sizeof(struct udma_query_rxtx_dfx), + &out_regs); + udma_fill_buf(&out, private_data->opcode, true, + sizeof(struct udma_query_rxtx_dfx), &out_regs); + + ret = ubase_cmd_send_inout(private_data->udma_dev->comdev.adev, &in, &out); + if (ret) { + dev_err(private_data->udma_dev->dev, "failed to query rxtx DFX, ret = %d.\n", ret); + return ret; + } + + show_tp_rxtx_dfx(&out_regs); + + return 0; +} + +static inline int udma_debugfs_open(struct inode *inode, struct file *filp) +{ + filp->private_data = inode->i_private; + + return 0; +} + +static ssize_t udma_debugfs_read(struct file *filp, char __user *buf, + size_t size, loff_t *ppos) +{ + struct file_private_data *private_data = filp->private_data; + int ret; + + switch (private_data->sub_opcode) { + case UDMA_TA_MRD: + ret = udma_query_mrd_dfx(private_data); + break; + case UDMA_TP_RXTX: + ret = udma_query_rxtx_dfx(private_data); + break; + default: + dev_err(private_data->udma_dev->dev, "invalid type %u.\n", + private_data->sub_opcode); + return -EFAULT; + } + + return ret; +} + +static const struct file_operations udma_debugfs_rd_fops = { + .owner = THIS_MODULE, + .read = udma_debugfs_read, + .open = udma_debugfs_open, +}; + +static const uint16_t file_mod[FILE_MOD_SIZE] = { + 0200, 0400, +}; + +static int udma_debugfs_create_files(struct udma_dev *udma_dev, struct udma_dev_debugfs *dbgfs) +{ + struct file_private_data *private_data; + struct file_private_data *cur_p; + struct dentry *entry; + int i; + + private_data = kzalloc(sizeof(struct file_private_data) * (TA_MAX_SIZE + TP_MAX_SIZE), + GFP_KERNEL); + if (!private_data) + return -ENOMEM; + + for (i = 0; i < TA_MAX_SIZE; ++i) { + cur_p = private_data + i; + cur_p->udma_dev = udma_dev; + cur_p->opcode = g_ta_dfx_mod[i].opcode; + cur_p->sub_opcode = g_ta_dfx_mod[i].sub_opcode; + entry = debugfs_create_file(g_ta_dfx_mod[i].name, file_mod[g_ta_dfx_mod[i].fmod], + dbgfs->ta_root, cur_p, &udma_debugfs_rd_fops); + if (IS_ERR(entry)) { + dev_err(udma_dev->dev, "create %s failed.\n", g_ta_dfx_mod[i].name); + kfree(private_data); + return -EINVAL; + } + } + + for (i = 0; i < TP_MAX_SIZE; ++i) { + cur_p = private_data + i + TA_MAX_SIZE; + cur_p->udma_dev = udma_dev; + cur_p->opcode = g_tp_dfx_mod[i].opcode; + cur_p->sub_opcode = g_tp_dfx_mod[i].sub_opcode; + entry = debugfs_create_file(g_tp_dfx_mod[i].name, file_mod[g_tp_dfx_mod[i].fmod], + dbgfs->tp_root, cur_p, &udma_debugfs_rd_fops); + if (IS_ERR(entry)) { + dev_err(udma_dev->dev, "create %s failed.\n", g_tp_dfx_mod[i].name); + kfree(private_data); + return -EINVAL; + } + } + + dbgfs->private_data = private_data; + dbgfs->private_data_size = TA_MAX_SIZE + TP_MAX_SIZE; + + return 0; +} + +void udma_register_debugfs(struct udma_dev *udma_dev) +{ + struct udma_dev_debugfs *dbgfs; + + if (IS_ERR_OR_NULL(g_udma_dbgfs_root)) { + dev_err(udma_dev->dev, "Debugfs root path does not exist.\n"); + goto create_error; + } + + dbgfs = kzalloc(sizeof(*dbgfs), GFP_KERNEL); + if (!dbgfs) + goto create_error; + + dbgfs->root = debugfs_create_dir(udma_dev->dev_name, g_udma_dbgfs_root); + if (IS_ERR(dbgfs->root)) { + dev_err(udma_dev->dev, "Debugfs create dev path failed.\n"); + goto create_dev_error; + } + + dbgfs->ta_root = debugfs_create_dir("ta", dbgfs->root); + if (IS_ERR(dbgfs->ta_root)) { + dev_err(udma_dev->dev, "Debugfs create ta path failed.\n"); + goto create_path_error; + } + + dbgfs->tp_root = debugfs_create_dir("tp", dbgfs->root); + if (IS_ERR(dbgfs->tp_root)) { + dev_err(udma_dev->dev, "Debugfs create tp path failed.\n"); + goto create_path_error; + } + + if (udma_debugfs_create_files(udma_dev, dbgfs)) { + dev_err(udma_dev->dev, "Debugfs create files failed.\n"); + goto create_path_error; + } + + udma_dev->dbgfs = dbgfs; + + return; + +create_path_error: + debugfs_remove_recursive(dbgfs->root); +create_dev_error: + kfree(dbgfs); +create_error: + udma_dev->dbgfs = NULL; +} + +void udma_unregister_debugfs(struct udma_dev *udma_dev) +{ + if (IS_ERR_OR_NULL(g_udma_dbgfs_root)) + return; + + if (!udma_dev->dbgfs) + return; + + debugfs_remove_recursive(udma_dev->dbgfs->root); + kfree(udma_dev->dbgfs->private_data); + kfree(udma_dev->dbgfs); + udma_dev->dbgfs = NULL; +} + +void udma_init_debugfs(void) +{ + g_udma_dbgfs_root = debugfs_create_dir("udma", NULL); +} + +void udma_uninit_debugfs(void) +{ + debugfs_remove_recursive(g_udma_dbgfs_root); + g_udma_dbgfs_root = NULL; +} diff --git a/drivers/ub/urma/hw/udma/udma_debugfs.h b/drivers/ub/urma/hw/udma/udma_debugfs.h new file mode 100644 index 000000000000..d49440251dab --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_debugfs.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_DEBUGFS_H__ +#define __UDMA_DEBUGFS_H__ + +#include "udma_dev.h" +#include "udma_cmd.h" + +#define TA_MAX_SIZE 1 +#define TP_MAX_SIZE 1 +#define FILE_MOD_SIZE 2 + +enum udma_dfx_sub_opcode { + UDMA_TA_MRD, + UDMA_TP_RXTX, +}; + +enum udma_debugfs_file_mod { + RDONLY, +}; + +struct udma_debugfs_file_info { + const char *name; + enum udma_debugfs_file_mod fmod; + enum udma_cmd_opcode_type opcode; + enum udma_dfx_sub_opcode sub_opcode; +}; + +struct udma_query_rxtx_dfx { + uint32_t sub_module; + uint64_t tpp2_txdma_hdr_um_pkt_cnt; + uint64_t tpp2_txdma_ctp_rm_pkt_cnt; + uint64_t tpp2_txdma_ctp_rc_pkt_cnt; + uint64_t tpp2_txdma_tp_rm_pkt_cnt; + uint64_t tpp2_txdma_tp_rc_pkt_cnt; + uint64_t rhp_glb_rm_pkt_cnt; + uint64_t rhp_glb_rc_pkt_cnt; + uint64_t rhp_clan_rm_pkt_cnt; + uint64_t rhp_clan_rc_pkt_cnt; + uint64_t rhp_ud_pkt_cnt; + uint32_t rsvd[16]; +}; + +struct udma_query_mrd_dfx { + uint32_t sub_module; + uint32_t mrd_dsqe_issue_cnt; + uint32_t mrd_dsqe_exec_cnt; + uint32_t mrd_dsqe_drop_cnt; + uint32_t mrd_jfsdb_issue_cnt; + uint32_t mrd_jfsdb_exec_cnt; + uint32_t mrd_mb_issue_cnt; + uint32_t mrd_mb_exec_cnt; + uint32_t mrd_eqdb_issue_cnt; + uint32_t mrd_mb_buff_full; + uint32_t mrd_mb_buff_empty; + uint32_t mrd_mem_ecc_err_1b; + uint32_t mrd_mem_ecc_1b_info; + uint32_t mrd_mb_state; + uint32_t mrd_eqdb_exec_cnt; + uint32_t rsvd[7]; +}; + +struct udma_dev_debugfs { + struct dentry *root; + struct dentry *ta_root; + struct dentry *tp_root; + struct file_private_data *private_data; + uint32_t private_data_size; +}; + +struct file_private_data { + struct udma_dev *udma_dev; + enum udma_cmd_opcode_type opcode; + enum udma_dfx_sub_opcode sub_opcode; +}; + +void udma_init_debugfs(void); +void udma_uninit_debugfs(void); +void udma_unregister_debugfs(struct udma_dev *udma_dev); +void udma_register_debugfs(struct udma_dev *udma_dev); + +#endif /* __UDMA_DEBUGFS_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_dev.h b/drivers/ub/urma/hw/udma/udma_dev.h index a4df1f114d23..c12e390c962a 100644 --- a/drivers/ub/urma/hw/udma/udma_dev.h +++ b/drivers/ub/urma/hw/udma/udma_dev.h @@ -107,6 +107,7 @@ struct udma_dev { struct list_head db_list[UDMA_DB_TYPE_NUM]; struct mutex db_mutex; uint32_t status; + struct udma_dev_debugfs *dbgfs; uint32_t ue_num; uint32_t ue_id; struct page *db_page; diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 77ade2c69f4a..15088884080c 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -21,6 +21,7 @@ #include "udma_ctx.h" #include "udma_rct.h" #include "udma_tid.h" +#include "udma_debugfs.h" #include "udma_common.h" #include "udma_ctrlq_tp.h" @@ -788,6 +789,7 @@ static int udma_init_dev(struct auxiliary_device *adev) goto err_create; } + udma_register_debugfs(udma_dev); udma_dev->status = UDMA_NORMAL; mutex_unlock(&udma_reset_mutex); dev_info(udma_dev->dev, "init udma successfully.\n"); @@ -820,6 +822,7 @@ void udma_reset_down(struct auxiliary_device *adev) udma_dev->status = UDMA_SUSPEND; + udma_unregister_debugfs(udma_dev); udma_unset_ubcore_dev(udma_dev); mutex_unlock(&udma_reset_mutex); } @@ -889,9 +892,12 @@ static int __init udma_init(void) { int ret; + udma_init_debugfs(); ret = auxiliary_driver_register(&udma_drv); - if (ret) + if (ret) { pr_err("failed to register auxiliary_driver\n"); + udma_uninit_debugfs(); + } return ret; } @@ -900,6 +906,7 @@ static void __exit udma_exit(void) { is_rmmod = true; auxiliary_driver_unregister(&udma_drv); + udma_uninit_debugfs(); } module_init(udma_init); -- Gitee From 1aea6167efb735ae8a33d1a47c4af727f9f53f8e Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Thu, 18 Sep 2025 10:25:32 +0800 Subject: [PATCH 044/103] ub: udma: Support register and unregister ae event. commit 73d92d483ecd28324f902da53838bb7c1e183a5f openEuler This patch adds the ability to register and unregister ta related ae event. In driver loading process, udma will register ae event function. In driver unloading process, udma will unregister ae event function. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/Makefile | 2 +- drivers/ub/urma/hw/udma/udma_common.h | 11 + drivers/ub/urma/hw/udma/udma_dev.h | 1 + drivers/ub/urma/hw/udma/udma_eq.c | 281 ++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_eq.h | 10 + drivers/ub/urma/hw/udma/udma_jetty.h | 5 + drivers/ub/urma/hw/udma/udma_jfc.h | 35 ++++ drivers/ub/urma/hw/udma/udma_jfr.h | 43 ++++ drivers/ub/urma/hw/udma/udma_main.c | 28 ++- 9 files changed, 414 insertions(+), 2 deletions(-) create mode 100644 drivers/ub/urma/hw/udma/udma_eq.c create mode 100644 drivers/ub/urma/hw/udma/udma_eq.h create mode 100644 drivers/ub/urma/hw/udma/udma_jfc.h create mode 100644 drivers/ub/urma/hw/udma/udma_jfr.h diff --git a/drivers/ub/urma/hw/udma/Makefile b/drivers/ub/urma/hw/udma/Makefile index 416fff14aa6a..ac9f9885b1e8 100644 --- a/drivers/ub/urma/hw/udma/Makefile +++ b/drivers/ub/urma/hw/udma/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0+ udma-$(CONFIG_UB_UDMA) := udma_main.o udma_cmd.o udma_common.o udma_ctx.o udma_db.o \ - udma_rct.o udma_tid.o udma_debugfs.o + udma_rct.o udma_tid.o udma_debugfs.o udma_eq.o obj-m := udma.o diff --git a/drivers/ub/urma/hw/udma/udma_common.h b/drivers/ub/urma/hw/udma/udma_common.h index f3f32862db0a..c6e83a0d84c3 100644 --- a/drivers/ub/urma/hw/udma/udma_common.h +++ b/drivers/ub/urma/hw/udma/udma_common.h @@ -8,6 +8,17 @@ #include #include "udma_dev.h" +struct udma_jetty_grp { + struct ubcore_jetty_group ubcore_jetty_grp; + uint32_t start_jetty_id; + uint32_t next_jetty_id; + uint32_t jetty_grp_id; + uint32_t valid; + struct mutex valid_lock; + refcount_t ae_refcount; + struct completion ae_comp; +}; + struct udma_jetty_queue { struct udma_buf buf; void *kva_curr; diff --git a/drivers/ub/urma/hw/udma/udma_dev.h b/drivers/ub/urma/hw/udma/udma_dev.h index c12e390c962a..cc073ec8d97d 100644 --- a/drivers/ub/urma/hw/udma/udma_dev.h +++ b/drivers/ub/urma/hw/udma/udma_dev.h @@ -96,6 +96,7 @@ struct udma_dev { struct xarray npu_nb_table; struct mutex npu_nb_mutex; struct xarray tpn_ue_idx_table; + struct ubase_event_nb *ae_event_addr[UBASE_EVENT_TYPE_MAX]; resource_size_t db_base; void __iomem *k_db_base; struct xarray ksva_table; diff --git a/drivers/ub/urma/hw/udma/udma_eq.c b/drivers/ub/urma/hw/udma/udma_eq.c new file mode 100644 index 000000000000..8ac14585ec6c --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_eq.c @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt +#define pr_fmt(fmt) "UDMA: " fmt + +#include +#include +#include +#include +#include +#include "udma_ctrlq_tp.h" +#include "udma_dev.h" +#include "udma_cmd.h" +#include "udma_jfs.h" +#include "udma_jfr.h" +#include "udma_jfc.h" +#include "udma_jetty.h" +#include +#include "udma_eq.h" + +static int udma_ae_jfs_check_err(struct auxiliary_device *adev, uint32_t queue_num) +{ + struct udma_dev *udma_dev = get_udma_dev(adev); + struct ubcore_jetty *ubcore_jetty; + struct udma_jetty_queue *udma_sq; + struct udma_jetty *udma_jetty; + struct ubcore_jfs *ubcore_jfs; + struct udma_jfs *udma_jfs; + struct ubcore_event ae; + + xa_lock(&udma_dev->jetty_table.xa); + udma_sq = (struct udma_jetty_queue *)xa_load(&udma_dev->jetty_table.xa, queue_num); + if (!udma_sq) { + dev_warn(udma_dev->dev, + "async event for bogus queue number = %u.\n", queue_num); + xa_unlock(&udma_dev->jetty_table.xa); + return -EINVAL; + } + + if (udma_sq->is_jetty) { + udma_jetty = to_udma_jetty_from_queue(udma_sq); + ubcore_jetty = &udma_jetty->ubcore_jetty; + if (ubcore_jetty->jfae_handler) { + refcount_inc(&udma_jetty->ae_refcount); + xa_unlock(&udma_dev->jetty_table.xa); + ae.ub_dev = ubcore_jetty->ub_dev; + ae.element.jetty = ubcore_jetty; + ae.event_type = UBCORE_EVENT_JETTY_ERR; + ubcore_jetty->jfae_handler(&ae, ubcore_jetty->uctx); + if (refcount_dec_and_test(&udma_jetty->ae_refcount)) + complete(&udma_jetty->ae_comp); + } else { + xa_unlock(&udma_dev->jetty_table.xa); + } + } else { + udma_jfs = to_udma_jfs_from_queue(udma_sq); + ubcore_jfs = &udma_jfs->ubcore_jfs; + if (ubcore_jfs->jfae_handler) { + refcount_inc(&udma_jfs->ae_refcount); + xa_unlock(&udma_dev->jetty_table.xa); + ae.ub_dev = ubcore_jfs->ub_dev; + ae.element.jfs = ubcore_jfs; + ae.event_type = UBCORE_EVENT_JFS_ERR; + ubcore_jfs->jfae_handler(&ae, ubcore_jfs->uctx); + if (refcount_dec_and_test(&udma_jfs->ae_refcount)) + complete(&udma_jfs->ae_comp); + } else { + xa_unlock(&udma_dev->jetty_table.xa); + } + } + + return 0; +} + +static int udma_ae_jfr_check_err(struct auxiliary_device *adev, uint32_t queue_num, + enum ubcore_event_type ubcore_etype) +{ + struct udma_dev *udma_dev = get_udma_dev(adev); + struct ubcore_jfr *ubcore_jfr; + struct udma_jfr *udma_jfr; + struct ubcore_event ae; + + xa_lock(&udma_dev->jfr_table.xa); + udma_jfr = (struct udma_jfr *)xa_load(&udma_dev->jfr_table.xa, queue_num); + if (!udma_jfr) { + dev_warn(udma_dev->dev, + "async event for bogus jfr number = %u.\n", queue_num); + xa_unlock(&udma_dev->jfr_table.xa); + return -EINVAL; + } + + ubcore_jfr = &udma_jfr->ubcore_jfr; + if (ubcore_jfr->jfae_handler) { + refcount_inc(&udma_jfr->ae_refcount); + xa_unlock(&udma_dev->jfr_table.xa); + ae.ub_dev = ubcore_jfr->ub_dev; + ae.element.jfr = ubcore_jfr; + ae.event_type = ubcore_etype; + ubcore_jfr->jfae_handler(&ae, ubcore_jfr->uctx); + if (refcount_dec_and_test(&udma_jfr->ae_refcount)) + complete(&udma_jfr->ae_comp); + } else { + xa_unlock(&udma_dev->jfr_table.xa); + } + + return 0; +} + +static int udma_ae_jfc_check_err(struct auxiliary_device *adev, uint32_t queue_num) +{ + struct udma_dev *udma_dev = get_udma_dev(adev); + struct ubcore_jfc *ubcore_jfc; + struct udma_jfc *udma_jfc; + struct ubcore_event ae; + unsigned long flags; + + xa_lock_irqsave(&udma_dev->jfc_table.xa, flags); + udma_jfc = (struct udma_jfc *)xa_load(&udma_dev->jfc_table.xa, queue_num); + if (!udma_jfc) { + dev_warn(udma_dev->dev, + "async event for bogus jfc number = %u.\n", queue_num); + xa_unlock_irqrestore(&udma_dev->jfc_table.xa, flags); + return -EINVAL; + } + + ubcore_jfc = &udma_jfc->base; + if (ubcore_jfc->jfae_handler) { + refcount_inc(&udma_jfc->event_refcount); + xa_unlock_irqrestore(&udma_dev->jfc_table.xa, flags); + ae.ub_dev = ubcore_jfc->ub_dev; + ae.element.jfc = ubcore_jfc; + ae.event_type = UBCORE_EVENT_JFC_ERR; + ubcore_jfc->jfae_handler(&ae, ubcore_jfc->uctx); + if (refcount_dec_and_test(&udma_jfc->event_refcount)) + complete(&udma_jfc->event_comp); + } else { + xa_unlock_irqrestore(&udma_dev->jfc_table.xa, flags); + } + + return 0; +} + +static int udma_ae_jetty_group_check_err(struct auxiliary_device *adev, uint32_t queue_num) +{ + struct udma_dev *udma_dev = get_udma_dev(adev); + struct ubcore_jetty_group *ubcore_jetty_grp; + struct udma_jetty_grp *udma_jetty_grp; + struct ubcore_event ae; + + xa_lock(&udma_dev->jetty_grp_table.xa); + udma_jetty_grp = (struct udma_jetty_grp *)xa_load(&udma_dev->jetty_grp_table.xa, queue_num); + if (!udma_jetty_grp) { + dev_warn(udma_dev->dev, + "async event for bogus jetty group number = %u.\n", queue_num); + xa_unlock(&udma_dev->jetty_grp_table.xa); + return -EINVAL; + } + + ubcore_jetty_grp = &udma_jetty_grp->ubcore_jetty_grp; + if (ubcore_jetty_grp->jfae_handler) { + refcount_inc(&udma_jetty_grp->ae_refcount); + xa_unlock(&udma_dev->jetty_grp_table.xa); + ae.ub_dev = ubcore_jetty_grp->ub_dev; + ae.element.jetty_grp = ubcore_jetty_grp; + ae.event_type = UBCORE_EVENT_JETTY_GRP_ERR; + ubcore_jetty_grp->jfae_handler(&ae, ubcore_jetty_grp->uctx); + if (refcount_dec_and_test(&udma_jetty_grp->ae_refcount)) + complete(&udma_jetty_grp->ae_comp); + } else { + xa_unlock(&udma_dev->jetty_grp_table.xa); + } + + return 0; +} + +static int udma_ae_jetty_level_error(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct ubase_event_nb *ev_nb = container_of(nb, struct ubase_event_nb, nb); + struct auxiliary_device *adev = (struct auxiliary_device *)ev_nb->back; + struct ubase_aeq_notify_info *info = data; + uint32_t queue_num; + + queue_num = info->aeqe->event.queue_event.num; + + dev_warn(&adev->dev, + "trigger jetty level ae, event type is %d, sub type is %d, queue_num is %u.\n", + info->event_type, info->sub_type, queue_num); + + if (info->event_type == UBASE_EVENT_TYPE_JFR_LIMIT_REACHED) + return udma_ae_jfr_check_err(adev, queue_num, UBCORE_EVENT_JFR_LIMIT_REACHED); + + switch (info->sub_type) { + case UBASE_SUBEVENT_TYPE_JFS_CHECK_ERROR: + return udma_ae_jfs_check_err(adev, queue_num); + case UBASE_SUBEVENT_TYPE_JFR_CHECK_ERROR: + return udma_ae_jfr_check_err(adev, queue_num, UBCORE_EVENT_JFR_ERR); + case UBASE_SUBEVENT_TYPE_JFC_CHECK_ERROR: + return udma_ae_jfc_check_err(adev, queue_num); + case UBASE_SUBEVENT_TYPE_JETTY_GROUP_CHECK_ERROR: + return udma_ae_jetty_group_check_err(adev, queue_num); + default: + dev_warn(&adev->dev, + "udma get unsupported async event.\n"); + return -EINVAL; + } +} + +struct ae_operation { + uint32_t op_code; + notifier_fn_t call; +}; + +static struct ae_operation udma_ae_opts[] = { + {UBASE_EVENT_TYPE_JETTY_LEVEL_ERROR, udma_ae_jetty_level_error}, + {UBASE_EVENT_TYPE_JFR_LIMIT_REACHED, udma_ae_jetty_level_error}, +}; + +void udma_unregister_ae_event(struct auxiliary_device *adev) +{ + struct udma_dev *udma_dev = get_udma_dev(adev); + int i; + + for (i = 0; i < UBASE_EVENT_TYPE_MAX; i++) { + if (udma_dev->ae_event_addr[i]) { + ubase_event_unregister(adev, udma_dev->ae_event_addr[i]); + kfree(udma_dev->ae_event_addr[i]); + udma_dev->ae_event_addr[i] = NULL; + } + } +} + +static int +udma_event_register(struct auxiliary_device *adev, enum ubase_event_type event_type, + int (*call)(struct notifier_block *nb, + unsigned long action, void *data)) +{ + struct udma_dev *udma_dev = get_udma_dev(adev); + struct ubase_event_nb *cb; + int ret = 0; + + cb = kzalloc(sizeof(*cb), GFP_KERNEL); + if (!cb) + return -ENOMEM; + + cb->drv_type = UBASE_DRV_UDMA; + cb->event_type = event_type; + cb->back = (void *)adev; + cb->nb.notifier_call = call; + + ret = ubase_event_register(adev, cb); + if (ret) { + dev_err(&adev->dev, + "failed to register async event, event type = %u, ret = %d.\n", + cb->event_type, ret); + kfree(cb); + return ret; + } + udma_dev->ae_event_addr[event_type] = cb; + + return 0; +} + +/* thanks to drivers/infiniband/hw/erdma/erdma_eq.c */ +int udma_register_ae_event(struct auxiliary_device *adev) +{ + uint32_t i, opt_num; + int ret; + + opt_num = sizeof(udma_ae_opts) / sizeof(struct ae_operation); + for (i = 0; i < opt_num; ++i) { + ret = udma_event_register(adev, udma_ae_opts[i].op_code, udma_ae_opts[i].call); + if (ret) { + udma_unregister_ae_event(adev); + break; + } + } + + return ret; +} diff --git a/drivers/ub/urma/hw/udma/udma_eq.h b/drivers/ub/urma/hw/udma/udma_eq.h new file mode 100644 index 000000000000..f771483e168f --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_eq.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_EQ_H__ +#define __UDMA_EQ_H__ + +int udma_register_ae_event(struct auxiliary_device *adev); +void udma_unregister_ae_event(struct auxiliary_device *adev); + +#endif /* __UDMA_EQ_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_jetty.h b/drivers/ub/urma/hw/udma/udma_jetty.h index e213278bcca3..00a3c41b39b6 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.h +++ b/drivers/ub/urma/hw/udma/udma_jetty.h @@ -22,6 +22,11 @@ static inline struct udma_jetty *to_udma_jetty(struct ubcore_jetty *jetty) return container_of(jetty, struct udma_jetty, ubcore_jetty); } +static inline struct udma_jetty_grp *to_udma_jetty_grp(struct ubcore_jetty_group *jetty_grp) +{ + return container_of(jetty_grp, struct udma_jetty_grp, ubcore_jetty_grp); +} + static inline struct udma_jetty *to_udma_jetty_from_queue(struct udma_jetty_queue *queue) { return container_of(queue, struct udma_jetty, sq); diff --git a/drivers/ub/urma/hw/udma/udma_jfc.h b/drivers/ub/urma/hw/udma/udma_jfc.h new file mode 100644 index 000000000000..3841049c28a0 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_jfc.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_JFC_H__ +#define __UDMA_JFC_H__ + +#include "udma_dev.h" +#include "udma_ctx.h" + +struct udma_jfc { + struct ubcore_jfc base; + uint32_t jfcn; + uint32_t ceqn; + uint32_t tid; + struct udma_buf buf; + struct udma_sw_db db; + uint32_t ci; + uint32_t arm_sn; /* only kernel mode use */ + spinlock_t lock; + refcount_t event_refcount; + struct completion event_comp; + uint32_t lock_free; + uint32_t inline_en; + uint32_t mode; + uint64_t stars_chnl_addr; + bool stars_en; + uint32_t cq_shift; +}; + +static inline struct udma_jfc *to_udma_jfc(struct ubcore_jfc *jfc) +{ + return container_of(jfc, struct udma_jfc, base); +} + +#endif /* __UDMA_JFC_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_jfr.h b/drivers/ub/urma/hw/udma/udma_jfr.h new file mode 100644 index 000000000000..cb1ecbaf3572 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_jfr.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_JFR_H__ +#define __UDMA_JFR_H__ + +#include "udma_dev.h" +#include "udma_ctx.h" +#include "udma_common.h" + +struct udma_jfr_idx_que { + struct udma_buf buf; + struct udma_table jfr_idx_table; +}; + +struct udma_jfr { + struct ubcore_jfr ubcore_jfr; + struct udma_jetty_queue rq; + struct udma_jfr_idx_que idx_que; + struct udma_sw_db sw_db; + struct udma_sw_db jfr_sleep_buf; + struct udma_context *udma_ctx; + uint32_t rx_threshold; + uint32_t wqe_cnt; + uint64_t jetty_addr; + enum ubcore_jfr_state state; + uint32_t max_sge; + spinlock_t lock; + refcount_t ae_refcount; + struct completion ae_comp; +}; + +static inline struct udma_jfr *to_udma_jfr(struct ubcore_jfr *jfr) +{ + return container_of(jfr, struct udma_jfr, ubcore_jfr); +} + +static inline struct udma_jfr *to_udma_jfr_from_queue(struct udma_jetty_queue *queue) +{ + return container_of(queue, struct udma_jfr, rq); +} + +#endif /* __UDMA_JFR_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 15088884080c..2088da125e0b 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -17,6 +17,7 @@ #include #include #include "udma_dev.h" +#include "udma_eq.h" #include "udma_cmd.h" #include "udma_ctx.h" #include "udma_rct.h" @@ -726,6 +727,22 @@ static struct udma_dev *udma_create_dev(struct auxiliary_device *adev) return NULL; } +static int udma_register_event(struct auxiliary_device *adev) +{ + int ret; + + ret = udma_register_ae_event(adev); + if (ret) + return ret; + + return 0; +} + +static void udma_unregister_event(struct auxiliary_device *adev) +{ + udma_unregister_ae_event(adev); +} + static bool udma_is_need_probe(struct auxiliary_device *adev) { struct udma_dev *udma_dev; @@ -783,10 +800,14 @@ static int udma_init_dev(struct auxiliary_device *adev) if (!udma_dev) goto err_create; + ret = udma_register_event(adev); + if (ret) + goto err_event_register; + ret = udma_set_ubcore_dev(udma_dev); if (ret) { dev_err(udma_dev->dev, "failed to set ubcore dev, ret is %d.\n", ret); - goto err_create; + goto err_set_ubcore_dev; } udma_register_debugfs(udma_dev); @@ -796,6 +817,10 @@ static int udma_init_dev(struct auxiliary_device *adev) return 0; +err_set_ubcore_dev: + udma_unregister_event(adev); +err_event_register: + udma_destroy_dev(udma_dev); err_create: mutex_unlock(&udma_reset_mutex); @@ -824,6 +849,7 @@ void udma_reset_down(struct auxiliary_device *adev) udma_unregister_debugfs(udma_dev); udma_unset_ubcore_dev(udma_dev); + udma_unregister_event(adev); mutex_unlock(&udma_reset_mutex); } -- Gitee From 7b0dbd3feb9ac3bb065f7278820a5ac5faa97626 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Thu, 18 Sep 2025 10:35:27 +0800 Subject: [PATCH 045/103] ub: udma: Support register and unregister ce and crq event. commit 354915ac2f4aad3d40da1d5e0a70ef8482d8de37 openEuler This patch adds the ability to register and unregister ce and crq event. In driver loading process, udma will register ce and crq event function. In driver unloading process, udma will unregister ce and crq event function. In addition, this patch adds the function of registering and unregistering workqueue. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/Makefile | 2 +- drivers/ub/urma/hw/udma/udma_cmd.c | 55 +++++ drivers/ub/urma/hw/udma/udma_cmd.h | 4 + drivers/ub/urma/hw/udma/udma_ctrlq_tp.h | 11 + drivers/ub/urma/hw/udma/udma_dev.h | 1 + drivers/ub/urma/hw/udma/udma_eq.c | 273 ++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_eq.h | 15 ++ drivers/ub/urma/hw/udma/udma_jfc.c | 52 +++++ drivers/ub/urma/hw/udma/udma_jfc.h | 3 + drivers/ub/urma/hw/udma/udma_main.c | 104 ++++++++- 10 files changed, 511 insertions(+), 9 deletions(-) create mode 100644 drivers/ub/urma/hw/udma/udma_jfc.c diff --git a/drivers/ub/urma/hw/udma/Makefile b/drivers/ub/urma/hw/udma/Makefile index ac9f9885b1e8..3a3e3f18467f 100644 --- a/drivers/ub/urma/hw/udma/Makefile +++ b/drivers/ub/urma/hw/udma/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0+ udma-$(CONFIG_UB_UDMA) := udma_main.o udma_cmd.o udma_common.o udma_ctx.o udma_db.o \ - udma_rct.o udma_tid.o udma_debugfs.o udma_eq.o + udma_rct.o udma_tid.o udma_debugfs.o udma_eq.o udma_jfc.o obj-m := udma.o diff --git a/drivers/ub/urma/hw/udma/udma_cmd.c b/drivers/ub/urma/hw/udma/udma_cmd.c index 244646f86a42..6e4c66af0537 100644 --- a/drivers/ub/urma/hw/udma/udma_cmd.c +++ b/drivers/ub/urma/hw/udma/udma_cmd.c @@ -204,5 +204,60 @@ struct ubase_cmd_mailbox *udma_mailbox_query_ctx(struct udma_dev *udma_dev, return mailbox; } +int udma_close_ue_rx(struct udma_dev *dev, bool check_feature_enable, bool check_ta_flush, + bool is_reset, uint32_t tp_num) +{ + int ret = 0; + + if (check_ta_flush) + return ret; + + if (check_feature_enable && !(dev->caps.feature & UDMA_CAP_FEATURE_UE_RX_CLOSE)) + return ret; + + mutex_lock(&dev->disable_ue_rx_mutex); + if (dev->disable_ue_rx_count == 0 && !is_reset) { + ret = ubase_deactivate_dev(dev->comdev.adev); + if (ret) { + dev_err(dev->dev, "failed to close ue rx, ret = %d.\n", ret); + goto out; + } + } + if (tp_num) + dev->disable_ue_rx_count += tp_num; + else + dev->disable_ue_rx_count++; +out: + mutex_unlock(&dev->disable_ue_rx_mutex); + + return ret; +} + +int udma_open_ue_rx(struct udma_dev *dev, bool check_feature_enable, bool check_ta_flush, + bool is_reset, uint32_t tp_num) +{ + int ret = 0; + + if (check_ta_flush) + return ret; + + if (check_feature_enable && !(dev->caps.feature & UDMA_CAP_FEATURE_UE_RX_CLOSE)) + return ret; + + mutex_lock(&dev->disable_ue_rx_mutex); + if (tp_num) + dev->disable_ue_rx_count -= tp_num; + else + dev->disable_ue_rx_count--; + if (dev->disable_ue_rx_count == 0 && !is_reset) { + ret = ubase_activate_dev(dev->comdev.adev); + if (ret) + dev_err(dev->dev, "failed to open ue rx, ret = %d.\n", ret); + } + mutex_unlock(&dev->disable_ue_rx_mutex); + + return ret; +} + module_param(debug_switch, bool, 0444); MODULE_PARM_DESC(debug_switch, "set debug print ON, default: true"); diff --git a/drivers/ub/urma/hw/udma/udma_cmd.h b/drivers/ub/urma/hw/udma/udma_cmd.h index 3dd27765fb56..fb1476350e07 100644 --- a/drivers/ub/urma/hw/udma/udma_cmd.h +++ b/drivers/ub/urma/hw/udma/udma_cmd.h @@ -237,5 +237,9 @@ int post_mailbox_update_ctx(struct udma_dev *udma_dev, void *ctx, uint32_t size, struct ubase_mbx_attr *attr); struct ubase_cmd_mailbox *udma_mailbox_query_ctx(struct udma_dev *udma_dev, struct ubase_mbx_attr *attr); +int udma_close_ue_rx(struct udma_dev *dev, bool check_feature_enable, bool check_ta_flush, + bool is_reset, uint32_t tp_num); +int udma_open_ue_rx(struct udma_dev *dev, bool check_feature_enable, bool check_ta_flush, + bool is_reset, uint32_t tp_num); #endif /* __UDMA_CMD_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_ctrlq_tp.h b/drivers/ub/urma/hw/udma/udma_ctrlq_tp.h index 93898a153a98..560f96a17919 100644 --- a/drivers/ub/urma/hw/udma/udma_ctrlq_tp.h +++ b/drivers/ub/urma/hw/udma/udma_ctrlq_tp.h @@ -8,6 +8,17 @@ #define UDMA_UE_NUM 64 +enum udma_cmd_ue_opcode { + UDMA_CMD_UBCORE_COMMAND = 0x1, + UDMA_CMD_NOTIFY_MUE_SAVE_TP = 0x2, + UDMA_CMD_NOTIFY_UE_FLUSH_DONE = 0x3, +}; + +struct udma_ue_tp_info { + uint32_t tp_cnt : 8; + uint32_t start_tpn : 24; +}; + struct udma_ue_idx_table { uint32_t num; uint8_t ue_idx[UDMA_UE_NUM]; diff --git a/drivers/ub/urma/hw/udma/udma_dev.h b/drivers/ub/urma/hw/udma/udma_dev.h index cc073ec8d97d..fd71dfe71ed1 100644 --- a/drivers/ub/urma/hw/udma/udma_dev.h +++ b/drivers/ub/urma/hw/udma/udma_dev.h @@ -99,6 +99,7 @@ struct udma_dev { struct ubase_event_nb *ae_event_addr[UBASE_EVENT_TYPE_MAX]; resource_size_t db_base; void __iomem *k_db_base; + struct workqueue_struct *act_workq; struct xarray ksva_table; struct mutex ksva_mutex; struct xarray eid_table; diff --git a/drivers/ub/urma/hw/udma/udma_eq.c b/drivers/ub/urma/hw/udma/udma_eq.c index 8ac14585ec6c..90c949c14375 100644 --- a/drivers/ub/urma/hw/udma/udma_eq.c +++ b/drivers/ub/urma/hw/udma/udma_eq.c @@ -279,3 +279,276 @@ int udma_register_ae_event(struct auxiliary_device *adev) return ret; } + +/* thanks to drivers/infiniband/hw/erdma/erdma_eq.c */ +int udma_register_ce_event(struct auxiliary_device *adev) +{ + int ret; + + ret = ubase_comp_register(adev, udma_jfc_completion); + if (ret) + dev_err(&adev->dev, + "failed to register ce event, ret: %d.\n", ret); + + return ret; +} + +static inline bool udma_check_tpn_ue_idx(struct udma_ue_idx_table *tp_ue_idx_info, + uint8_t ue_idx) +{ + int i; + + for (i = 0; i < tp_ue_idx_info->num; i++) { + if (tp_ue_idx_info->ue_idx[i] == ue_idx) + return true; + } + + return false; +} + +static int udma_save_tpn_ue_idx_info(struct udma_dev *udma_dev, uint8_t ue_idx, + uint32_t tpn) +{ + struct udma_ue_idx_table *tp_ue_idx_info; + int ret; + + xa_lock(&udma_dev->tpn_ue_idx_table); + tp_ue_idx_info = xa_load(&udma_dev->tpn_ue_idx_table, tpn); + if (tp_ue_idx_info) { + if (tp_ue_idx_info->num >= UDMA_UE_NUM) { + dev_err(udma_dev->dev, + "num exceeds the maximum value.\n"); + xa_unlock(&udma_dev->tpn_ue_idx_table); + + return -EINVAL; + } + + if (!udma_check_tpn_ue_idx(tp_ue_idx_info, ue_idx)) + tp_ue_idx_info->ue_idx[tp_ue_idx_info->num++] = ue_idx; + + xa_unlock(&udma_dev->tpn_ue_idx_table); + + return 0; + } + xa_unlock(&udma_dev->tpn_ue_idx_table); + + tp_ue_idx_info = kzalloc(sizeof(*tp_ue_idx_info), GFP_KERNEL); + if (!tp_ue_idx_info) + return -ENOMEM; + + tp_ue_idx_info->ue_idx[tp_ue_idx_info->num++] = ue_idx; + ret = xa_err(xa_store(&udma_dev->tpn_ue_idx_table, tpn, tp_ue_idx_info, + GFP_KERNEL)); + if (ret) { + dev_err(udma_dev->dev, + "store tpn ue idx table failed, ret is %d.\n", ret); + goto err_store_ue_id; + } + + return ret; + +err_store_ue_id: + kfree(tp_ue_idx_info); + return ret; +} + +static void udma_delete_tpn_ue_idx_info(struct udma_dev *udma_dev, uint32_t tpn) +{ + struct udma_ue_idx_table *tp_ue_idx_info; + + xa_lock(&udma_dev->tpn_ue_idx_table); + tp_ue_idx_info = xa_load(&udma_dev->tpn_ue_idx_table, tpn); + if (tp_ue_idx_info) { + tp_ue_idx_info->num--; + if (tp_ue_idx_info->num == 0) { + __xa_erase(&udma_dev->tpn_ue_idx_table, tpn); + kfree(tp_ue_idx_info); + } + } + xa_unlock(&udma_dev->tpn_ue_idx_table); +} + +static int udma_save_tp_info(struct udma_dev *udma_dev, struct udma_ue_tp_info *info, + uint8_t ue_idx) +{ +#define UDMA_RSP_TP_MUL 2 + uint32_t tpn; + int ret = 0; + int i; + + for (i = 0; i < info->tp_cnt * UDMA_RSP_TP_MUL; i++) { + tpn = info->start_tpn + i; + ret = udma_save_tpn_ue_idx_info(udma_dev, ue_idx, tpn); + if (ret) { + dev_err(udma_dev->dev, "save tpn info fail, ret = %d, tpn = %u.\n", + ret, tpn); + goto err_save_ue_id; + } + } + + return ret; + +err_save_ue_id: + for (i--; i >= 0; i--) { + tpn = info->start_tpn + i; + udma_delete_tpn_ue_idx_info(udma_dev, tpn); + } + + return ret; +} + +static int udma_crq_recv_req_msg(void *dev, void *data, uint32_t len) +{ + struct udma_dev *udma_dev = get_udma_dev((struct auxiliary_device *)dev); + struct udma_ue_tp_info *info; + struct udma_req_msg *req; + + if (len < sizeof(*req) + sizeof(*info)) { + dev_err(udma_dev->dev, "len of crq req is too small, len = %u.\n", len); + return -EINVAL; + } + req = (struct udma_req_msg *)data; + + if (req->resp_code != UDMA_CMD_NOTIFY_MUE_SAVE_TP) { + dev_err(udma_dev->dev, "ue to mue opcode error, opcode = %u.\n", + req->resp_code); + return -EINVAL; + } + info = (struct udma_ue_tp_info *)req->req.data; + + return udma_save_tp_info(udma_dev, info, req->dst_ue_idx); +} + +static void udma_activate_dev_work(struct work_struct *work) +{ + struct udma_flush_work *flush_work = container_of(work, struct udma_flush_work, work); + struct udma_dev *udev = flush_work->udev; + int ret; + + ret = udma_open_ue_rx(udev, true, false, false, 0); + if (ret) + dev_err(udev->dev, "udma open ue rx failed, ret = %d.\n", ret); + + kfree(flush_work); +} + +static int udma_crq_recv_resp_msg(void *dev, void *data, uint32_t len) +{ + struct udma_dev *udma_dev = get_udma_dev((struct auxiliary_device *)dev); + struct udma_flush_work *flush_work; + struct udma_resp_msg *udma_resp; + + if (len < sizeof(*udma_resp)) { + dev_err(udma_dev->dev, "len of crq resp is too small, len = %u.\n", len); + return -EINVAL; + } + udma_resp = (struct udma_resp_msg *)data; + if (udma_resp->resp_code != UDMA_CMD_NOTIFY_UE_FLUSH_DONE) { + dev_err(udma_dev->dev, "mue to ue opcode err, opcode = %u.\n", + udma_resp->resp_code); + return -EINVAL; + } + + flush_work = kzalloc(sizeof(*flush_work), GFP_ATOMIC); + if (!flush_work) + return -ENOMEM; + + flush_work->udev = udma_dev; + INIT_WORK(&flush_work->work, udma_activate_dev_work); + queue_work(udma_dev->act_workq, &flush_work->work); + + return 0; +} + +static struct ubase_crq_event_nb udma_crq_opts[] = { + {UBASE_OPC_UE_TO_MUE, NULL, udma_crq_recv_req_msg}, + {UBASE_OPC_MUE_TO_UE, NULL, udma_crq_recv_resp_msg}, +}; + +void udma_unregister_crq_event(struct auxiliary_device *adev) +{ + struct udma_dev *udma_dev = get_udma_dev(adev); + struct ubase_crq_event_nb *nb = NULL; + size_t index; + + xa_for_each(&udma_dev->crq_nb_table, index, nb) { + xa_erase(&udma_dev->crq_nb_table, index); + ubase_unregister_crq_event(adev, nb->opcode); + kfree(nb); + nb = NULL; + } +} + +static int udma_register_one_crq_event(struct auxiliary_device *adev, + struct ubase_crq_event_nb *crq_nb, + uint32_t index) +{ + struct udma_dev *udma_dev = get_udma_dev(adev); + struct ubase_crq_event_nb *nb; + int ret; + + nb = kzalloc(sizeof(*nb), GFP_KERNEL); + if (!nb) + return -ENOMEM; + + nb->opcode = crq_nb->opcode; + nb->back = adev; + nb->crq_handler = crq_nb->crq_handler; + ret = ubase_register_crq_event(adev, nb); + if (ret) { + dev_err(udma_dev->dev, + "register crq event failed, opcode is %u, ret is %d.\n", + nb->opcode, ret); + goto err_register_crq_event; + } + + ret = xa_err(xa_store(&udma_dev->crq_nb_table, index, nb, GFP_KERNEL)); + if (ret) { + dev_err(udma_dev->dev, + "save crq nb entry failed, opcode is %u, ret is %d.\n", + nb->opcode, ret); + goto err_store_crq_nb; + } + + return ret; + +err_store_crq_nb: + ubase_unregister_crq_event(adev, nb->opcode); +err_register_crq_event: + kfree(nb); + return ret; +} + +int udma_register_crq_event(struct auxiliary_device *adev) +{ + uint32_t opt_num = sizeof(udma_crq_opts) / sizeof(struct ubase_crq_event_nb); + uint32_t index; + int ret = 0; + + for (index = 0; index < opt_num; ++index) { + ret = udma_register_one_crq_event(adev, &udma_crq_opts[index], index); + if (ret) { + udma_unregister_crq_event(adev); + break; + } + } + + return ret; +} + +int udma_register_activate_workqueue(struct udma_dev *udma_dev) +{ + udma_dev->act_workq = alloc_workqueue("udma_activate_workq", WQ_UNBOUND, 0); + if (!udma_dev->act_workq) { + dev_err(udma_dev->dev, "failed to create activate workqueue.\n"); + return -ENOMEM; + } + + return 0; +} + +void udma_unregister_activate_workqueue(struct udma_dev *udma_dev) +{ + flush_workqueue(udma_dev->act_workq); + destroy_workqueue(udma_dev->act_workq); +} diff --git a/drivers/ub/urma/hw/udma/udma_eq.h b/drivers/ub/urma/hw/udma/udma_eq.h index f771483e168f..336a8544cb9d 100644 --- a/drivers/ub/urma/hw/udma/udma_eq.h +++ b/drivers/ub/urma/hw/udma/udma_eq.h @@ -6,5 +6,20 @@ int udma_register_ae_event(struct auxiliary_device *adev); void udma_unregister_ae_event(struct auxiliary_device *adev); +int udma_register_ce_event(struct auxiliary_device *adev); +void udma_unregister_crq_event(struct auxiliary_device *adev); +int udma_register_crq_event(struct auxiliary_device *adev); +int udma_register_activate_workqueue(struct udma_dev *udma_dev); +void udma_unregister_activate_workqueue(struct udma_dev *udma_dev); + +static inline void udma_unregister_ce_event(struct auxiliary_device *adev) +{ + ubase_comp_unregister(adev); +} + +struct udma_flush_work { + struct udma_dev *udev; + struct work_struct work; +}; #endif /* __UDMA_EQ_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_jfc.c b/drivers/ub/urma/hw/udma/udma_jfc.c new file mode 100644 index 000000000000..ee223bb923f6 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_jfc.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt + +#include +#include +#include +#include +#include +#include "udma_cmd.h" +#include "udma_common.h" +#include "udma_jetty.h" +#include "udma_jfr.h" +#include "udma_jfs.h" +#include "udma_ctx.h" +#include "udma_db.h" +#include +#include "udma_jfc.h" + +int udma_jfc_completion(struct notifier_block *nb, unsigned long jfcn, + void *data) +{ + struct auxiliary_device *adev = (struct auxiliary_device *)data; + struct udma_dev *udma_dev = get_udma_dev(adev); + struct ubcore_jfc *ubcore_jfc; + struct udma_jfc *udma_jfc; + + xa_lock(&udma_dev->jfc_table.xa); + udma_jfc = (struct udma_jfc *)xa_load(&udma_dev->jfc_table.xa, jfcn); + if (!udma_jfc) { + dev_warn(udma_dev->dev, + "Completion event for bogus jfcn %lu.\n", jfcn); + xa_unlock(&udma_dev->jfc_table.xa); + return -EINVAL; + } + + ++udma_jfc->arm_sn; + + ubcore_jfc = &udma_jfc->base; + if (ubcore_jfc->jfce_handler) { + refcount_inc(&udma_jfc->event_refcount); + xa_unlock(&udma_dev->jfc_table.xa); + ubcore_jfc->jfce_handler(ubcore_jfc); + if (refcount_dec_and_test(&udma_jfc->event_refcount)) + complete(&udma_jfc->event_comp); + } else { + xa_unlock(&udma_dev->jfc_table.xa); + } + + return 0; +} diff --git a/drivers/ub/urma/hw/udma/udma_jfc.h b/drivers/ub/urma/hw/udma/udma_jfc.h index 3841049c28a0..e225efdece4c 100644 --- a/drivers/ub/urma/hw/udma/udma_jfc.h +++ b/drivers/ub/urma/hw/udma/udma_jfc.h @@ -32,4 +32,7 @@ static inline struct udma_jfc *to_udma_jfc(struct ubcore_jfc *jfc) return container_of(jfc, struct udma_jfc, base); } +int udma_jfc_completion(struct notifier_block *nb, unsigned long jfcn, + void *data); + #endif /* __UDMA_JFC_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 2088da125e0b..0393cc0ba18b 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -735,11 +735,28 @@ static int udma_register_event(struct auxiliary_device *adev) if (ret) return ret; + ret = udma_register_ce_event(adev); + if (ret) + goto err_ce_register; + + ret = udma_register_crq_event(adev); + if (ret) + goto err_crq_register; + return 0; + +err_crq_register: + udma_unregister_ce_event(adev); +err_ce_register: + udma_unregister_ae_event(adev); + + return ret; } static void udma_unregister_event(struct auxiliary_device *adev) { + udma_unregister_crq_event(adev); + udma_unregister_ce_event(adev); udma_unregister_ae_event(adev); } @@ -765,6 +782,26 @@ static bool udma_is_need_probe(struct auxiliary_device *adev) return true; } +static void udma_report_reset_event(enum ubcore_event_type event_type, + struct udma_dev *udma_dev) +{ + struct ubcore_event ae = {}; + + ae.ub_dev = &udma_dev->ub_dev; + ae.event_type = event_type; + + if (event_type == UBCORE_EVENT_ELR_ERR) + dev_info(udma_dev->dev, + "udma report reset event elr_err, matched udma dev(%s).\n", + udma_dev->dev_name); + else if (event_type == UBCORE_EVENT_ELR_DONE) + dev_info(udma_dev->dev, + "udma report reset event elr_done, matched udma dev(%s).\n", + udma_dev->dev_name); + + ubcore_dispatch_async_event(&ae); +} + static void udma_reset_handler(struct auxiliary_device *adev, enum ubase_reset_stage stage) { @@ -804,6 +841,12 @@ static int udma_init_dev(struct auxiliary_device *adev) if (ret) goto err_event_register; + ret = udma_register_activate_workqueue(udma_dev); + if (ret) { + dev_err(udma_dev->dev, "UDMA activate workqueue failed.\n"); + goto err_register_act_init; + } + ret = udma_set_ubcore_dev(udma_dev); if (ret) { dev_err(udma_dev->dev, "failed to set ubcore dev, ret is %d.\n", ret); @@ -818,6 +861,8 @@ static int udma_init_dev(struct auxiliary_device *adev) return 0; err_set_ubcore_dev: + udma_unregister_activate_workqueue(udma_dev); +err_register_act_init: udma_unregister_event(adev); err_event_register: udma_destroy_dev(udma_dev); @@ -827,6 +872,24 @@ static int udma_init_dev(struct auxiliary_device *adev) return -EINVAL; } +static void check_and_wait_flush_done(struct udma_dev *udma_dev) +{ +#define WAIT_MAX_TIMES 15 + uint32_t wait_times = 0; + + while (true) { + if (udma_dev->disable_ue_rx_count == 1) + break; + + if (wait_times > WAIT_MAX_TIMES) { + dev_warn(udma_dev->dev, "wait flush done timeout.\n"); + break; + } + msleep(1 << wait_times); + wait_times++; + } +} + void udma_reset_down(struct auxiliary_device *adev) { struct udma_dev *udma_dev; @@ -845,11 +908,15 @@ void udma_reset_down(struct auxiliary_device *adev) return; } - udma_dev->status = UDMA_SUSPEND; + ubcore_stop_requests(&udma_dev->ub_dev); + if (udma_close_ue_rx(udma_dev, false, false, true, 0)) { + mutex_unlock(&udma_reset_mutex); + dev_err(&adev->dev, "udma close ue rx failed in reset down process.\n"); + return; + } - udma_unregister_debugfs(udma_dev); - udma_unset_ubcore_dev(udma_dev); - udma_unregister_event(adev); + udma_report_reset_event(UBCORE_EVENT_ELR_ERR, udma_dev); + udma_dev->status = UDMA_SUSPEND; mutex_unlock(&udma_reset_mutex); } @@ -871,6 +938,11 @@ void udma_reset_uninit(struct auxiliary_device *adev) return; } + udma_unset_ubcore_dev(udma_dev); + udma_unregister_debugfs(udma_dev); + udma_unregister_activate_workqueue(udma_dev); + udma_open_ue_rx(udma_dev, false, false, true, 0); + udma_unregister_event(adev); udma_destroy_dev(udma_dev); mutex_unlock(&udma_reset_mutex); } @@ -894,17 +966,33 @@ void udma_remove(struct auxiliary_device *adev) { struct udma_dev *udma_dev; + mutex_lock(&udma_reset_mutex); + ubase_reset_unregister(adev); udma_dev = get_udma_dev(adev); if (!udma_dev) { + mutex_unlock(&udma_reset_mutex); dev_info(&adev->dev, "udma device is not exist.\n"); - ubase_reset_unregister(adev); return; } - udma_reset_down(adev); - udma_reset_uninit(adev); + ubcore_stop_requests(&udma_dev->ub_dev); + if (udma_close_ue_rx(udma_dev, false, false, false, 0)) { + mutex_unlock(&udma_reset_mutex); + dev_err(&adev->dev, "udma close ue rx failed in remove process.\n"); + return; + } - ubase_reset_unregister(adev); + udma_dev->status = UDMA_SUSPEND; + udma_report_reset_event(UBCORE_EVENT_ELR_ERR, udma_dev); + + udma_unset_ubcore_dev(udma_dev); + udma_unregister_debugfs(udma_dev); + udma_unregister_activate_workqueue(udma_dev); + check_and_wait_flush_done(udma_dev); + (void)ubase_activate_dev(adev); + udma_unregister_event(adev); + udma_destroy_dev(udma_dev); + mutex_unlock(&udma_reset_mutex); } static struct auxiliary_driver udma_drv = { -- Gitee From 30f966046d963cbecda44cd40b30a4b932d2dd4c Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Thu, 18 Sep 2025 10:49:46 +0800 Subject: [PATCH 046/103] ub: udma: Support register and unregister ctrlq event. commit af4f2c7d6ea264e66f6e3410cbb1b8b2e9ea59a3 openEuler This patch adds the ability to register and unregister ctrlq event. In driver loading process, udma will register ctrlq event function. In driver unloading process, udma will unregister ctrlq event function. In addition, this patch adds the function of querying ae aux info from ubase. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/Makefile | 3 +- drivers/ub/urma/hw/udma/udma_cmd.h | 46 ++++ drivers/ub/urma/hw/udma/udma_common.c | 8 + drivers/ub/urma/hw/udma/udma_common.h | 9 + drivers/ub/urma/hw/udma/udma_ctl.c | 210 +++++++++++++++++ drivers/ub/urma/hw/udma/udma_ctrlq_tp.c | 147 ++++++++++++ drivers/ub/urma/hw/udma/udma_ctrlq_tp.h | 80 +++++++ drivers/ub/urma/hw/udma/udma_dev.h | 2 + drivers/ub/urma/hw/udma/udma_eid.c | 98 ++++++++ drivers/ub/urma/hw/udma/udma_eid.h | 13 ++ drivers/ub/urma/hw/udma/udma_eq.c | 295 ++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_eq.h | 2 + drivers/ub/urma/hw/udma/udma_main.c | 30 +++ 13 files changed, 942 insertions(+), 1 deletion(-) create mode 100644 drivers/ub/urma/hw/udma/udma_ctl.c create mode 100644 drivers/ub/urma/hw/udma/udma_ctrlq_tp.c create mode 100644 drivers/ub/urma/hw/udma/udma_eid.c create mode 100644 drivers/ub/urma/hw/udma/udma_eid.h diff --git a/drivers/ub/urma/hw/udma/Makefile b/drivers/ub/urma/hw/udma/Makefile index 3a3e3f18467f..2739d92c115e 100644 --- a/drivers/ub/urma/hw/udma/Makefile +++ b/drivers/ub/urma/hw/udma/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+ udma-$(CONFIG_UB_UDMA) := udma_main.o udma_cmd.o udma_common.o udma_ctx.o udma_db.o \ - udma_rct.o udma_tid.o udma_debugfs.o udma_eq.o udma_jfc.o + udma_rct.o udma_tid.o udma_debugfs.o udma_eq.o udma_jfc.o \ + udma_ctrlq_tp.o udma_eid.o udma_ctl.o obj-m := udma.o diff --git a/drivers/ub/urma/hw/udma/udma_cmd.h b/drivers/ub/urma/hw/udma/udma_cmd.h index fb1476350e07..6ec531913033 100644 --- a/drivers/ub/urma/hw/udma/udma_cmd.h +++ b/drivers/ub/urma/hw/udma/udma_cmd.h @@ -19,12 +19,44 @@ extern bool debug_switch; #define SPEED_50G 50000 #define SPEED_25G 25000 +#define UDMA_CTRLQ_SEID_NUM 64 + struct udma_ctrlq_eid_info { uint32_t eid_idx; union ubcore_eid eid; uint32_t upi; } __packed; +struct udma_ctrlq_eid_in_query { + uint32_t cmd : 8; + uint32_t rsv : 24; +}; + +struct udma_ctrlq_eid_out_query { + uint32_t seid_num : 8; + uint32_t rsv : 24; + struct udma_ctrlq_eid_info eids[UDMA_CTRLQ_SEID_NUM]; +} __packed; + +struct udma_ctrlq_eid_out_update { + struct udma_ctrlq_eid_info eid_info; + uint32_t op_type : 4; + uint32_t rsv : 28; +} __packed; + +enum udma_ctrlq_eid_update_op { + UDMA_CTRLQ_EID_ADD = 0, + UDMA_CTRLQ_EID_DEL, +}; + +enum udma_ctrlq_dev_mgmt_opcode { + UDMA_CTRLQ_GET_SEID_INFO = 0x1, + UDMA_CTRLQ_UPDATE_SEID_INFO = 0x2, + UDMA_CTRLQ_GET_DEV_RESOURCE_COUNT = 0x11, + UDMA_CTRLQ_GET_DEV_RESOURCE_RATIO = 0x12, + UDMA_CTRLQ_NOTIFY_DEV_RESOURCE_RATIO = 0x13, +}; + enum udma_cmd_opcode_type { UDMA_CMD_QUERY_UE_RES = 0x0002, UDMA_CMD_QUERY_UE_INDEX = 0x241d, @@ -213,6 +245,20 @@ struct udma_cmd_wqebb_va { uint32_t ue_num; }; +struct udma_cmd_query_cqe_aux_info { + uint32_t status : 8; + uint32_t is_client : 1; + uint32_t rsvd : 23; + uint32_t cqe_aux_info[MAX_CQE_AUX_INFO_TYPE_NUM]; +}; + +struct udma_cmd_query_ae_aux_info { + uint32_t event_type : 8; + uint32_t sub_type : 8; + uint32_t rsvd : 16; + uint32_t ae_aux_info[MAX_AE_AUX_INFO_TYPE_NUM]; +}; + static inline void udma_fill_buf(struct ubase_cmd_buf *buf, u16 opcode, bool is_read, u32 data_size, void *data) { diff --git a/drivers/ub/urma/hw/udma/udma_common.c b/drivers/ub/urma/hw/udma/udma_common.c index d313e1d17443..4b4ccc22124a 100644 --- a/drivers/ub/urma/hw/udma/udma_common.c +++ b/drivers/ub/urma/hw/udma/udma_common.c @@ -578,3 +578,11 @@ void udma_free_iova(struct udma_dev *udma_dev, size_t memory_size, void *kva_or_ dma_free_iova(slot); } + +void udma_swap_endian(uint8_t arr[], uint8_t res[], uint32_t res_size) +{ + uint32_t i; + + for (i = 0; i < res_size; i++) + res[i] = arr[res_size - i - 1]; +} diff --git a/drivers/ub/urma/hw/udma/udma_common.h b/drivers/ub/urma/hw/udma/udma_common.h index c6e83a0d84c3..3cec74f9ec8e 100644 --- a/drivers/ub/urma/hw/udma/udma_common.h +++ b/drivers/ub/urma/hw/udma/udma_common.h @@ -46,6 +46,13 @@ struct udma_jetty_queue { enum udma_jetty_type jetty_type; }; +enum tp_state { + TP_INVALID = 0x0, + TP_VALID = 0x1, + TP_RTS = 0x3, + TP_ERROR = 0x6, +}; + int pin_queue_addr(struct udma_dev *dev, uint64_t addr, uint32_t len, struct udma_buf *buf); void unpin_queue_addr(struct ubcore_umem *umem); @@ -75,4 +82,6 @@ static inline uint64_t udma_cal_npages(uint64_t va, uint64_t len) return (ALIGN(va + len, PAGE_SIZE) - ALIGN_DOWN(va, PAGE_SIZE)) / PAGE_SIZE; } +void udma_swap_endian(uint8_t arr[], uint8_t res[], uint32_t res_size); + #endif /* __UDMA_COMM_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_ctl.c b/drivers/ub/urma/hw/udma/udma_ctl.c new file mode 100644 index 000000000000..8b709dc10a20 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_ctl.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt + +#include +#include +#include +#include "udma_common.h" +#include "udma_dev.h" +#include +#include "udma_cmd.h" +#include "udma_jetty.h" +#include "udma_jfs.h" +#include "udma_jfc.h" +#include "udma_db.h" +#include "udma_ctrlq_tp.h" +#include +#include "udma_def.h" + +static int to_hw_ae_event_type(struct udma_dev *udma_dev, uint32_t event_type, + struct udma_cmd_query_ae_aux_info *info) +{ + switch (event_type) { + case UBCORE_EVENT_TP_FLUSH_DONE: + info->event_type = UBASE_EVENT_TYPE_TP_FLUSH_DONE; + break; + case UBCORE_EVENT_TP_ERR: + info->event_type = UBASE_EVENT_TYPE_TP_LEVEL_ERROR; + break; + case UBCORE_EVENT_JFS_ERR: + case UBCORE_EVENT_JETTY_ERR: + info->event_type = UBASE_EVENT_TYPE_JETTY_LEVEL_ERROR; + info->sub_type = UBASE_SUBEVENT_TYPE_JFS_CHECK_ERROR; + break; + case UBCORE_EVENT_JFC_ERR: + info->event_type = UBASE_EVENT_TYPE_JETTY_LEVEL_ERROR; + info->sub_type = UBASE_SUBEVENT_TYPE_JFC_CHECK_ERROR; + break; + default: + dev_err(udma_dev->dev, "Invalid event type %u.\n", event_type); + return -EINVAL; + } + + return 0; +} + +static int send_cmd_query_ae_aux_info(struct udma_dev *udma_dev, + struct udma_cmd_query_ae_aux_info *info) +{ + struct ubase_cmd_buf cmd_in, cmd_out; + int ret; + + udma_fill_buf(&cmd_in, UDMA_CMD_GET_AE_AUX_INFO, true, + sizeof(struct udma_cmd_query_ae_aux_info), info); + udma_fill_buf(&cmd_out, UDMA_CMD_GET_AE_AUX_INFO, true, + sizeof(struct udma_cmd_query_ae_aux_info), info); + + ret = ubase_cmd_send_inout(udma_dev->comdev.adev, &cmd_in, &cmd_out); + if (ret) + dev_err(udma_dev->dev, + "failed to query ae aux info, ret = %d.\n", ret); + + return ret; +} + +static void free_kernel_ae_aux_info(struct udma_ae_aux_info_out *user_aux_info_out, + struct udma_ae_aux_info_out *aux_info_out) +{ + if (!user_aux_info_out->aux_info_type) + return; + + kfree(aux_info_out->aux_info_type); + aux_info_out->aux_info_type = NULL; + + kfree(aux_info_out->aux_info_value); + aux_info_out->aux_info_value = NULL; +} + +static int copy_out_ae_data_from_user(struct udma_dev *udma_dev, + struct ubcore_user_ctl_out *out, + struct udma_ae_aux_info_out *aux_info_out, + struct ubcore_ucontext *uctx, + struct udma_ae_aux_info_out *user_aux_info_out) +{ + if (out->addr != 0 && out->len == sizeof(struct udma_ae_aux_info_out)) { + memcpy(aux_info_out, (void *)(uintptr_t)out->addr, + sizeof(struct udma_ae_aux_info_out)); + if (uctx && aux_info_out->aux_info_num > 0 && + aux_info_out->aux_info_type != NULL && + aux_info_out->aux_info_value != NULL) { + if (aux_info_out->aux_info_num > MAX_AE_AUX_INFO_TYPE_NUM) { + dev_err(udma_dev->dev, + "invalid ae aux info num %u.\n", + aux_info_out->aux_info_num); + return -EINVAL; + } + + user_aux_info_out->aux_info_type = aux_info_out->aux_info_type; + user_aux_info_out->aux_info_value = aux_info_out->aux_info_value; + aux_info_out->aux_info_type = + kcalloc(aux_info_out->aux_info_num, + sizeof(enum udma_ae_aux_info_type), GFP_KERNEL); + if (!aux_info_out->aux_info_type) + return -ENOMEM; + + aux_info_out->aux_info_value = + kcalloc(aux_info_out->aux_info_num, + sizeof(uint32_t), GFP_KERNEL); + if (!aux_info_out->aux_info_value) { + kfree(aux_info_out->aux_info_type); + return -ENOMEM; + } + } + } + + return 0; +} + +static int copy_out_ae_data_to_user(struct udma_dev *udma_dev, + struct ubcore_user_ctl_out *out, + struct udma_ae_aux_info_out *aux_info_out, + struct ubcore_ucontext *uctx, + struct udma_ae_aux_info_out *user_aux_info_out) +{ + unsigned long byte; + + if (out->addr != 0 && out->len == sizeof(struct udma_ae_aux_info_out)) { + if (uctx && aux_info_out->aux_info_num > 0 && + aux_info_out->aux_info_type != NULL && + aux_info_out->aux_info_value != NULL) { + byte = copy_to_user((void __user *)user_aux_info_out->aux_info_type, + (void *)aux_info_out->aux_info_type, + aux_info_out->aux_info_num * + sizeof(enum udma_ae_aux_info_type)); + if (byte) { + dev_err(udma_dev->dev, + "copy resp to aux info type failed, byte = %lu.\n", byte); + return -EFAULT; + } + + byte = copy_to_user((void __user *)user_aux_info_out->aux_info_value, + (void *)aux_info_out->aux_info_value, + aux_info_out->aux_info_num * + sizeof(uint32_t)); + if (byte) { + dev_err(udma_dev->dev, + "copy resp to aux info value failed, byte = %lu.\n", byte); + return -EFAULT; + } + + kfree(aux_info_out->aux_info_type); + kfree(aux_info_out->aux_info_value); + aux_info_out->aux_info_type = user_aux_info_out->aux_info_type; + aux_info_out->aux_info_value = user_aux_info_out->aux_info_value; + } + memcpy((void *)(uintptr_t)out->addr, aux_info_out, + sizeof(struct udma_ae_aux_info_out)); + } + + return 0; +} + +int udma_query_ae_aux_info(struct ubcore_device *dev, struct ubcore_ucontext *uctx, + struct ubcore_user_ctl_in *in, + struct ubcore_user_ctl_out *out) +{ + struct udma_ae_aux_info_out user_aux_info_out = {}; + struct udma_ae_aux_info_out aux_info_out = {}; + struct udma_dev *udma_dev = to_udma_dev(dev); + struct udma_cmd_query_ae_aux_info info = {}; + struct udma_ae_info_in ae_info_in = {}; + int ret; + + if (udma_check_base_param(in->addr, in->len, sizeof(struct udma_ae_info_in))) { + dev_err(udma_dev->dev, "parameter invalid in query ae aux info, in_len = %u.\n", + in->len); + return -EINVAL; + } + memcpy(&ae_info_in, (void *)(uintptr_t)in->addr, + sizeof(struct udma_ae_info_in)); + ret = to_hw_ae_event_type(udma_dev, ae_info_in.event_type, &info); + if (ret) + return ret; + + ret = copy_out_ae_data_from_user(udma_dev, out, &aux_info_out, uctx, &user_aux_info_out); + if (ret) { + dev_err(udma_dev->dev, + "copy out data from user failed, ret = %d.\n", ret); + return ret; + } + + ret = send_cmd_query_ae_aux_info(udma_dev, &info); + if (ret) { + dev_err(udma_dev->dev, + "send cmd query aux info failed, ret = %d.\n", + ret); + free_kernel_ae_aux_info(&user_aux_info_out, &aux_info_out); + return ret; + } + + ret = copy_out_ae_data_to_user(udma_dev, out, &aux_info_out, uctx, &user_aux_info_out); + if (ret) { + dev_err(udma_dev->dev, + "copy out data to user failed, ret = %d.\n", ret); + free_kernel_ae_aux_info(&user_aux_info_out, &aux_info_out); + } + + return ret; +} diff --git a/drivers/ub/urma/hw/udma/udma_ctrlq_tp.c b/drivers/ub/urma/hw/udma/udma_ctrlq_tp.c new file mode 100644 index 000000000000..af1732e1629b --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_ctrlq_tp.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt + +#include +#include +#include +#include +#include "udma_cmd.h" +#include +#include "udma_common.h" +#include "udma_ctrlq_tp.h" + +static void udma_ctrlq_set_tp_msg(struct ubase_ctrlq_msg *msg, void *in, + uint16_t in_len, void *out, uint16_t out_len) +{ + msg->service_ver = UBASE_CTRLQ_SER_VER_01; + msg->service_type = UBASE_CTRLQ_SER_TYPE_TP_ACL; + msg->need_resp = 1; + msg->is_resp = 0; + msg->in_size = in_len; + msg->in = in; + msg->out_size = out_len; + msg->out = out; +} + +int udma_ctrlq_remove_single_tp(struct udma_dev *udev, uint32_t tpn, int status) +{ + struct udma_ctrlq_remove_single_tp_req_data tp_cfg_req = {}; + struct ubase_ctrlq_msg msg = {}; + int r_status = 0; + int ret; + + tp_cfg_req.tpn = tpn; + tp_cfg_req.tp_status = (uint32_t)status; + msg.opcode = UDMA_CMD_CTRLQ_REMOVE_SINGLE_TP; + udma_ctrlq_set_tp_msg(&msg, (void *)&tp_cfg_req, + sizeof(tp_cfg_req), &r_status, sizeof(int)); + + ret = ubase_ctrlq_send_msg(udev->comdev.adev, &msg); + if (ret) + dev_err(udev->dev, "remove single tp %u failed, ret %d status %d.\n", + tpn, ret, r_status); + + return ret; +} + +static int udma_send_req_to_ue(struct udma_dev *udma_dev, uint8_t ue_idx) +{ + struct ubcore_resp *ubcore_req; + int ret; + + ubcore_req = kzalloc(sizeof(*ubcore_req), GFP_KERNEL); + if (!ubcore_req) + return -ENOMEM; + + ret = send_resp_to_ue(udma_dev, ubcore_req, ue_idx, + UDMA_CMD_NOTIFY_UE_FLUSH_DONE); + if (ret) + dev_err(udma_dev->dev, "fail to notify ue the tp flush done, ret %d.\n", ret); + + kfree(ubcore_req); + + return ret; +} + +static struct udma_ue_idx_table *udma_find_ue_idx_by_tpn(struct udma_dev *udev, + uint32_t tpn) +{ + struct udma_ue_idx_table *tp_ue_idx_info; + + xa_lock(&udev->tpn_ue_idx_table); + tp_ue_idx_info = xa_load(&udev->tpn_ue_idx_table, tpn); + if (!tp_ue_idx_info) { + dev_warn(udev->dev, "ue idx info not exist, tpn %u.\n", tpn); + xa_unlock(&udev->tpn_ue_idx_table); + + return NULL; + } + + __xa_erase(&udev->tpn_ue_idx_table, tpn); + xa_unlock(&udev->tpn_ue_idx_table); + + return tp_ue_idx_info; +} + +int udma_ctrlq_tp_flush_done(struct udma_dev *udev, uint32_t tpn) +{ + struct udma_ctrlq_tp_flush_done_req_data tp_cfg_req = {}; + struct udma_ue_idx_table *tp_ue_idx_info; + struct ubase_ctrlq_msg msg = {}; + int ret = 0; + uint32_t i; + + tp_ue_idx_info = udma_find_ue_idx_by_tpn(udev, tpn); + if (tp_ue_idx_info) { + for (i = 0; i < tp_ue_idx_info->num; i++) + (void)udma_send_req_to_ue(udev, tp_ue_idx_info->ue_idx[i]); + + kfree(tp_ue_idx_info); + } else { + ret = udma_open_ue_rx(udev, true, false, false, 0); + if (ret) + dev_err(udev->dev, "udma open ue rx failed in tp flush done.\n"); + } + + tp_cfg_req.tpn = tpn; + msg.opcode = UDMA_CMD_CTRLQ_TP_FLUSH_DONE; + udma_ctrlq_set_tp_msg(&msg, (void *)&tp_cfg_req, sizeof(tp_cfg_req), NULL, 0); + ret = ubase_ctrlq_send_msg(udev->comdev.adev, &msg); + if (ret) + dev_err(udev->dev, "tp flush done ctrlq tp %u failed, ret %d.\n", tpn, ret); + + return ret; +} + +int send_resp_to_ue(struct udma_dev *udma_dev, struct ubcore_resp *req_host, + uint8_t dst_ue_idx, uint16_t opcode) +{ + struct udma_resp_msg *udma_req; + struct ubase_cmd_buf in; + uint32_t msg_len; + int ret; + + msg_len = sizeof(*udma_req) + req_host->len; + udma_req = kzalloc(msg_len, GFP_KERNEL); + if (!udma_req) + return -ENOMEM; + + udma_req->dst_ue_idx = dst_ue_idx; + udma_req->resp_code = opcode; + + (void)memcpy(&udma_req->resp, req_host, sizeof(*req_host)); + (void)memcpy(udma_req->resp.data, req_host->data, req_host->len); + + udma_fill_buf(&in, UBASE_OPC_MUE_TO_UE, false, msg_len, udma_req); + + ret = ubase_cmd_send_in(udma_dev->comdev.adev, &in); + if (ret) + dev_err(udma_dev->dev, + "send resp msg cmd failed, ret is %d.\n", ret); + + kfree(udma_req); + + return ret; +} diff --git a/drivers/ub/urma/hw/udma/udma_ctrlq_tp.h b/drivers/ub/urma/hw/udma/udma_ctrlq_tp.h index 560f96a17919..6672f8ea01ec 100644 --- a/drivers/ub/urma/hw/udma/udma_ctrlq_tp.h +++ b/drivers/ub/urma/hw/udma/udma_ctrlq_tp.h @@ -6,8 +6,79 @@ #include "udma_common.h" +#define UDMA_EID_SIZE 16 +#define UDMA_CNA_SIZE 16 #define UDMA_UE_NUM 64 +enum udma_ctrlq_cmd_code_type { + UDMA_CMD_CTRLQ_REMOVE_SINGLE_TP = 0x13, + UDMA_CMD_CTRLQ_TP_FLUSH_DONE, + UDMA_CMD_CTRLQ_CHECK_TP_ACTIVE, + UDMA_CMD_CTRLQ_GET_TP_LIST = 0x21, + UDMA_CMD_CTRLQ_ACTIVE_TP, + UDMA_CMD_CTRLQ_DEACTIVE_TP, + UDMA_CMD_CTRLQ_SET_TP_ATTR, + UDMA_CMD_CTRLQ_GET_TP_ATTR, + UDMA_CMD_CTRLQ_MAX +}; + +enum udma_ctrlq_trans_type { + UDMA_CTRLQ_TRANS_TYPE_TP_RM = 0, + UDMA_CTRLQ_TRANS_TYPE_CTP, + UDMA_CTRLQ_TRANS_TYPE_TP_UM, + UDMA_CTRLQ_TRANS_TYPE_TP_RC = 4, + UDMA_CTRLQ_TRANS_TYPE_MAX +}; + +enum udma_ctrlq_tpid_status { + UDMA_CTRLQ_TPID_IN_USE = 0, + UDMA_CTRLQ_TPID_EXITED, + UDMA_CTRLQ_TPID_IDLE, +}; + +struct udma_ctrlq_tp_flush_done_req_data { + uint32_t tpn : 24; + uint32_t rsv : 8; +}; + +struct udma_ctrlq_remove_single_tp_req_data { + uint32_t tpn : 24; + uint32_t tp_status : 8; +}; + +struct udma_ctrlq_tpn_data { + uint32_t tpg_flag : 8; + uint32_t rsv : 24; + uint32_t tpgn : 24; + uint32_t rsv1 : 8; + uint32_t tpn_cnt : 8; + uint32_t start_tpn : 24; +}; + +struct udma_ctrlq_check_tp_active_req_data { + uint32_t tp_id : 24; + uint32_t rsv : 8; + uint32_t pid_flag : 24; + uint32_t rsv1 : 8; +}; + +struct udma_ctrlq_check_tp_active_req_info { + uint32_t num : 8; + uint32_t rsv : 24; + struct udma_ctrlq_check_tp_active_req_data data[]; +}; + +struct udma_ctrlq_check_tp_active_rsp_data { + uint32_t tp_id : 24; + uint32_t result : 8; +}; + +struct udma_ctrlq_check_tp_active_rsp_info { + uint32_t num : 8; + uint32_t rsv : 24; + struct udma_ctrlq_check_tp_active_rsp_data data[]; +}; + enum udma_cmd_ue_opcode { UDMA_CMD_UBCORE_COMMAND = 0x1, UDMA_CMD_NOTIFY_MUE_SAVE_TP = 0x2, @@ -24,4 +95,13 @@ struct udma_ue_idx_table { uint8_t ue_idx[UDMA_UE_NUM]; }; +struct udma_notify_flush_done { + uint32_t tpn; +}; + +int udma_ctrlq_tp_flush_done(struct udma_dev *udev, uint32_t tpn); +int udma_ctrlq_remove_single_tp(struct udma_dev *udev, uint32_t tpn, int status); +int send_resp_to_ue(struct udma_dev *udma_dev, struct ubcore_resp *req_host, + uint8_t dst_ue_idx, uint16_t opcode); + #endif /* __UDMA_CTRLQ_TP_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_dev.h b/drivers/ub/urma/hw/udma/udma_dev.h index fd71dfe71ed1..89b91ff08e79 100644 --- a/drivers/ub/urma/hw/udma/udma_dev.h +++ b/drivers/ub/urma/hw/udma/udma_dev.h @@ -27,6 +27,8 @@ extern bool dump_aux_info; #define UDMA_DEV_UE_NUM 47 +#define SEID_TABLE_SIZE 1024 + #define UDMA_MAX_SL_NUM 16 #define UDMA_DEFAULT_SL_NUM 0 diff --git a/drivers/ub/urma/hw/udma/udma_eid.c b/drivers/ub/urma/hw/udma/udma_eid.c new file mode 100644 index 000000000000..ad88d7eec976 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_eid.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt + +#include +#include +#include +#include "udma_dev.h" +#include "udma_cmd.h" +#include "udma_common.h" +#include +#include "udma_eid.h" + +static void udma_dispatch_eid_event(struct udma_dev *udma_dev, + struct udma_ctrlq_eid_info *eid_entry, + enum ubcore_mgmt_event_type type) +{ + struct ubcore_mgmt_event event = {}; + struct ubcore_eid_info info = {}; + + udma_swap_endian(eid_entry->eid.raw, info.eid.raw, sizeof(union ubcore_eid)); + info.eid_index = eid_entry->eid_idx; + + event.ub_dev = &udma_dev->ub_dev; + event.element.eid_info = &info; + event.event_type = type; + ubcore_dispatch_mgmt_event(&event); +} + +int udma_add_one_eid(struct udma_dev *udma_dev, struct udma_ctrlq_eid_info *eid_info) +{ + struct udma_ctrlq_eid_info *eid_entry; + eid_t ummu_eid = 0; + guid_t guid = {}; + int ret; + + eid_entry = kzalloc(sizeof(struct udma_ctrlq_eid_info), GFP_KERNEL); + if (!eid_entry) + return -ENOMEM; + + memcpy(eid_entry, eid_info, sizeof(struct udma_ctrlq_eid_info)); + ret = xa_err(xa_store(&udma_dev->eid_table, eid_info->eid_idx, eid_entry, GFP_KERNEL)); + if (ret) { + dev_err(udma_dev->dev, + "save eid entry failed, ret = %d, eid index = %u.\n", + ret, eid_info->eid_idx); + goto store_err; + } + + if (!udma_dev->is_ue) { + (void)memcpy(&ummu_eid, eid_info->eid.raw, sizeof(ummu_eid)); + ret = ummu_core_add_eid(&guid, ummu_eid, EID_NONE); + if (ret) { + dev_err(udma_dev->dev, + "set ummu eid entry failed, ret is %d.\n", ret); + goto err_add_ummu_eid; + } + } + udma_dispatch_eid_event(udma_dev, eid_entry, UBCORE_MGMT_EVENT_EID_ADD); + + return ret; +err_add_ummu_eid: + xa_erase(&udma_dev->eid_table, eid_info->eid_idx); +store_err: + kfree(eid_entry); + + return ret; +} + +int udma_del_one_eid(struct udma_dev *udma_dev, struct udma_ctrlq_eid_info *eid_info) +{ + struct udma_ctrlq_eid_info *eid_entry; + uint32_t index = eid_info->eid_idx; + eid_t ummu_eid = 0; + guid_t guid = {}; + + eid_entry = (struct udma_ctrlq_eid_info *)xa_load(&udma_dev->eid_table, index); + if (!eid_entry) { + dev_err(udma_dev->dev, "get eid entry failed, eid index = %u.\n", + index); + return -EINVAL; + } + if (memcmp(eid_entry->eid.raw, eid_info->eid.raw, sizeof(eid_entry->eid.raw))) { + dev_err(udma_dev->dev, "eid is not match, index = %u.\n", index); + return -EINVAL; + } + xa_erase(&udma_dev->eid_table, index); + + if (!udma_dev->is_ue) { + (void)memcpy(&ummu_eid, eid_entry->eid.raw, sizeof(ummu_eid)); + ummu_core_del_eid(&guid, ummu_eid, EID_NONE); + } + udma_dispatch_eid_event(udma_dev, eid_entry, UBCORE_MGMT_EVENT_EID_RMV); + kfree(eid_entry); + + return 0; +} diff --git a/drivers/ub/urma/hw/udma/udma_eid.h b/drivers/ub/urma/hw/udma/udma_eid.h new file mode 100644 index 000000000000..0e9e676524bc --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_eid.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_EID_H__ +#define __UDMA_EID_H__ + +#include +#include "udma_cmd.h" + +int udma_add_one_eid(struct udma_dev *udma_dev, struct udma_ctrlq_eid_info *eid_info); +int udma_del_one_eid(struct udma_dev *udma_dev, struct udma_ctrlq_eid_info *eid_info); + +#endif /* __UDMA_EID_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_eq.c b/drivers/ub/urma/hw/udma/udma_eq.c index 90c949c14375..53dfb2bdebd5 100644 --- a/drivers/ub/urma/hw/udma/udma_eq.c +++ b/drivers/ub/urma/hw/udma/udma_eq.c @@ -16,9 +16,61 @@ #include "udma_jfr.h" #include "udma_jfc.h" #include "udma_jetty.h" +#include "udma_eid.h" #include #include "udma_eq.h" +static inline int udma_ae_tp_ctrlq_msg_deal(struct udma_dev *udma_dev, + struct ubase_aeq_notify_info *info, + uint32_t queue_num) +{ + switch (info->event_type) { + case UBASE_EVENT_TYPE_TP_FLUSH_DONE: + return udma_ctrlq_tp_flush_done(udma_dev, queue_num); + case UBASE_EVENT_TYPE_TP_LEVEL_ERROR: + return udma_ctrlq_remove_single_tp(udma_dev, queue_num, TP_ERROR); + default: + dev_warn(udma_dev->dev, "udma get unsupported async event.\n"); + return 0; + } +} + +static void dump_ae_aux_info(struct udma_dev *dev, uint8_t event_type) +{ + struct ubcore_user_ctl_out out = {}; + struct ubcore_user_ctl_in in = {}; + struct udma_ae_info_in info_in; + + if (!dump_aux_info) + return; + + info_in.event_type = event_type; + in.addr = (uint64_t)&info_in; + in.len = sizeof(struct udma_ae_info_in); + in.opcode = UDMA_USER_CTL_QUERY_AE_AUX_INFO; + + (void)udma_query_ae_aux_info(&dev->ub_dev, NULL, &in, &out); +} + +static int udma_ae_tp_level_error(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct ubase_event_nb *ev_nb = container_of(nb, struct ubase_event_nb, nb); + struct auxiliary_device *adev = (struct auxiliary_device *)ev_nb->back; + struct ubase_aeq_notify_info *info = data; + struct udma_dev *udma_dev; + uint32_t queue_num; + + queue_num = info->aeqe->event.queue_event.num; + udma_dev = get_udma_dev(adev); + + dev_warn(udma_dev->dev, + "trigger tp level ae, event type is %d, sub type is %d, queue_num is %u.\n", + info->event_type, info->sub_type, queue_num); + + return udma_ae_tp_ctrlq_msg_deal(udma_dev, info, queue_num); +} + static int udma_ae_jfs_check_err(struct auxiliary_device *adev, uint32_t queue_num) { struct udma_dev *udma_dev = get_udma_dev(adev); @@ -47,6 +99,7 @@ static int udma_ae_jfs_check_err(struct auxiliary_device *adev, uint32_t queue_n ae.ub_dev = ubcore_jetty->ub_dev; ae.element.jetty = ubcore_jetty; ae.event_type = UBCORE_EVENT_JETTY_ERR; + dump_ae_aux_info(udma_dev, ae.event_type); ubcore_jetty->jfae_handler(&ae, ubcore_jetty->uctx); if (refcount_dec_and_test(&udma_jetty->ae_refcount)) complete(&udma_jetty->ae_comp); @@ -62,6 +115,7 @@ static int udma_ae_jfs_check_err(struct auxiliary_device *adev, uint32_t queue_n ae.ub_dev = ubcore_jfs->ub_dev; ae.element.jfs = ubcore_jfs; ae.event_type = UBCORE_EVENT_JFS_ERR; + dump_ae_aux_info(udma_dev, ae.event_type); ubcore_jfs->jfae_handler(&ae, ubcore_jfs->uctx); if (refcount_dec_and_test(&udma_jfs->ae_refcount)) complete(&udma_jfs->ae_comp); @@ -131,6 +185,7 @@ static int udma_ae_jfc_check_err(struct auxiliary_device *adev, uint32_t queue_n ae.ub_dev = ubcore_jfc->ub_dev; ae.element.jfc = ubcore_jfc; ae.event_type = UBCORE_EVENT_JFC_ERR; + dump_ae_aux_info(udma_dev, ae.event_type); ubcore_jfc->jfae_handler(&ae, ubcore_jfc->uctx); if (refcount_dec_and_test(&udma_jfc->event_refcount)) complete(&udma_jfc->event_comp); @@ -215,6 +270,8 @@ struct ae_operation { static struct ae_operation udma_ae_opts[] = { {UBASE_EVENT_TYPE_JETTY_LEVEL_ERROR, udma_ae_jetty_level_error}, {UBASE_EVENT_TYPE_JFR_LIMIT_REACHED, udma_ae_jetty_level_error}, + {UBASE_EVENT_TYPE_TP_LEVEL_ERROR, udma_ae_tp_level_error}, + {UBASE_EVENT_TYPE_TP_FLUSH_DONE, udma_ae_tp_level_error}, }; void udma_unregister_ae_event(struct auxiliary_device *adev) @@ -536,6 +593,244 @@ int udma_register_crq_event(struct auxiliary_device *adev) return ret; } +static int udma_ctrlq_send_eid_update_response(struct udma_dev *udma_dev, uint16_t seq, int ret_val) +{ + struct ubase_ctrlq_msg msg = {}; + int inbuf = 0; + int ret; + + msg.service_ver = UBASE_CTRLQ_SER_VER_01; + msg.service_type = UBASE_CTRLQ_SER_TYPE_DEV_REGISTER; + msg.opcode = UDMA_CTRLQ_UPDATE_SEID_INFO; + msg.need_resp = 0; + msg.is_resp = 1; + msg.resp_seq = seq; + msg.resp_ret = (uint8_t)(-ret_val); + msg.in = (void *)&inbuf; + msg.in_size = sizeof(inbuf); + + ret = ubase_ctrlq_send_msg(udma_dev->comdev.adev, &msg); + if (ret) + dev_err(udma_dev->dev, "send eid update response failed, ret = %d, ret_val = %d.\n", + ret, ret_val); + return ret; +} + +static int udma_ctrlq_eid_update(struct auxiliary_device *adev, uint8_t service_ver, + void *data, uint16_t len, uint16_t seq) +{ + struct udma_ctrlq_eid_out_update eid_entry = {}; + struct udma_dev *udma_dev; + int ret; + + if (adev == NULL || data == NULL) { + pr_err("adev or data is NULL.\n"); + return -EINVAL; + } + + udma_dev = get_udma_dev(adev); + if (len < sizeof(struct udma_ctrlq_eid_out_update)) { + dev_err(udma_dev->dev, "msg len(%u) is invalid.\n", len); + return udma_ctrlq_send_eid_update_response(udma_dev, seq, -EINVAL); + } + memcpy(&eid_entry, data, sizeof(eid_entry)); + if (eid_entry.op_type != UDMA_CTRLQ_EID_ADD && eid_entry.op_type != UDMA_CTRLQ_EID_DEL) { + dev_err(udma_dev->dev, "update eid op type(%u) is invalid.\n", eid_entry.op_type); + return udma_ctrlq_send_eid_update_response(udma_dev, seq, -EINVAL); + } + if (eid_entry.eid_info.eid_idx >= SEID_TABLE_SIZE) { + dev_err(udma_dev->dev, "update invalid eid_idx = %u.\n", + eid_entry.eid_info.eid_idx); + return udma_ctrlq_send_eid_update_response(udma_dev, seq, -EINVAL); + } + mutex_lock(&udma_dev->eid_mutex); + if (eid_entry.op_type == UDMA_CTRLQ_EID_ADD) + ret = udma_add_one_eid(udma_dev, &(eid_entry.eid_info)); + else + ret = udma_del_one_eid(udma_dev, &(eid_entry.eid_info)); + if (ret) + dev_err(udma_dev->dev, "update eid failed, op = %u, index = %u, ret = %d.\n", + eid_entry.op_type, eid_entry.eid_info.eid_idx, ret); + mutex_unlock(&udma_dev->eid_mutex); + + return udma_ctrlq_send_eid_update_response(udma_dev, seq, ret); +} + +static int udma_ctrlq_check_tp_status(struct udma_dev *udev, void *data, + uint16_t len, uint32_t tp_num, + struct udma_ctrlq_check_tp_active_rsp_info *rsp_info) +{ + struct udma_ctrlq_check_tp_active_req_info *req_info = NULL; + uint32_t req_info_len = 0; + int i; + + req_info_len = sizeof(uint32_t) + + sizeof(struct udma_ctrlq_check_tp_active_req_data) * tp_num; + if (len < req_info_len) { + dev_err(udev->dev, "msg param num(%u) is invalid.\n", tp_num); + return -EINVAL; + } + req_info = kzalloc(req_info_len, GFP_KERNEL); + if (!req_info) + return -ENOMEM; + memcpy(req_info, data, req_info_len); + + rcu_read_lock(); + for (i = 0; i < req_info->num; i++) { + if (find_vpid(req_info->data[i].pid_flag)) + rsp_info->data[i].result = UDMA_CTRLQ_TPID_IN_USE; + else + rsp_info->data[i].result = UDMA_CTRLQ_TPID_EXITED; + + rsp_info->data[i].tp_id = req_info->data[i].tp_id; + } + rsp_info->num = tp_num; + rcu_read_unlock(); + kfree(req_info); + + return 0; +} + +static int udma_ctrlq_check_param(struct udma_dev *udev, void *data, uint16_t len) +{ +#define UDMA_CTRLQ_HDR_LEN 12 +#define UDMA_CTRLQ_MAX_BB 32 +#define UDMA_CTRLQ_BB_LEN 32 + + if (data == NULL) { + dev_err(udev->dev, "data is NULL.\n"); + return -EINVAL; + } + + if ((len < UDMA_CTRLQ_BB_LEN - UDMA_CTRLQ_HDR_LEN) || + len > (UDMA_CTRLQ_BB_LEN * UDMA_CTRLQ_MAX_BB - UDMA_CTRLQ_HDR_LEN)) { + dev_err(udev->dev, "msg data len(%u) is invalid.\n", len); + return -EINVAL; + } + + return 0; +} + +static int udma_ctrlq_check_tp_active(struct auxiliary_device *adev, + uint8_t service_ver, void *data, + uint16_t len, uint16_t seq) +{ +#define UDMA_CTRLQ_CHECK_TP_OFFSET 0xFF + struct udma_ctrlq_check_tp_active_rsp_info *rsp_info = NULL; + struct udma_dev *udev = get_udma_dev(adev); + struct ubase_ctrlq_msg msg = {}; + uint32_t rsp_info_len = 0; + uint32_t tp_num = 0; + int ret_val; + int ret; + + ret_val = udma_ctrlq_check_param(udev, data, len); + if (ret_val == 0) { + tp_num = *((uint32_t *)data) & UDMA_CTRLQ_CHECK_TP_OFFSET; + rsp_info_len = sizeof(uint32_t) + + sizeof(struct udma_ctrlq_check_tp_active_rsp_data) * tp_num; + rsp_info = kzalloc(rsp_info_len, GFP_KERNEL); + if (!rsp_info) { + dev_err(udev->dev, "check tp mag malloc failed.\n"); + return -ENOMEM; + } + + ret_val = udma_ctrlq_check_tp_status(udev, data, len, tp_num, rsp_info); + if (ret_val) + dev_err(udev->dev, "check tp status failed, ret_val(%d).\n", ret_val); + } + + msg.service_ver = UBASE_CTRLQ_SER_VER_01; + msg.service_type = UBASE_CTRLQ_SER_TYPE_TP_ACL; + msg.opcode = UDMA_CMD_CTRLQ_CHECK_TP_ACTIVE; + msg.need_resp = 0; + msg.is_resp = 1; + msg.in_size = (uint16_t)rsp_info_len; + msg.in = (void *)rsp_info; + msg.resp_seq = seq; + msg.resp_ret = (uint8_t)(-ret_val); + + ret = ubase_ctrlq_send_msg(adev, &msg); + if (ret) { + kfree(rsp_info); + dev_err(udev->dev, "send check tp active ctrlq msg failed, ret(%d).\n", ret); + return ret; + } + kfree(rsp_info); + + return (ret_val) ? ret_val : 0; +} + +static struct ubase_ctrlq_event_nb udma_ctrlq_opts[] = { + {UBASE_CTRLQ_SER_TYPE_TP_ACL, UDMA_CMD_CTRLQ_CHECK_TP_ACTIVE, NULL, + udma_ctrlq_check_tp_active}, + {UBASE_CTRLQ_SER_TYPE_DEV_REGISTER, UDMA_CTRLQ_UPDATE_SEID_INFO, NULL, + udma_ctrlq_eid_update}, +}; + +static int udma_register_one_ctrlq_event(struct auxiliary_device *adev, + struct ubase_ctrlq_event_nb *ctrlq_nb, + uint32_t index) +{ + struct udma_dev *udma_dev = get_udma_dev(adev); + struct ubase_ctrlq_event_nb *nb; + int ret; + + nb = kzalloc(sizeof(*nb), GFP_KERNEL); + if (nb == NULL) + return -ENOMEM; + + nb->service_type = ctrlq_nb->service_type; + nb->opcode = ctrlq_nb->opcode; + nb->back = adev; + nb->crq_handler = ctrlq_nb->crq_handler; + ret = ubase_ctrlq_register_crq_event(adev, nb); + if (ret) + dev_err(udma_dev->dev, + "ubase register ctrlq event failed, opcode = %u, ret is %d.\n", + nb->opcode, ret); + + kfree(nb); + + return ret; +} + +void udma_unregister_ctrlq_event(struct auxiliary_device *adev) +{ + int opt_num; + int index; + + opt_num = ARRAY_SIZE(udma_ctrlq_opts); + for (index = 0; index < opt_num; ++index) + ubase_ctrlq_unregister_crq_event(adev, udma_ctrlq_opts[index].service_type, + udma_ctrlq_opts[index].opcode); +} + +int udma_register_ctrlq_event(struct auxiliary_device *adev) +{ + int opt_num; + int index; + int ret; + + opt_num = ARRAY_SIZE(udma_ctrlq_opts); + for (index = 0; index < opt_num; ++index) { + ret = udma_register_one_ctrlq_event(adev, &udma_ctrlq_opts[index], index); + if (ret) + goto err_register_one_ctrlq_event; + } + + return ret; + +err_register_one_ctrlq_event: + for (index--; index >= 0; index--) { + ubase_ctrlq_unregister_crq_event(adev, + udma_ctrlq_opts[index].service_type, + udma_ctrlq_opts[index].opcode); + } + + return ret; +} + int udma_register_activate_workqueue(struct udma_dev *udma_dev) { udma_dev->act_workq = alloc_workqueue("udma_activate_workq", WQ_UNBOUND, 0); diff --git a/drivers/ub/urma/hw/udma/udma_eq.h b/drivers/ub/urma/hw/udma/udma_eq.h index 336a8544cb9d..c0d727de78b6 100644 --- a/drivers/ub/urma/hw/udma/udma_eq.h +++ b/drivers/ub/urma/hw/udma/udma_eq.h @@ -9,6 +9,8 @@ void udma_unregister_ae_event(struct auxiliary_device *adev); int udma_register_ce_event(struct auxiliary_device *adev); void udma_unregister_crq_event(struct auxiliary_device *adev); int udma_register_crq_event(struct auxiliary_device *adev); +int udma_register_ctrlq_event(struct auxiliary_device *adev); +void udma_unregister_ctrlq_event(struct auxiliary_device *adev); int udma_register_activate_workqueue(struct udma_dev *udma_dev); void udma_unregister_activate_workqueue(struct udma_dev *udma_dev); diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 0393cc0ba18b..5ebfeccf454e 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -727,6 +727,26 @@ static struct udma_dev *udma_create_dev(struct auxiliary_device *adev) return NULL; } +static void udma_port_handler(struct auxiliary_device *adev, bool link_up) +{ + struct udma_dev *udma_dev = get_udma_dev(adev); + struct ubcore_event ae = {}; + + ae.ub_dev = &udma_dev->ub_dev; + + if (link_up) + ae.event_type = UBCORE_EVENT_PORT_ACTIVE; + else + ae.event_type = UBCORE_EVENT_PORT_DOWN; + + ae.element.port_id = udma_dev->port_id; + dev_info(udma_dev->dev, + "udma report port event %s, matched udma dev(%s).\n", + link_up ? "ACTIVE" : "DOWN", udma_dev->dev_name); + + ubcore_dispatch_async_event(&ae); +} + static int udma_register_event(struct auxiliary_device *adev) { int ret; @@ -743,8 +763,16 @@ static int udma_register_event(struct auxiliary_device *adev) if (ret) goto err_crq_register; + ret = udma_register_ctrlq_event(adev); + if (ret) + goto err_ctrlq_register; + + ubase_port_register(adev, udma_port_handler); + return 0; +err_ctrlq_register: + udma_unregister_crq_event(adev); err_crq_register: udma_unregister_ce_event(adev); err_ce_register: @@ -755,6 +783,8 @@ static int udma_register_event(struct auxiliary_device *adev) static void udma_unregister_event(struct auxiliary_device *adev) { + ubase_port_unregister(adev); + udma_unregister_ctrlq_event(adev); udma_unregister_crq_event(adev); udma_unregister_ce_event(adev); udma_unregister_ae_event(adev); -- Gitee From 33846e8ecdebccac879e59088901228a5d0521d6 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 09:45:26 +0800 Subject: [PATCH 047/103] ub: udma: Support set eid function. commit b2eb67d690c6c4ba5ce5d7e651ef8c60e4dc33b1 openEuler This patch adds the ability to set eid in driver loading process. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_eid.c | 72 +++++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_eid.h | 1 + drivers/ub/urma/hw/udma/udma_main.c | 19 ++++++++ 3 files changed, 92 insertions(+) diff --git a/drivers/ub/urma/hw/udma/udma_eid.c b/drivers/ub/urma/hw/udma/udma_eid.c index ad88d7eec976..3ff649f343be 100644 --- a/drivers/ub/urma/hw/udma/udma_eid.c +++ b/drivers/ub/urma/hw/udma/udma_eid.c @@ -96,3 +96,75 @@ int udma_del_one_eid(struct udma_dev *udma_dev, struct udma_ctrlq_eid_info *eid_ return 0; } + +static int udma_send_query_eid_cmd(struct udma_dev *udma_dev, + struct udma_ctrlq_eid_out_query *eid_out_query) +{ +#define UDMA_CMD_CTRLQ_QUERY_SEID 0xb5 + struct udma_ctrlq_eid_in_query eid_in_query = {}; + struct ubase_ctrlq_msg msg = {}; + int ret; + + msg.opcode = UDMA_CTRLQ_GET_SEID_INFO; + msg.service_ver = UBASE_CTRLQ_SER_VER_01; + msg.service_type = UBASE_CTRLQ_SER_TYPE_DEV_REGISTER; + msg.need_resp = 1; + msg.is_resp = 0; + msg.in_size = sizeof(eid_in_query); + msg.in = &eid_in_query; + msg.out_size = sizeof(*eid_out_query); + msg.out = eid_out_query; + eid_in_query.cmd = UDMA_CMD_CTRLQ_QUERY_SEID; + + ret = ubase_ctrlq_send_msg(udma_dev->comdev.adev, &msg); + if (ret) + dev_err(udma_dev->dev, + "query seid from ctrl cpu failed, ret = %d.\n", ret); + + return ret; +} + +int udma_query_eid_from_ctrl_cpu(struct udma_dev *udma_dev) +{ + struct udma_ctrlq_eid_out_query eid_out_query = {}; + int ret, ret_tmp, i; + + ret = udma_send_query_eid_cmd(udma_dev, &eid_out_query); + if (ret) { + dev_err(udma_dev->dev, "query eid failed, ret = %d.\n", ret); + return ret; + } + + if (eid_out_query.seid_num > UDMA_CTRLQ_SEID_NUM) { + dev_err(udma_dev->dev, "Invalid param: seid num is %u.\n", eid_out_query.seid_num); + return -EINVAL; + } + + mutex_lock(&udma_dev->eid_mutex); + for (i = 0; i < (int)eid_out_query.seid_num; i++) { + if (eid_out_query.eids[i].eid_idx >= SEID_TABLE_SIZE) { + dev_err(udma_dev->dev, "invalid eid_idx = %u.\n", + eid_out_query.eids[i].eid_idx); + goto err_add_ummu_eid; + } + ret = udma_add_one_eid(udma_dev, &(eid_out_query.eids[i])); + if (ret) { + dev_err(udma_dev->dev, "Add eid failed, ret = %d, eid_idx = %u.\n", + ret, eid_out_query.eids[i].eid_idx); + goto err_add_ummu_eid; + } + } + mutex_unlock(&udma_dev->eid_mutex); + + return 0; +err_add_ummu_eid: + for (i--; i >= 0; i--) { + ret_tmp = udma_del_one_eid(udma_dev, &eid_out_query.eids[i]); + if (ret_tmp) + dev_err(udma_dev->dev, "Del eid failed, ret = %d, idx = %u.\n", + ret_tmp, eid_out_query.eids[i].eid_idx); + } + mutex_unlock(&udma_dev->eid_mutex); + + return ret; +} diff --git a/drivers/ub/urma/hw/udma/udma_eid.h b/drivers/ub/urma/hw/udma/udma_eid.h index 0e9e676524bc..dc9b9bb47270 100644 --- a/drivers/ub/urma/hw/udma/udma_eid.h +++ b/drivers/ub/urma/hw/udma/udma_eid.h @@ -9,5 +9,6 @@ int udma_add_one_eid(struct udma_dev *udma_dev, struct udma_ctrlq_eid_info *eid_info); int udma_del_one_eid(struct udma_dev *udma_dev, struct udma_ctrlq_eid_info *eid_info); +int udma_query_eid_from_ctrl_cpu(struct udma_dev *udma_dev); #endif /* __UDMA_EID_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 5ebfeccf454e..2da4ef51ec67 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -22,6 +22,7 @@ #include "udma_ctx.h" #include "udma_rct.h" #include "udma_tid.h" +#include "udma_eid.h" #include "udma_debugfs.h" #include "udma_common.h" #include "udma_ctrlq_tp.h" @@ -850,6 +851,17 @@ static void udma_reset_handler(struct auxiliary_device *adev, } } +static int udma_init_eid_table(struct udma_dev *udma_dev) +{ + int ret; + + ret = udma_query_eid_from_ctrl_cpu(udma_dev); + if (ret) + dev_err(udma_dev->dev, "query eid info failed, ret = %d.\n", ret); + + return ret; +} + static int udma_init_dev(struct auxiliary_device *adev) { struct udma_dev *udma_dev; @@ -883,6 +895,11 @@ static int udma_init_dev(struct auxiliary_device *adev) goto err_set_ubcore_dev; } + ret = udma_init_eid_table(udma_dev); + if (ret) { + dev_err(udma_dev->dev, "init eid table failed.\n"); + goto err_init_eid; + } udma_register_debugfs(udma_dev); udma_dev->status = UDMA_NORMAL; mutex_unlock(&udma_reset_mutex); @@ -890,6 +907,8 @@ static int udma_init_dev(struct auxiliary_device *adev) return 0; +err_init_eid: + udma_unset_ubcore_dev(udma_dev); err_set_ubcore_dev: udma_unregister_activate_workqueue(udma_dev); err_register_act_init: -- Gitee From 7b87b814ba551c16dc9abab0d2b38a3844c540ab Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Thu, 18 Sep 2025 11:43:28 +0800 Subject: [PATCH 048/103] ub: udma: Support register and unregister segment function. commit 257c03e42137bb3c00ad742d1703e8674eed9d30 openEuler This patch adds the ability to register and unregister segment. In addition, this patch adds the function of import and unimport segment. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/Makefile | 2 +- drivers/ub/urma/hw/udma/udma_eid.h | 6 + drivers/ub/urma/hw/udma/udma_main.c | 5 + drivers/ub/urma/hw/udma/udma_segment.c | 251 +++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_segment.h | 32 ++++ 5 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 drivers/ub/urma/hw/udma/udma_segment.c create mode 100644 drivers/ub/urma/hw/udma/udma_segment.h diff --git a/drivers/ub/urma/hw/udma/Makefile b/drivers/ub/urma/hw/udma/Makefile index 2739d92c115e..a5358afd8e47 100644 --- a/drivers/ub/urma/hw/udma/Makefile +++ b/drivers/ub/urma/hw/udma/Makefile @@ -2,6 +2,6 @@ udma-$(CONFIG_UB_UDMA) := udma_main.o udma_cmd.o udma_common.o udma_ctx.o udma_db.o \ udma_rct.o udma_tid.o udma_debugfs.o udma_eq.o udma_jfc.o \ - udma_ctrlq_tp.o udma_eid.o udma_ctl.o + udma_ctrlq_tp.o udma_eid.o udma_ctl.o udma_segment.o obj-m := udma.o diff --git a/drivers/ub/urma/hw/udma/udma_eid.h b/drivers/ub/urma/hw/udma/udma_eid.h index dc9b9bb47270..0bb5d626503c 100644 --- a/drivers/ub/urma/hw/udma/udma_eid.h +++ b/drivers/ub/urma/hw/udma/udma_eid.h @@ -7,6 +7,12 @@ #include #include "udma_cmd.h" +struct udma_seid_upi { + union ubcore_eid seid; + uint32_t upi; + uint32_t rsvd0[3]; +}; + int udma_add_one_eid(struct udma_dev *udma_dev, struct udma_ctrlq_eid_info *eid_info); int udma_del_one_eid(struct udma_dev *udma_dev, struct udma_ctrlq_eid_info *eid_info); int udma_query_eid_from_ctrl_cpu(struct udma_dev *udma_dev); diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 2da4ef51ec67..8ae10ba7fbaa 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -18,6 +18,7 @@ #include #include "udma_dev.h" #include "udma_eq.h" +#include "udma_segment.h" #include "udma_cmd.h" #include "udma_ctx.h" #include "udma_rct.h" @@ -166,6 +167,10 @@ static struct ubcore_ops g_dev_ops = { .mmap = udma_mmap, .alloc_token_id = udma_alloc_tid, .free_token_id = udma_free_tid, + .register_seg = udma_register_seg, + .unregister_seg = udma_unregister_seg, + .import_seg = udma_import_seg, + .unimport_seg = udma_unimport_seg, }; static void udma_uninit_group_table(struct udma_dev *dev, struct udma_group_table *table) diff --git a/drivers/ub/urma/hw/udma/udma_segment.c b/drivers/ub/urma/hw/udma/udma_segment.c new file mode 100644 index 000000000000..69098a2f3a67 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_segment.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt + +#include +#include +#include "udma_common.h" +#include "udma_cmd.h" +#include "udma_eid.h" +#include "udma_tid.h" +#include "udma_segment.h" + +static int udma_pin_segment(struct ubcore_device *ub_dev, struct ubcore_seg_cfg *cfg, + struct udma_segment *seg) +{ + struct udma_dev *udma_dev = to_udma_dev(ub_dev); + struct udma_umem_param param; + int ret = 0; + + if (cfg->flag.bs.non_pin) + return 0; + + param.ub_dev = ub_dev; + param.va = cfg->va; + param.len = cfg->len; + + param.flag.bs.writable = + !!(cfg->flag.bs.access & UBCORE_ACCESS_WRITE); + param.flag.bs.non_pin = cfg->flag.bs.non_pin; + param.is_kernel = seg->kernel_mode; + + seg->umem = udma_umem_get(¶m); + if (IS_ERR(seg->umem)) { + ret = PTR_ERR(seg->umem); + dev_err(udma_dev->dev, + "failed to get segment umem, ret = %d.\n", ret); + } + + return ret; +} + +static void udma_unpin_seg(struct udma_segment *seg) +{ + if (!seg->core_tseg.seg.attr.bs.non_pin) + udma_umem_release(seg->umem, seg->kernel_mode); +} + +static int udma_check_seg_cfg(struct udma_dev *udma_dev, struct ubcore_seg_cfg *cfg) +{ + if (!cfg->token_id || cfg->flag.bs.access >= UDMA_SEGMENT_ACCESS_GUARD || + cfg->flag.bs.token_policy >= UBCORE_TOKEN_SIGNED) { + dev_err(udma_dev->dev, + "error segment input, access = %d, token_policy = %d, or null key_id.\n", + cfg->flag.bs.access, cfg->flag.bs.token_policy); + return -EINVAL; + } + + return 0; +} + +static void udma_init_seg_cfg(struct udma_segment *seg, struct ubcore_seg_cfg *cfg) +{ + seg->core_tseg.token_id = cfg->token_id; + seg->core_tseg.seg.token_id = cfg->token_id->token_id; + seg->core_tseg.seg.attr.value = cfg->flag.value; + seg->token_value = cfg->token_value.token; + seg->token_value_valid = cfg->flag.bs.token_policy != UBCORE_TOKEN_NONE; +} + +static int udma_u_get_seg_perm(struct ubcore_seg_cfg *cfg) +{ + if (cfg->flag.bs.access & UBCORE_ACCESS_LOCAL_ONLY || + cfg->flag.bs.access & UBCORE_ACCESS_ATOMIC) + return UMMU_DEV_ATOMIC | UMMU_DEV_WRITE | UMMU_DEV_READ; + + if (cfg->flag.bs.access & UBCORE_ACCESS_WRITE) + return UMMU_DEV_WRITE | UMMU_DEV_READ; + + return UMMU_DEV_READ; +} + +static int udma_sva_grant(struct ubcore_seg_cfg *cfg, struct iommu_sva *ksva) +{ +#define UDMA_TOKEN_VALUE_INPUT 0 + struct ummu_seg_attr seg_attr = {.token = NULL, .e_bit = UMMU_EBIT_ON}; + struct ummu_token_info token_info; + int perm; + int ret; + + perm = udma_u_get_seg_perm(cfg); + seg_attr.e_bit = (enum ummu_ebit_state)cfg->flag.bs.access & + UBCORE_ACCESS_LOCAL_ONLY; + + if (cfg->flag.bs.token_policy == UBCORE_TOKEN_NONE) { + return ummu_sva_grant_range(ksva, (void *)(uintptr_t)cfg->va, cfg->len, + perm, (void *)&seg_attr); + } else { + seg_attr.token = &token_info; + token_info.input = UDMA_TOKEN_VALUE_INPUT; + token_info.tokenVal = cfg->token_value.token; + ret = ummu_sva_grant_range(ksva, (void *)(uintptr_t)cfg->va, cfg->len, + perm, (void *)&seg_attr); + token_info.tokenVal = 0; + + return ret; + } +} + +struct ubcore_target_seg *udma_register_seg(struct ubcore_device *ub_dev, + struct ubcore_seg_cfg *cfg, + struct ubcore_udata *udata) +{ + struct udma_dev *udma_dev = to_udma_dev(ub_dev); + struct udma_tid *udma_tid; + struct udma_segment *seg; + struct iommu_sva *ksva; + int ret = 0; + + ret = udma_check_seg_cfg(udma_dev, cfg); + if (ret) + return NULL; + + seg = kzalloc(sizeof(*seg), GFP_KERNEL); + if (!seg) + return NULL; + + seg->kernel_mode = udata == NULL; + udma_init_seg_cfg(seg, cfg); + + ret = udma_pin_segment(ub_dev, cfg, seg); + if (ret) { + dev_err(udma_dev->dev, "pin segment failed, ret = %d.\n", ret); + goto err_pin_seg; + } + + if (udata) + return &seg->core_tseg; + + udma_tid = to_udma_tid(seg->core_tseg.token_id); + + mutex_lock(&udma_dev->ksva_mutex); + ksva = (struct iommu_sva *)xa_load(&udma_dev->ksva_table, udma_tid->tid); + if (!ksva) { + dev_err(udma_dev->dev, + "unable to get ksva while register segment, token maybe is free.\n"); + goto err_load_ksva; + } + + ret = udma_sva_grant(cfg, ksva); + if (ret) { + dev_err(udma_dev->dev, + "ksva grant failed with token policy %d, ret = %d.\n", + cfg->flag.bs.token_policy, ret); + goto err_load_ksva; + } + mutex_unlock(&udma_dev->ksva_mutex); + + return &seg->core_tseg; + +err_load_ksva: + mutex_unlock(&udma_dev->ksva_mutex); + udma_unpin_seg(seg); +err_pin_seg: + kfree(seg); + return NULL; +} + +int udma_unregister_seg(struct ubcore_target_seg *ubcore_seg) +{ + struct udma_tid *udma_tid = to_udma_tid(ubcore_seg->token_id); + struct udma_dev *udma_dev = to_udma_dev(ubcore_seg->ub_dev); + struct udma_segment *seg = to_udma_seg(ubcore_seg); + struct ummu_token_info token_info; + struct iommu_sva *ksva; + int ret; + + if (!seg->kernel_mode) + goto common_process; + + mutex_lock(&udma_dev->ksva_mutex); + ksva = (struct iommu_sva *)xa_load(&udma_dev->ksva_table, udma_tid->tid); + + if (!ksva) { + dev_warn(udma_dev->dev, + "unable to get ksva while unregister segment, token maybe is free.\n"); + } else { + if (seg->token_value_valid) { + token_info.tokenVal = seg->token_value; + ret = ummu_sva_ungrant_range(ksva, + (void *)(uintptr_t)ubcore_seg->seg.ubva.va, + ubcore_seg->seg.len, &token_info); + token_info.tokenVal = 0; + } else { + ret = ummu_sva_ungrant_range(ksva, + (void *)(uintptr_t)ubcore_seg->seg.ubva.va, + ubcore_seg->seg.len, NULL); + } + if (ret) { + mutex_unlock(&udma_dev->ksva_mutex); + dev_err(udma_dev->dev, "unregister segment failed, ret = %d.\n", ret); + return ret; + } + } + mutex_unlock(&udma_dev->ksva_mutex); + +common_process: + udma_unpin_seg(seg); + seg->token_value = 0; + kfree(seg); + + return 0; +} + +struct ubcore_target_seg *udma_import_seg(struct ubcore_device *dev, + struct ubcore_target_seg_cfg *cfg, + struct ubcore_udata *udata) +{ + struct udma_dev *udma_dev = to_udma_dev(dev); + struct udma_segment *seg; + + if (cfg->seg.attr.bs.token_policy > UBCORE_TOKEN_PLAIN_TEXT) { + dev_err(udma_dev->dev, "invalid token policy = %d.\n", + cfg->seg.attr.bs.token_policy); + return NULL; + } + + seg = kzalloc(sizeof(*seg), GFP_KERNEL); + if (!seg) + return NULL; + + if (cfg->seg.attr.bs.token_policy != UBCORE_TOKEN_NONE) { + seg->token_value = cfg->token_value.token; + seg->token_value_valid = true; + } + + seg->tid = cfg->seg.token_id >> UDMA_TID_SHIFT; + + return &seg->core_tseg; +} + +int udma_unimport_seg(struct ubcore_target_seg *tseg) +{ + struct udma_segment *seg; + + seg = to_udma_seg(tseg); + seg->token_value = 0; + kfree(seg); + + return 0; +} diff --git a/drivers/ub/urma/hw/udma/udma_segment.h b/drivers/ub/urma/hw/udma/udma_segment.h new file mode 100644 index 000000000000..7dba1fbf385e --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_segment.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_SEGMENT_H__ +#define __UDMA_SEGMENT_H__ + +#include "udma_dev.h" + +struct udma_segment { + struct ubcore_target_seg core_tseg; + struct ubcore_umem *umem; + uint32_t token_value; + bool token_value_valid; + bool kernel_mode; + uint32_t tid; +}; + +static inline struct udma_segment *to_udma_seg(struct ubcore_target_seg *seg) +{ + return container_of(seg, struct udma_segment, core_tseg); +} + +struct ubcore_target_seg *udma_register_seg(struct ubcore_device *ub_dev, + struct ubcore_seg_cfg *cfg, + struct ubcore_udata *udata); +int udma_unregister_seg(struct ubcore_target_seg *seg); +struct ubcore_target_seg *udma_import_seg(struct ubcore_device *dev, + struct ubcore_target_seg_cfg *cfg, + struct ubcore_udata *udata); +int udma_unimport_seg(struct ubcore_target_seg *tseg); + +#endif /* __UDMA_SEGMENT_H__ */ -- Gitee From c038648bfaa62419dceddc23a21a80f1f725cca6 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 10:01:20 +0800 Subject: [PATCH 049/103] ub: udma: Support init and uninit dfx function. commit dbb754b5f3278f3143607cc57f734fe273a605b8 openEuler This patch adds the ability to init and uninit dfx function. In addition, this patch enables the dfx function for rc and segment. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/Makefile | 3 +- drivers/ub/urma/hw/udma/udma_common.c | 64 ++++++ drivers/ub/urma/hw/udma/udma_common.h | 6 + drivers/ub/urma/hw/udma/udma_def.h | 33 +++ drivers/ub/urma/hw/udma/udma_dev.h | 2 + drivers/ub/urma/hw/udma/udma_dfx.c | 299 +++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_dfx.h | 55 +++++ drivers/ub/urma/hw/udma/udma_main.c | 3 + drivers/ub/urma/hw/udma/udma_rct.c | 6 + drivers/ub/urma/hw/udma/udma_segment.c | 102 +++++++++ 10 files changed, 572 insertions(+), 1 deletion(-) create mode 100644 drivers/ub/urma/hw/udma/udma_dfx.c create mode 100644 drivers/ub/urma/hw/udma/udma_dfx.h diff --git a/drivers/ub/urma/hw/udma/Makefile b/drivers/ub/urma/hw/udma/Makefile index a5358afd8e47..a087da421b2e 100644 --- a/drivers/ub/urma/hw/udma/Makefile +++ b/drivers/ub/urma/hw/udma/Makefile @@ -2,6 +2,7 @@ udma-$(CONFIG_UB_UDMA) := udma_main.o udma_cmd.o udma_common.o udma_ctx.o udma_db.o \ udma_rct.o udma_tid.o udma_debugfs.o udma_eq.o udma_jfc.o \ - udma_ctrlq_tp.o udma_eid.o udma_ctl.o udma_segment.o + udma_ctrlq_tp.o udma_eid.o udma_ctl.o udma_segment.o \ + udma_dfx.o obj-m := udma.o diff --git a/drivers/ub/urma/hw/udma/udma_common.c b/drivers/ub/urma/hw/udma/udma_common.c index 4b4ccc22124a..375ed4826f6a 100644 --- a/drivers/ub/urma/hw/udma/udma_common.c +++ b/drivers/ub/urma/hw/udma/udma_common.c @@ -470,6 +470,55 @@ void udma_destroy_eid_table(struct udma_dev *udma_dev) mutex_destroy(&udma_dev->eid_mutex); } +void udma_dfx_store_id(struct udma_dev *udma_dev, struct udma_dfx_entity *entity, + uint32_t id, const char *name) +{ + uint32_t *entry; + int ret; + + entry = (uint32_t *)xa_load(&entity->table, id); + if (entry) { + dev_warn(udma_dev->dev, "%s(%u) already exists in DFX.\n", name, id); + return; + } + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return; + + *entry = id; + + write_lock(&entity->rwlock); + ret = xa_err(xa_store(&entity->table, id, entry, GFP_KERNEL)); + if (ret) { + write_unlock(&entity->rwlock); + dev_err(udma_dev->dev, "store %s to table failed in DFX.\n", name); + kfree(entry); + return; + } + + ++entity->cnt; + write_unlock(&entity->rwlock); +} + +void udma_dfx_delete_id(struct udma_dev *udma_dev, struct udma_dfx_entity *entity, + uint32_t id) +{ + void *entry; + + write_lock(&entity->rwlock); + entry = xa_load(&entity->table, id); + if (!entry) { + write_unlock(&entity->rwlock); + return; + } + + xa_erase(&entity->table, id); + kfree(entry); + --entity->cnt; + write_unlock(&entity->rwlock); +} + static struct ubcore_umem *udma_pin_k_addr(struct ubcore_device *ub_dev, uint64_t va, uint64_t len) { @@ -579,6 +628,21 @@ void udma_free_iova(struct udma_dev *udma_dev, size_t memory_size, void *kva_or_ dma_free_iova(slot); } +void udma_dfx_ctx_print(struct udma_dev *udev, const char *name, uint32_t id, uint32_t len, + uint32_t *ctx) +{ + uint32_t i; + + pr_info("*************udma%u %s(%u) CONTEXT INFO *************\n", + udev->adev_id, name, id); + + for (i = 0; i < len; ++i) + pr_info("udma%u %s(%u) CONTEXT(byte%4lu): %08x\n", + udev->adev_id, name, id, (i + 1) * sizeof(uint32_t), ctx[i]); + + pr_info("**************************************************\n"); +} + void udma_swap_endian(uint8_t arr[], uint8_t res[], uint32_t res_size) { uint32_t i; diff --git a/drivers/ub/urma/hw/udma/udma_common.h b/drivers/ub/urma/hw/udma/udma_common.h index 3cec74f9ec8e..aba7b4afddb3 100644 --- a/drivers/ub/urma/hw/udma/udma_common.h +++ b/drivers/ub/urma/hw/udma/udma_common.h @@ -72,6 +72,10 @@ void udma_init_udma_table_mutex(struct xarray *table, struct mutex *udma_mutex); void udma_destroy_udma_table(struct udma_dev *dev, struct udma_table *table, const char *table_name); void udma_destroy_eid_table(struct udma_dev *udma_dev); +void udma_dfx_store_id(struct udma_dev *udma_dev, struct udma_dfx_entity *entity, + uint32_t id, const char *name); +void udma_dfx_delete_id(struct udma_dev *udma_dev, struct udma_dfx_entity *entity, + uint32_t id); int udma_k_alloc_buf(struct udma_dev *udma_dev, size_t memory_size, struct udma_buf *buf); void udma_k_free_buf(struct udma_dev *udma_dev, size_t memory_size, struct udma_buf *buf); void *udma_alloc_iova(struct udma_dev *udma_dev, size_t memory_size, dma_addr_t *addr); @@ -82,6 +86,8 @@ static inline uint64_t udma_cal_npages(uint64_t va, uint64_t len) return (ALIGN(va + len, PAGE_SIZE) - ALIGN_DOWN(va, PAGE_SIZE)) / PAGE_SIZE; } +void udma_dfx_ctx_print(struct udma_dev *udev, const char *name, uint32_t id, uint32_t len, + uint32_t *ctx); void udma_swap_endian(uint8_t arr[], uint8_t res[], uint32_t res_size); #endif /* __UDMA_COMM_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_def.h b/drivers/ub/urma/hw/udma/udma_def.h index c45c69cd0271..ca107e34a37c 100644 --- a/drivers/ub/urma/hw/udma/udma_def.h +++ b/drivers/ub/urma/hw/udma/udma_def.h @@ -69,6 +69,39 @@ struct udma_caps { struct udma_tbl seid; }; +struct udma_dfx_jetty { + uint32_t id; + uint32_t jfs_depth; +}; + +struct udma_dfx_jfs { + uint32_t id; + uint32_t depth; +}; + +struct udma_dfx_seg { + uint32_t id; + struct ubcore_ubva ubva; + uint64_t len; + struct ubcore_token token_value; +}; + +struct udma_dfx_entity { + uint32_t cnt; + struct xarray table; + rwlock_t rwlock; +}; + +struct udma_dfx_info { + struct udma_dfx_entity rc; + struct udma_dfx_entity jetty; + struct udma_dfx_entity jetty_grp; + struct udma_dfx_entity jfs; + struct udma_dfx_entity jfr; + struct udma_dfx_entity jfc; + struct udma_dfx_entity seg; +}; + struct udma_sw_db_page { struct list_head list; struct ubcore_umem *umem; diff --git a/drivers/ub/urma/hw/udma/udma_dev.h b/drivers/ub/urma/hw/udma/udma_dev.h index 89b91ff08e79..67e8847d66a6 100644 --- a/drivers/ub/urma/hw/udma/udma_dev.h +++ b/drivers/ub/urma/hw/udma/udma_dev.h @@ -11,6 +11,7 @@ #include #include +extern bool dfx_switch; extern uint32_t jfc_arm_mode; extern bool dump_aux_info; @@ -110,6 +111,7 @@ struct udma_dev { struct iommu_sva *ksva; struct list_head db_list[UDMA_DB_TYPE_NUM]; struct mutex db_mutex; + struct udma_dfx_info *dfx_info; uint32_t status; struct udma_dev_debugfs *dbgfs; uint32_t ue_num; diff --git a/drivers/ub/urma/hw/udma/udma_dfx.c b/drivers/ub/urma/hw/udma/udma_dfx.c new file mode 100644 index 000000000000..f6920f879eea --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_dfx.c @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt + +#include "udma_cmd.h" +#include "udma_jfr.h" +#include "udma_jfs.h" +#include "udma_jfc.h" +#include "udma_jetty.h" +#include "udma_rct.h" +#include "udma_dfx.h" + +bool dfx_switch; + +static int udma_query_res_list(struct udma_dev *udma_dev, + struct udma_dfx_entity *entity, + struct ubcore_res_val *val, + const char *name) +{ + struct ubcore_res_list_val *res_list = (struct ubcore_res_list_val *)val->addr; + size_t idx = 0; + uint32_t *id; + + res_list->cnt = 0; + + read_lock(&entity->rwlock); + if (entity->cnt == 0) { + read_unlock(&entity->rwlock); + return 0; + } + + res_list->list = vmalloc(sizeof(uint32_t) * entity->cnt); + if (!res_list->list) { + read_unlock(&entity->rwlock); + dev_err(udma_dev->dev, "failed to vmalloc %s_list, %s_cnt = %u!\n", + name, name, entity->cnt); + return -ENOMEM; + } + + xa_for_each(&entity->table, idx, id) { + if (res_list->cnt >= entity->cnt) { + read_unlock(&entity->rwlock); + vfree(res_list->list); + dev_err(udma_dev->dev, + "failed to query %s_id, %s_cnt = %u!\n", + name, name, entity->cnt); + return -EINVAL; + } + res_list->list[res_list->cnt] = idx; + ++res_list->cnt; + } + read_unlock(&entity->rwlock); + + return 0; +} + +static int udma_query_res_dev_seg(struct udma_dev *udma_dev, + struct ubcore_res_val *val) +{ + struct ubcore_res_seg_val *res_list = (struct ubcore_res_seg_val *)val->addr; + struct ubcore_seg_info *seg_list; + struct udma_dfx_seg *seg = NULL; + size_t idx; + + res_list->seg_cnt = 0; + + read_lock(&udma_dev->dfx_info->seg.rwlock); + if (udma_dev->dfx_info->seg.cnt == 0) { + read_unlock(&udma_dev->dfx_info->seg.rwlock); + return 0; + } + + seg_list = vmalloc(sizeof(*seg_list) * udma_dev->dfx_info->seg.cnt); + if (!seg_list) { + read_unlock(&udma_dev->dfx_info->seg.rwlock); + return -ENOMEM; + } + + xa_for_each(&udma_dev->dfx_info->seg.table, idx, seg) { + if (res_list->seg_cnt >= udma_dev->dfx_info->seg.cnt) { + read_unlock(&udma_dev->dfx_info->seg.rwlock); + vfree(seg_list); + dev_err(udma_dev->dev, + "failed to query seg_list, seg_cnt = %u!\n", + udma_dev->dfx_info->seg.cnt); + return -EINVAL; + } + seg_list[res_list->seg_cnt].token_id = seg->id; + seg_list[res_list->seg_cnt].len = seg->len; + seg_list[res_list->seg_cnt].ubva = seg->ubva; + seg_list[res_list->seg_cnt].ubva.va = 0; + ++res_list->seg_cnt; + } + read_unlock(&udma_dev->dfx_info->seg.rwlock); + + res_list->seg_list = seg_list; + + return 0; +} + +static int udma_query_res_rc(struct udma_dev *udma_dev, + struct ubcore_res_key *key, + struct ubcore_res_val *val) +{ + struct ubcore_res_rc_val *res_rc = (struct ubcore_res_rc_val *)val->addr; + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + struct udma_rc_ctx *rcc; + uint32_t *rc_id; + + if (key->key_cnt == 0) + return udma_query_res_list(udma_dev, &udma_dev->dfx_info->rc, val, "rc"); + + rc_id = (uint32_t *)xa_load(&udma_dev->dfx_info->rc.table, key->key); + if (!rc_id) { + dev_err(udma_dev->dev, "failed to query rc, rc_id = %u.\n", + key->key); + return -EINVAL; + } + mbox_attr.tag = key->key; + mbox_attr.op = UDMA_CMD_QUERY_RC_CONTEXT; + mailbox = udma_mailbox_query_ctx(udma_dev, &mbox_attr); + if (!mailbox) + return -ENOMEM; + + rcc = (struct udma_rc_ctx *)mailbox->buf; + res_rc->rc_id = key->key; + res_rc->depth = 1 << rcc->rce_shift; + res_rc->type = 0; + res_rc->state = 0; + rcc->rce_base_addr_l = 0; + rcc->rce_base_addr_h = 0; + + udma_dfx_ctx_print(udma_dev, "RC", key->key, sizeof(*rcc) / sizeof(uint32_t), + (uint32_t *)rcc); + udma_free_cmd_mailbox(udma_dev, mailbox); + + return 0; +} + +static int udma_query_res_seg(struct udma_dev *udma_dev, struct ubcore_res_key *key, + struct ubcore_res_val *val) +{ + struct ubcore_res_seg_val *res_seg = (struct ubcore_res_seg_val *)val->addr; + struct udma_dfx_seg *seg; + + if (key->key_cnt == 0) + return udma_query_res_dev_seg(udma_dev, val); + + read_lock(&udma_dev->dfx_info->seg.rwlock); + seg = (struct udma_dfx_seg *)xa_load(&udma_dev->dfx_info->seg.table, key->key); + if (!seg) { + read_unlock(&udma_dev->dfx_info->seg.rwlock); + dev_err(udma_dev->dev, "failed to query seg, token_id = %u.\n", + key->key); + return -EINVAL; + } + + res_seg->seg_list = vmalloc(sizeof(struct ubcore_seg_info)); + if (!res_seg->seg_list) { + read_unlock(&udma_dev->dfx_info->seg.rwlock); + return -ENOMEM; + } + + res_seg->seg_cnt = 1; + res_seg->seg_list->token_id = seg->id; + res_seg->seg_list->len = seg->len; + res_seg->seg_list->ubva = seg->ubva; + res_seg->seg_list->ubva.va = 0; + read_unlock(&udma_dev->dfx_info->seg.rwlock); + + return 0; +} + +static int udma_query_res_dev_ta(struct udma_dev *udma_dev, + struct ubcore_res_key *key, + struct ubcore_res_val *val) +{ + struct ubcore_res_dev_ta_val *res_ta = (struct ubcore_res_dev_ta_val *)val->addr; + struct udma_dfx_info *dfx = udma_dev->dfx_info; + struct udma_dfx_entity_cnt udma_dfx_entity_cnt_ta[] = { + {&dfx->rc.rwlock, &dfx->rc, &res_ta->rc_cnt}, + {&dfx->jetty.rwlock, &dfx->jetty, &res_ta->jetty_cnt}, + {&dfx->jetty_grp.rwlock, &dfx->jetty_grp, &res_ta->jetty_group_cnt}, + {&dfx->jfs.rwlock, &dfx->jfs, &res_ta->jfs_cnt}, + {&dfx->jfr.rwlock, &dfx->jfr, &res_ta->jfr_cnt}, + {&dfx->jfc.rwlock, &dfx->jfc, &res_ta->jfc_cnt}, + {&dfx->seg.rwlock, &dfx->seg, &res_ta->seg_cnt}, + }; + + int size = ARRAY_SIZE(udma_dfx_entity_cnt_ta); + int i; + + for (i = 0; i < size; i++) { + read_lock(udma_dfx_entity_cnt_ta[i].rwlock); + *udma_dfx_entity_cnt_ta[i].res_cnt = + udma_dfx_entity_cnt_ta[i].entity->cnt; + read_unlock(udma_dfx_entity_cnt_ta[i].rwlock); + } + + return 0; +} + +typedef int (*udma_query_res_handler)(struct udma_dev *udma_dev, + struct ubcore_res_key *key, + struct ubcore_res_val *val); + +static udma_query_res_handler g_udma_query_res_handlers[] = { + [0] = NULL, + [UBCORE_RES_KEY_RC] = udma_query_res_rc, + [UBCORE_RES_KEY_SEG] = udma_query_res_seg, + [UBCORE_RES_KEY_DEV_TA] = udma_query_res_dev_ta, +}; + +int udma_query_res(struct ubcore_device *dev, struct ubcore_res_key *key, + struct ubcore_res_val *val) +{ + struct udma_dev *udma_dev = to_udma_dev(dev); + + if (!dfx_switch) { + dev_warn(udma_dev->dev, "the dfx_switch is not enabled.\n"); + return -EPERM; + } + + if (key->type < UBCORE_RES_KEY_VTP || key->type > UBCORE_RES_KEY_DEV_TP || + g_udma_query_res_handlers[key->type] == NULL) { + dev_err(udma_dev->dev, "key type(%u) invalid.\n", key->type); + return -EINVAL; + } + + return g_udma_query_res_handlers[key->type](udma_dev, key, val); +} + +static void list_lock_init(struct udma_dfx_info *dfx) +{ + struct udma_dfx_entity_initialization udma_dfx_entity_initialization_arr[] = { + {&dfx->rc.rwlock, &dfx->rc.table}, + {&dfx->jetty.rwlock, &dfx->jetty.table}, + {&dfx->jetty_grp.rwlock, &dfx->jetty_grp.table}, + {&dfx->jfs.rwlock, &dfx->jfs.table}, + {&dfx->jfr.rwlock, &dfx->jfr.table}, + {&dfx->jfc.rwlock, &dfx->jfc.table}, + {&dfx->seg.rwlock, &dfx->seg.table}, + }; + int size = ARRAY_SIZE(udma_dfx_entity_initialization_arr); + int i; + + for (i = 0; i < size; i++) { + rwlock_init(udma_dfx_entity_initialization_arr[i].rwlock); + xa_init(udma_dfx_entity_initialization_arr[i].table); + } +} + +int udma_dfx_init(struct udma_dev *udma_dev) +{ + if (!dfx_switch) + return 0; + + udma_dev->dfx_info = kzalloc(sizeof(struct udma_dfx_info), GFP_KERNEL); + if (!udma_dev->dfx_info) + return -ENOMEM; + + list_lock_init(udma_dev->dfx_info); + + return 0; +} + +static void udma_dfx_destroy_xa(struct udma_dev *udma_dev, struct xarray *table, + const char *name) +{ + if (!xa_empty(table)) + dev_err(udma_dev->dev, "%s table is not empty.\n", name); + xa_destroy(table); +} + +static void udma_dfx_table_free(struct udma_dev *dev) +{ + udma_dfx_destroy_xa(dev, &dev->dfx_info->rc.table, "rc"); + udma_dfx_destroy_xa(dev, &dev->dfx_info->jetty.table, "jetty"); + udma_dfx_destroy_xa(dev, &dev->dfx_info->jetty_grp.table, "jetty_grp"); + udma_dfx_destroy_xa(dev, &dev->dfx_info->jfs.table, "jfs"); + udma_dfx_destroy_xa(dev, &dev->dfx_info->jfr.table, "jfr"); + udma_dfx_destroy_xa(dev, &dev->dfx_info->jfc.table, "jfc"); + udma_dfx_destroy_xa(dev, &dev->dfx_info->seg.table, "seg"); +} + +void udma_dfx_uninit(struct udma_dev *udma_dev) +{ + if (!dfx_switch) + return; + + udma_dfx_table_free(udma_dev); + kfree(udma_dev->dfx_info); + udma_dev->dfx_info = NULL; +} + +module_param(dfx_switch, bool, 0444); +MODULE_PARM_DESC(dfx_switch, "Set whether to enable the udma_dfx function, default: 0(0:off, 1:on)"); diff --git a/drivers/ub/urma/hw/udma/udma_dfx.h b/drivers/ub/urma/hw/udma/udma_dfx.h new file mode 100644 index 000000000000..92c0db1aa744 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_dfx.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#ifndef __UDMA_DFX_H__ +#define __UDMA_DFX_H__ + +#include "udma_dev.h" +#include "udma_ctx.h" +#include "udma_jetty.h" + +#define UDMA_RX_THRESHOLD_0 0 +#define UDMA_RX_THRESHOLD_64 64 +#define UDMA_RX_THRESHOLD_512 512 +#define UDMA_RX_THRESHOLD_4096 4096 + +#define UDMA_RX_REQ_EPSN_H_SHIFT 16 + +enum udma_limit_wl { + UDMA_LIMIT_WL_0, + UDMA_LIMIT_WL_64, + UDMA_LIMIT_WL_512, + UDMA_LIMIT_WL_4096, +}; + +struct udma_dfx_entity_initialization { + rwlock_t *rwlock; + struct xarray *table; +}; + +struct udma_dfx_entity_cnt { + rwlock_t *rwlock; + struct udma_dfx_entity *entity; + uint32_t *res_cnt; +}; + +static inline uint32_t to_udma_rx_threshold(uint32_t limit_wl) +{ + switch (limit_wl) { + case UDMA_LIMIT_WL_0: + return UDMA_RX_THRESHOLD_0; + case UDMA_LIMIT_WL_64: + return UDMA_RX_THRESHOLD_64; + case UDMA_LIMIT_WL_512: + return UDMA_RX_THRESHOLD_512; + default: + return UDMA_RX_THRESHOLD_4096; + } +} + +int udma_query_res(struct ubcore_device *dev, struct ubcore_res_key *key, + struct ubcore_res_val *val); +int udma_dfx_init(struct udma_dev *udma_dev); +void udma_dfx_uninit(struct udma_dev *udma_dev); + +#endif /* __UDMA_DFX_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 8ae10ba7fbaa..5bf8631260a5 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -23,6 +23,7 @@ #include "udma_ctx.h" #include "udma_rct.h" #include "udma_tid.h" +#include "udma_dfx.h" #include "udma_eid.h" #include "udma_debugfs.h" #include "udma_common.h" @@ -161,6 +162,7 @@ static struct ubcore_ops g_dev_ops = { .abi_version = 0, .query_device_attr = udma_query_device_attr, .query_device_status = udma_query_device_status, + .query_res = udma_query_res, .config_device = udma_config_device, .alloc_ucontext = udma_alloc_ucontext, .free_ucontext = udma_free_ucontext, @@ -686,6 +688,7 @@ static const struct udma_func_map udma_dev_func_map[] = { {"dev param", udma_init_dev_param, udma_uninit_dev_param}, {"cmd", udma_cmd_init, udma_cmd_cleanup}, {"dev tid", udma_alloc_dev_tid, udma_free_dev_tid}, + {"dfx", udma_dfx_init, udma_dfx_uninit}, {"db page", udma_create_db_page, udma_destroy_db_page}, }; diff --git a/drivers/ub/urma/hw/udma/udma_rct.c b/drivers/ub/urma/hw/udma/udma_rct.c index 149b9b6f27b4..599c80c118fd 100644 --- a/drivers/ub/urma/hw/udma/udma_rct.c +++ b/drivers/ub/urma/hw/udma/udma_rct.c @@ -91,6 +91,9 @@ static int udma_alloc_rc_queue(struct udma_dev *dev, goto err_store_rcq_id; } + if (dfx_switch) + udma_dfx_store_id(dev, &dev->dfx_info->rc, rcq->id, "rc"); + return ret; err_store_rcq_id: @@ -125,6 +128,9 @@ void udma_free_rc_queue(struct udma_dev *dev, int rc_queue_id) dev_err(dev->dev, "udma destroy rc queue ctx failed, ret = %d.\n", ret); + if (dfx_switch) + udma_dfx_delete_id(dev, &dev->dfx_info->rc, rc_queue_id); + udma_free_iova(dev, rcq->buf.entry_size * rcq->buf.entry_cnt, rcq->buf.kva_or_slot, rcq->buf.addr); rcq->buf.kva_or_slot = NULL; diff --git a/drivers/ub/urma/hw/udma/udma_segment.c b/drivers/ub/urma/hw/udma/udma_segment.c index 69098a2f3a67..90615d1ae2b4 100644 --- a/drivers/ub/urma/hw/udma/udma_segment.c +++ b/drivers/ub/urma/hw/udma/udma_segment.c @@ -107,6 +107,101 @@ static int udma_sva_grant(struct ubcore_seg_cfg *cfg, struct iommu_sva *ksva) } } +static int udma_set_seg_eid(struct udma_dev *udma_dev, uint32_t eid_index, + union ubcore_eid *eid) +{ + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + struct udma_seid_upi *seid_upi; + int ret; + + if (udma_dev->is_ue) { + dev_info(udma_dev->dev, + "The ue does not support the delivery of seid(%u) mailbox.\n", + eid_index); + return 0; + } + + mailbox = udma_alloc_cmd_mailbox(udma_dev); + if (!mailbox) { + dev_err(udma_dev->dev, + "failed to alloc mailbox for get tp seid.\n"); + return -ENOMEM; + } + + mbox_attr.tag = eid_index; + mbox_attr.op = UDMA_CMD_READ_SEID_UPI; + ret = udma_post_mbox(udma_dev, mailbox, &mbox_attr); + if (ret) { + dev_err(udma_dev->dev, + "send tp eid table mailbox cmd failed, ret is %d.\n", ret); + } else { + seid_upi = (struct udma_seid_upi *)mailbox->buf; + *eid = seid_upi->seid; + } + + udma_free_cmd_mailbox(udma_dev, mailbox); + + return ret; +} + +static void udma_dfx_store_seg(struct udma_dev *udma_dev, + struct ubcore_seg_cfg *cfg) +{ + struct udma_dfx_seg *seg; + int ret; + + seg = (struct udma_dfx_seg *)xa_load(&udma_dev->dfx_info->seg.table, + cfg->token_id->token_id); + if (seg) { + dev_warn(udma_dev->dev, "segment already exists in DFX.\n"); + return; + } + + seg = kzalloc(sizeof(*seg), GFP_KERNEL); + if (!seg) + return; + + seg->id = cfg->token_id->token_id; + seg->ubva.va = cfg->va; + seg->len = cfg->len; + seg->token_value = cfg->token_value; + if (udma_set_seg_eid(udma_dev, cfg->eid_index, &seg->ubva.eid)) { + kfree(seg); + return; + } + + write_lock(&udma_dev->dfx_info->seg.rwlock); + ret = xa_err(xa_store(&udma_dev->dfx_info->seg.table, cfg->token_id->token_id, + seg, GFP_KERNEL)); + if (ret) { + write_unlock(&udma_dev->dfx_info->seg.rwlock); + dev_err(udma_dev->dev, "store segment to table failed in DFX.\n"); + kfree(seg); + return; + } + + ++udma_dev->dfx_info->seg.cnt; + write_unlock(&udma_dev->dfx_info->seg.rwlock); +} + +static void udma_dfx_delete_seg(struct udma_dev *udma_dev, uint32_t token_id, + uint64_t va) +{ + struct udma_dfx_seg *seg; + + write_lock(&udma_dev->dfx_info->seg.rwlock); + seg = (struct udma_dfx_seg *)xa_load(&udma_dev->dfx_info->seg.table, + token_id); + if (seg && seg->id == token_id && seg->ubva.va == va) { + xa_erase(&udma_dev->dfx_info->seg.table, token_id); + seg->token_value.token = 0; + kfree(seg); + --udma_dev->dfx_info->seg.cnt; + } + write_unlock(&udma_dev->dfx_info->seg.rwlock); +} + struct ubcore_target_seg *udma_register_seg(struct ubcore_device *ub_dev, struct ubcore_seg_cfg *cfg, struct ubcore_udata *udata) @@ -156,6 +251,9 @@ struct ubcore_target_seg *udma_register_seg(struct ubcore_device *ub_dev, } mutex_unlock(&udma_dev->ksva_mutex); + if (dfx_switch) + udma_dfx_store_seg(udma_dev, cfg); + return &seg->core_tseg; err_load_ksva: @@ -204,6 +302,10 @@ int udma_unregister_seg(struct ubcore_target_seg *ubcore_seg) } mutex_unlock(&udma_dev->ksva_mutex); + if (dfx_switch) + udma_dfx_delete_seg(udma_dev, ubcore_seg->token_id->token_id, + ubcore_seg->seg.ubva.va); + common_process: udma_unpin_seg(seg); seg->token_value = 0; -- Gitee From 9449d5469b70db915cd5aeab7c288c543ab303c1 Mon Sep 17 00:00:00 2001 From: Lizhi He Date: Tue, 2 Sep 2025 14:14:15 +0800 Subject: [PATCH 050/103] dma-mapping: benchmark: add support for UB devices commit 72204766a0326d01d1c357357038bd74c1e73825 openEuler The current dma_map benchmark only supports platform devices and PCI devices. This patch adds support for UB devices. Signed-off-by: Xiaofeng Liu Signed-off-by: Li Wentao Signed-off-by: Lizhi He Signed-off-by: zhaolichang <943677312@qq.com> --- kernel/dma/map_benchmark.c | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/kernel/dma/map_benchmark.c b/kernel/dma/map_benchmark.c index cc19a3efea89..23aeba267cfa 100644 --- a/kernel/dma/map_benchmark.c +++ b/kernel/dma/map_benchmark.c @@ -18,6 +18,9 @@ #include #include #include +#ifdef CONFIG_UB_UBUS +#include +#endif struct map_benchmark_data { struct map_benchmark bparam; @@ -351,6 +354,19 @@ static struct pci_driver map_benchmark_pci_driver = { .probe = map_benchmark_pci_probe, }; +#ifdef CONFIG_UB_UBUS +static int map_benchmark_ub_probe(struct ub_entity *uent, + const struct ub_device_id *id) +{ + return __map_benchmark_probe(&uent->dev); +} + +static struct ub_driver map_benchmark_ub_driver = { + .name = "dma_map_benchmark", + .probe = map_benchmark_ub_probe, +}; +#endif + static int __init map_benchmark_init(void) { int ret; @@ -360,16 +376,30 @@ static int __init map_benchmark_init(void) return ret; ret = platform_driver_register(&map_benchmark_platform_driver); - if (ret) { - pci_unregister_driver(&map_benchmark_pci_driver); - return ret; - } + if (ret) + goto err_reg_platform; + +#ifdef CONFIG_UB_UBUS + ret = ub_register_driver(&map_benchmark_ub_driver); + if (ret) + goto err_reg_ub; +#endif return 0; +#ifdef CONFIG_UB_UBUS +err_reg_ub: + platform_driver_unregister(&map_benchmark_platform_driver); +#endif +err_reg_platform: + pci_unregister_driver(&map_benchmark_pci_driver); + return ret; } static void __exit map_benchmark_cleanup(void) { +#ifdef CONFIG_UB_UBUS + ub_unregister_driver(&map_benchmark_ub_driver); +#endif platform_driver_unregister(&map_benchmark_platform_driver); pci_unregister_driver(&map_benchmark_pci_driver); } -- Gitee From 72f8e0a376961ce85a6adb8e5af2e31f3101ea8c Mon Sep 17 00:00:00 2001 From: Yahui Liu Date: Fri, 14 Nov 2025 14:18:53 +0800 Subject: [PATCH 051/103] ub:ubus: call ub_host_probe inside register_ub_manage_subsystem_ops commit 59de5029039dc2a046518ce1cdf5e3bf7bc3ac02 openEuler Call ub_host_probe inside register_ub_manage_subsystem_ops so that ub_host_probe can become static function, same to ub_host_remove. Query entity and port na first, then do the config read in ub_fm_flush_ubc_info because config read will check na. Fix some comment description issues. Signed-off-by: Yahui Liu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/ubus/pool.c | 20 ++-- drivers/ub/ubus/ubus.h | 2 - drivers/ub/ubus/ubus_driver.c | 100 +++++++++++-------- drivers/ub/ubus/ubus_driver.h | 2 - drivers/ub/ubus/vendor/hisilicon/hisi-ubus.c | 7 -- include/ub/ubus/ubus.h | 98 +++++++++--------- 6 files changed, 121 insertions(+), 108 deletions(-) diff --git a/drivers/ub/ubus/pool.c b/drivers/ub/ubus/pool.c index 2aeb8d57ee9a..e86b19b58f63 100644 --- a/drivers/ub/ubus/pool.c +++ b/drivers/ub/ubus/pool.c @@ -456,6 +456,18 @@ int ub_fm_flush_ubc_info(struct ub_bus_controller *ubc) if (!buf) goto out; + ret = ub_query_ent_na(ubc->uent, buf); + if (ret) { + dev_err(dev, "update cluster ubc cna failed, ret=%d\n", ret); + goto free_buf; + } + + ret = ub_query_port_na(ubc->uent, buf); + if (ret) { + dev_err(dev, "update cluster ubc port cna failed, ret=%d\n", ret); + goto free_buf; + } + ret = ub_cfg_read_word(ubc->uent, UB_UPI, &upi); if (ret) { dev_err(dev, "update cluster upi failed, ret=%d\n", ret); @@ -489,14 +501,6 @@ int ub_fm_flush_ubc_info(struct ub_bus_controller *ubc) ubc->uent->fm_cna = fm_cna & UB_FM_CNA_MASK; dev_info(dev, "update cluster ubc fm cna to %#x\n", ubc->uent->fm_cna); - ret = ub_query_ent_na(ubc->uent, buf); - if (ret) { - dev_err(dev, "update cluster ubc cna failed, ret=%d\n", ret); - goto free_buf; - } - - ret = ub_query_port_na(ubc->uent, buf); - free_buf: kfree(buf); out: diff --git a/drivers/ub/ubus/ubus.h b/drivers/ub/ubus/ubus.h index a4b46402e32d..d26e0816b89b 100644 --- a/drivers/ub/ubus/ubus.h +++ b/drivers/ub/ubus/ubus.h @@ -56,8 +56,6 @@ static inline bool ub_entity_test_priv_flag(struct ub_entity *uent, int bit) return test_bit(bit, &uent->priv_flags); } -int ub_host_probe(void); -void ub_host_remove(void); struct ub_bus_controller *ub_find_bus_controller(u32 ctl_no); struct ub_manage_subsystem_ops { diff --git a/drivers/ub/ubus/ubus_driver.c b/drivers/ub/ubus/ubus_driver.c index b4c6f0d3b760..9431bbccd3b0 100644 --- a/drivers/ub/ubus/ubus_driver.c +++ b/drivers/ub/ubus/ubus_driver.c @@ -33,45 +33,12 @@ MODULE_PARM_DESC(entity_flex_en, "Entity Flexible enable: default: 0"); DECLARE_RWSEM(ub_bus_sem); +#define UBC_GUID_VENDOR_SHIFT 48 +#define UBC_GUID_VENDOR_MASK GENMASK(15, 0) + static DEFINE_MUTEX(manage_subsystem_ops_mutex); static const struct ub_manage_subsystem_ops *manage_subsystem_ops; -int register_ub_manage_subsystem_ops(const struct ub_manage_subsystem_ops *ops) -{ - if (!ops) - return -EINVAL; - - mutex_lock(&manage_subsystem_ops_mutex); - if (!manage_subsystem_ops) { - manage_subsystem_ops = ops; - mutex_unlock(&manage_subsystem_ops_mutex); - pr_info("ub manage subsystem ops register successfully\n"); - return 0; - } - - pr_warn("ub manage subsystem ops has been registered\n"); - mutex_unlock(&manage_subsystem_ops_mutex); - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(register_ub_manage_subsystem_ops); - -void unregister_ub_manage_subsystem_ops(const struct ub_manage_subsystem_ops *ops) -{ - if (!ops) - return; - - mutex_lock(&manage_subsystem_ops_mutex); - if (manage_subsystem_ops == ops) { - manage_subsystem_ops = NULL; - pr_info("ub manage subsystem ops unregister successfully\n"); - } else { - pr_warn("ub manage subsystem ops is not registered by this vendor\n"); - } - mutex_unlock(&manage_subsystem_ops_mutex); -} -EXPORT_SYMBOL_GPL(unregister_ub_manage_subsystem_ops); - const struct ub_manage_subsystem_ops *get_ub_manage_subsystem_ops(void) { return manage_subsystem_ops; @@ -653,7 +620,7 @@ static void ubus_driver_resource_drain(void) ub_static_cluster_instance_drain(); } -int ub_host_probe(void) +static int ub_host_probe(void) { int ret; @@ -724,9 +691,8 @@ int ub_host_probe(void) ub_bus_type_uninit(); return ret; } -EXPORT_SYMBOL_GPL(ub_host_probe); -void ub_host_remove(void) +static void ub_host_remove(void) { message_rx_uninit(); if (manage_subsystem_ops && manage_subsystem_ops->ras_handler_remove) @@ -741,7 +707,61 @@ void ub_host_remove(void) unregister_ub_cfg_ops(); ub_bus_type_uninit(); } -EXPORT_SYMBOL_GPL(ub_host_remove); + +int register_ub_manage_subsystem_ops(const struct ub_manage_subsystem_ops *ops) +{ + struct ub_bus_controller *ubc; + int ret; + + if (!ops) { + pr_err("ub manage subsystem ops is NULL\n"); + return -EINVAL; + } + + mutex_lock(&manage_subsystem_ops_mutex); + if (!manage_subsystem_ops) { + list_for_each_entry(ubc, &ubc_list, node) { + if (((ubc->attr.ubc_guid_high >> UBC_GUID_VENDOR_SHIFT) & + UBC_GUID_VENDOR_MASK) == ops->vendor) { + manage_subsystem_ops = ops; + ret = ub_host_probe(); + if (ret) + manage_subsystem_ops = NULL; + else + pr_info("ub manage subsystem ops register successfully\n"); + + mutex_unlock(&manage_subsystem_ops_mutex); + return ret; + } + } + pr_warn("ub manage subsystem ops is not match with any of ub controller\n"); + } else { + pr_warn("ub manage subsystem ops has been registered\n"); + } + mutex_unlock(&manage_subsystem_ops_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(register_ub_manage_subsystem_ops); + +void unregister_ub_manage_subsystem_ops(const struct ub_manage_subsystem_ops *ops) +{ + if (!ops) { + pr_err("ub manage subsystem ops is NULL\n"); + return; + } + + mutex_lock(&manage_subsystem_ops_mutex); + if (manage_subsystem_ops == ops) { + ub_host_remove(); + manage_subsystem_ops = NULL; + pr_info("ub manage subsystem ops unregister successfully\n"); + } else { + pr_warn("ub manage subsystem ops is not registered by this vendor\n"); + } + mutex_unlock(&manage_subsystem_ops_mutex); +} +EXPORT_SYMBOL_GPL(unregister_ub_manage_subsystem_ops); static int __init ubus_driver_init(void) { diff --git a/drivers/ub/ubus/ubus_driver.h b/drivers/ub/ubus/ubus_driver.h index f2bff32bbee9..b2eab906fa31 100644 --- a/drivers/ub/ubus/ubus_driver.h +++ b/drivers/ub/ubus/ubus_driver.h @@ -8,7 +8,5 @@ extern struct rw_semaphore ub_bus_sem; extern struct bus_type ub_service_bus_type; -int ub_host_probe(void); -void ub_host_remove(void); #endif /* __UBUS_DRIVER_H__ */ diff --git a/drivers/ub/ubus/vendor/hisilicon/hisi-ubus.c b/drivers/ub/ubus/vendor/hisilicon/hisi-ubus.c index be86f055cb34..3627b0e8f018 100644 --- a/drivers/ub/ubus/vendor/hisilicon/hisi-ubus.c +++ b/drivers/ub/ubus/vendor/hisilicon/hisi-ubus.c @@ -53,10 +53,6 @@ static int __init hisi_ubus_driver_register(struct platform_driver *drv) if (ret) return ret; - ret = ub_host_probe(); - if (ret) - goto host_probe_fail; - ret = platform_driver_register(drv); if (ret) goto platform_driver_register_fail; @@ -64,8 +60,6 @@ static int __init hisi_ubus_driver_register(struct platform_driver *drv) return 0; platform_driver_register_fail: - ub_host_remove(); -host_probe_fail: unregister_ub_manage_subsystem_ops(&hisi_ub_manage_subsystem_ops); return ret; } @@ -73,7 +67,6 @@ static int __init hisi_ubus_driver_register(struct platform_driver *drv) static void __exit hisi_ubus_driver_unregister(struct platform_driver *drv) { platform_driver_unregister(drv); - ub_host_remove(); unregister_ub_manage_subsystem_ops(&hisi_ub_manage_subsystem_ops); } diff --git a/include/ub/ubus/ubus.h b/include/ub/ubus/ubus.h index a81d652a18ff..ca3ba63c226a 100644 --- a/include/ub/ubus/ubus.h +++ b/include/ub/ubus/ubus.h @@ -193,7 +193,7 @@ struct ub_entity { u32 token_id; u32 token_value; - /* mue & ue info */ + /* MUE & UE info */ u8 is_mue; u16 total_ues; u16 num_ues; @@ -205,7 +205,7 @@ struct ub_entity { /* entity topology info */ struct list_head node; struct ub_bus_controller *ubc; - struct ub_entity *pue; /* ue/mue connected to their mue */ + struct ub_entity *pue; /* UE/MUE connected to their MUE */ int topo_rank; /* The levels of Breadth-First Search */ /* entity port info */ @@ -334,10 +334,10 @@ struct ub_dynids { * @shutdown: Hook into reboot_notifier_list (kernel/sys.c). * Intended to stop any idling operations. * @virt_configure: Optional driver callback to allow configuration of - * ues. This function is called to enable or disable ues. + * UEs. This function is called to enable or disable UEs. * @virt_notify: Optional driver callback to notify the driver about - * changes in ue status. This function is called - * when the status of a ue changes. + * changes in UE status. This function is called + * when the status of a UE changes. * @activate: Activate a specific entity. This function is called to * activate an entity by its index. * @deactivate: Deactivate a specific entity. This function is called to @@ -510,14 +510,14 @@ void ub_bus_type_iommu_ops_set(const struct iommu_ops *ops); const struct iommu_ops *ub_bus_type_iommu_ops_get(void); /** - * ub_get_ent_by_eid() - Searching for UB Devices by EID. + * ub_get_ent_by_eid() - Searching for UB entity by EID. * @eid: entity EID. * * Traverse the UB bus device linked list and search for the device with * the target EID. You need to call ub_entity_put() after using it. * * Context: Any context. - * Return: The device found, or NULL if not found. + * Return: The entity found, or NULL if not found. */ struct ub_entity *ub_get_ent_by_eid(unsigned int eid); @@ -566,8 +566,7 @@ struct ub_entity *ub_get_entity(unsigned int vendor, unsigned int entity, * @uent: UB entity. * @enable: Enable or disable. * - * Enables or disables the entity access bus and the path through which - * the bus accesses the entity. + * Enable or disable the communication channel between entity and user host. * * Context: Any context. */ @@ -588,31 +587,31 @@ int ub_set_user_info(struct ub_entity *uent); * ub_unset_user_info() - Deinitialize host information for the entity. * @uent: UB entity. * - * Clearing the Host Information of a entity. + * Clearing the host information of an entity. * * Context: Any context. */ void ub_unset_user_info(struct ub_entity *uent); /** - * ub_enable_entities() - Enable ues of mue in batches. - * @pue: UB mue. + * ub_enable_entities() - Enable UEs of MUE in batches. + * @pue: UB MUE. * @nums: Number of enabled entities. * - * Create ues in batches, initialize them, and add them to the system. + * Create and initialize UEs in batches and add to the system. * * Context: Any context. - * Return: 0 if success, or %-EINVAL if @pue type is not mue or nums over - * mue's total ue nums, or %-ENOMEM if the system is out of memory, + * Return: 0 if success, or %-EINVAL if @pue type is not MUE or nums over + * MUE's total UE nums, or %-ENOMEM if the system is out of memory, * or other failed negative values. */ int ub_enable_entities(struct ub_entity *pue, int nums); /** - * ub_disable_entities() - Disable ues of mue in batches. - * @pue: UB mue. + * ub_disable_entities() - Disable UEs of MUE in batches. + * @pue: UB MUE. * - * Remove all enabled ues under the mue from the system. + * Remove all enabled UEs under the MUE from the system. * * Context: Any context. */ @@ -620,29 +619,29 @@ void ub_disable_entities(struct ub_entity *pue); /** * ub_enable_ue() - Enable a single ue. - * @pue: UB mue. + * @pue: UB MUE. * @entity_idx: Number of the entity to be enabled. * - * Create a specified ue under mue, initialize the ue, + * Create a specified UE under MUE, initialize the ue, * and add it to the system. * * Context: Any context. - * Return: 0 if success, or %-EINVAL if @pue type is not mue or @entity_idx - * is no longer in the ue range of mue, or %-EEXIST if entity has been + * Return: 0 if success, or %-EINVAL if @pue type is not MUE or @entity_idx + * is no longer in the UE range of MUE, or %-EEXIST if entity has been * enabled, or other failed negative values. */ int ub_enable_ue(struct ub_entity *pue, int entity_idx); /** * ub_disable_ue() - Disable a single ue. - * @pue: UB mue. + * @pue: UB MUE. * @entity_idx: Number of the entity to be disabled. * - * Remove a specified ue. + * Remove a specified UE. * * Context: Any context. - * Return: 0 if success, or %-EINVAL if @pue type is not mue or @entity_idx - * is no longer in the ue range of mue, or %-ENODEV if entity hasn't + * Return: 0 if success, or %-EINVAL if @pue type is not MUE or @entity_idx + * is no longer in the UE range of MUE, or %-ENODEV if entity hasn't * been enabled. */ int ub_disable_ue(struct ub_entity *pue, int entity_idx); @@ -662,7 +661,7 @@ bool ub_get_entity_flex_en(void); * @uent: UB entity. * * Return the EID of bus instance if the entity has already been bound, - * or controller's EID. + * otherwise return controller's EID. * * Context: Any context. * Return: positive number if success, or %-EINVAL if @dev is %NULL, @@ -743,7 +742,7 @@ void ub_unregister_share_port(struct ub_entity *uent, u16 port_id, * ub_reset_entity() - Function entity level reset. * @ent: UB entity. * - * Reset a single entity without affecting other entities, If you want to reuse + * Reset a single entity without affecting other entities. If you want to reuse * the entity after reset, you need to re-initialize it. * * Context: Any context @@ -757,7 +756,7 @@ int ub_reset_entity(struct ub_entity *ent); * ub_device_reset() - Device level reset. * @ent: UB entity. * - * Reset Device, include all entities under the device, If you want to reuse + * Reset device, including all entities under the device. If you want to reuse * the device after reset, you need to re-initialize it. * * Context: Any context @@ -771,10 +770,10 @@ int ub_device_reset(struct ub_entity *ent); * @uent: UB entity. * @vdm_pld: Vendor private message payload context. * - * Send a vendor private message to the entity. Response will put in - * vdm_pld->rsp_pld, and will fill in vdm->rsp_pld_len. + * Send a vendor private message to the entity. Response will be put in + * vdm_pld->rsp_pld, and response length is stored in vdm->rsp_pld_len. * - * Context: Any context, It will take spin_lock_irqsave()/spin_unlock_restore() + * Context: Any context, it will take spin_lock_irqsave()/spin_unlock_restore() * Return: 0 if success, or %-EINVAL if parameters invalid, * or %-ENOMEM if system out of memory, or other failed negative values. */ @@ -796,10 +795,10 @@ unsigned int ub_irq_calc_affinity_vectors(unsigned int minvec, void ub_disable_intr(struct ub_entity *uent); /** - * ub_intr_vec_count() - Interrupt Vectors Supported by a entity. + * ub_intr_vec_count() - Interrupt Vectors Supported by an entity. * @uent: UB entity. * - * Querying the Number of Interrupt Vectors Supported by a entity. + * Querying the Number of Interrupt Vectors Supported by an entity. * For interrupt type 2. * * Context: Any context. @@ -808,10 +807,10 @@ void ub_disable_intr(struct ub_entity *uent); u32 ub_intr_vec_count(struct ub_entity *uent); /** - * ub_int_type1_vec_count() - Interrupt Vectors Supported by a entity. + * ub_int_type1_vec_count() - Interrupt Vectors Supported by an entity. * @uent: UB entity. * - * Querying the Number of Interrupt Vectors Supported by a entity. + * Querying the Number of Interrupt Vectors Supported by an entity. * For interrupt type 1. * * Context: Any context. @@ -864,7 +863,7 @@ static inline int ub_alloc_irq_vectors(struct ub_entity *uent, int ub_irq_vector(struct ub_entity *uent, unsigned int nr); /** - * ub_irq_get_affinity() - Get a entity interrupt vector affinity + * ub_irq_get_affinity() - Get an entity interrupt vector affinity * @uent: the UB entity to operate on * @nr: entity-relative interrupt vector index (0-based); has different * meanings, depending on interrupt mode: @@ -884,7 +883,7 @@ const struct cpumask *ub_irq_get_affinity(struct ub_entity *uent, int nr); * @uent: UB entity. * @entity_idx: Number of the entity to be activated. * - * Context: Any context, It will take device_trylock()/device_unlock() + * Context: Any context, it will take device_trylock()/device_unlock() * Return: 0 if success, or %-EINVAL if the device doesn't match the driver, * or %-EBUSY if can't get device_trylock(), or other failed negative values. */ @@ -895,7 +894,7 @@ int ub_activate_entity(struct ub_entity *uent, u32 entity_idx); * @uent: UB entity. * @entity_idx: Number of the entity to be deactivated. * - * Context: Any context, It will take device_trylock()/device_unlock() + * Context: Any context, it will take device_trylock()/device_unlock() * Return: 0 if success, or %-EINVAL if the entity doesn't match the driver, * or %-EBUSY if can't get device_trylock(), or other failed negative values. */ @@ -910,7 +909,7 @@ int ub_deactivate_entity(struct ub_entity *uent, u32 entity_idx); * Initiate configuration access to the specified address of the entity * configuration space and read 1 byte. * - * Context: Any context, It will take spin_lock_irqsave()/spin_unlock_restore() + * Context: Any context, it will take spin_lock_irqsave()/spin_unlock_restore() * Return: 0 if success, or negative value if failed. */ int ub_cfg_read_byte(struct ub_entity *uent, u64 pos, u8 *val); @@ -925,7 +924,7 @@ int ub_cfg_read_dword(struct ub_entity *uent, u64 pos, u32 *val); * Initiate configuration access to the specified address of the entity * configuration space and write 1 byte. * - * Context: Any context, It will take spin_lock_irqsave()/spin_unlock_restore() + * Context: Any context, it will take spin_lock_irqsave()/spin_unlock_restore() * Return: 0 if success, or negative value if failed. */ int ub_cfg_write_byte(struct ub_entity *uent, u64 pos, u8 val); @@ -937,7 +936,7 @@ int ub_cfg_write_dword(struct ub_entity *uent, u64 pos, u32 val); * @uent: UB entity pointer. * * Context: Any context. - * Return: uent, or NULL if @uent is NULL. + * Return: @uent itself, or NULL if @uent is NULL. */ struct ub_entity *ub_entity_get(struct ub_entity *uent); @@ -955,9 +954,9 @@ void ub_entity_put(struct ub_entity *uent); * @max_num: Buffer size. * @real_num: Real entities num. * - * All ub bus controllers in the system are returned. Increase the reference - * counting of all entities by 1. Remember to call ub_put_bus_controller() after - * using it. + * All ub bus controllers in the system are collected in @uents. Increase the + * reference counting of all entities by 1. Remember to call + * ub_put_bus_controller() after using it. * * Context: Any context. * Return: 0 if success, or %-EINVAL if input parameter is NULL, @@ -1020,8 +1019,8 @@ void ub_unregister_driver(struct ub_driver *drv); * ub_stop_ent() - Stop the entity. * @uent: UB entity. * - * Call device_release_driver(), user can't use it again, if it's a mue, - * will stop all ues under it, if it's entity0, will stop all entity under it. + * Call device_release_driver(), user can't use it again. If it's a MUE, + * will stop all UEs under it. If it's entity0, will stop all entities under it. * * Context: Any context. */ @@ -1031,8 +1030,9 @@ void ub_stop_ent(struct ub_entity *uent); * ub_stop_and_remove_ent() - Stop and remove the entity from system. * @uent: UB entity. * - * Call device_release_driver() and device_unregister(), if it's a mue, - * will remove all ues under it, if it's entity0, will remove all entity under it. + * Call device_release_driver() and device_unregister(). If it's a MUE, + * will remove all UEs under it. If it's entity0, will remove all entities + * under it. * * Context: Any context. */ -- Gitee From ebd7fc0aca8adc064b30c823da4e33420cdc7e75 Mon Sep 17 00:00:00 2001 From: Haibin Lu Date: Wed, 24 Sep 2025 15:26:09 +0800 Subject: [PATCH 052/103] net: unic: Support driver dump register. commit 8ca3dec3d53e6bd47e70f9f599ace2a704aaf85e openEuler Currently, the commit operation contains only the framework of dump registers and does not contain the specific register address of the bar space. This patch complete functions: 1.Add tlv format data to registers data. 2.Register information can be obtained from the firmware and bar space. Signed-off-by: Jianqiang Li Signed-off-by: Xiongchuan Zhou Signed-off-by: Haibin Lu Signed-off-by: Junxin Chen Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/net/ub/unic/unic_dev.h | 17 ++ drivers/net/ub/unic/unic_ethtool.c | 2 + drivers/net/ub/unic/unic_stats.c | 286 +++++++++++++++++++++++++++++ drivers/net/ub/unic/unic_stats.h | 70 +++++++ include/ub/ubase/ubase_comm_cmd.h | 6 + 5 files changed, 381 insertions(+) diff --git a/drivers/net/ub/unic/unic_dev.h b/drivers/net/ub/unic/unic_dev.h index f0df795ad011..8654aa9a819e 100644 --- a/drivers/net/ub/unic/unic_dev.h +++ b/drivers/net/ub/unic/unic_dev.h @@ -262,6 +262,11 @@ static inline bool unic_dev_ubl_supported(struct unic_dev *unic_dev) return ubase_adev_ubl_supported(unic_dev->comdev.adev); } +static inline bool unic_dev_eth_mac_supported(struct unic_dev *unic_dev) +{ + return ubase_adev_eth_mac_supported(unic_dev->comdev.adev); +} + static inline bool unic_dev_ets_supported(struct unic_dev *unic_dev) { return unic_get_cap_bit(unic_dev, UNIC_SUPPORT_ETS_B); @@ -327,6 +332,18 @@ static inline bool unic_is_initing_or_resetting(struct unic_dev *unic_dev) return __unic_resetting(unic_dev) || __unic_initing(unic_dev); } +static inline u32 unic_read_reg(struct unic_dev *unic_dev, u32 reg) +{ + struct ubase_resource_space *io_base = ubase_get_io_base(unic_dev->comdev.adev); + u8 __iomem *reg_addr; + + if (!io_base) + return 0; + + reg_addr = READ_ONCE(io_base->addr); + return readl(reg_addr + reg); +} + static inline u32 unic_get_sq_cqe_mask(struct unic_dev *unic_dev) { return unic_dev->channels.sq_cqe_depth - 1; diff --git a/drivers/net/ub/unic/unic_ethtool.c b/drivers/net/ub/unic/unic_ethtool.c index 9e50f0332d4e..474626833d89 100644 --- a/drivers/net/ub/unic/unic_ethtool.c +++ b/drivers/net/ub/unic/unic_ethtool.c @@ -122,6 +122,8 @@ static const struct ethtool_ops unic_ethtool_ops = { .get_link = unic_get_link_status, .get_link_ksettings = unic_get_link_ksettings, .get_drvinfo = unic_get_driver_info, + .get_regs_len = unic_get_regs_len, + .get_regs = unic_get_regs, .get_channels = unic_get_channels, .set_channels = unic_set_channels, .get_ringparam = unic_get_channels_param, diff --git a/drivers/net/ub/unic/unic_stats.c b/drivers/net/ub/unic/unic_stats.c index 8167bb6a6fca..dcefeab1bb2d 100644 --- a/drivers/net/ub/unic/unic_stats.c +++ b/drivers/net/ub/unic/unic_stats.c @@ -14,6 +14,292 @@ #include "unic_netdev.h" #include "unic_stats.h" +static u32 cmdq_regs_addr[] = { + UNIC_TX_CMDQ_DEPTH, + UNIC_TX_CMDQ_TAIL, + UNIC_TX_CMDQ_HEAD, + UNIC_RX_CMDQ_DEPTH, + UNIC_RX_CMDQ_TAIL, + UNIC_RX_CMDQ_HEAD, + UNIC_CMDQ_INT_GEN, + UNIC_CMDQ_INT_SCR, + UNIC_CMDQ_INT_MASK, + UNIC_CMDQ_INT_STS, +}; + +static u32 ctrlq_regs_addr[] = { + UNIC_TX_CTRLQ_DEPTH, + UNIC_TX_CTRLQ_TAIL, + UNIC_TX_CTRLQ_HEAD, + UNIC_RX_CTRLQ_DEPTH, + UNIC_RX_CTRLQ_TAIL, + UNIC_RX_CTRLQ_HEAD, + UNIC_CTRLQ_INT_GEN, + UNIC_CTRLQ_INT_SCR, + UNIC_CTRLQ_INT_MASK, + UNIC_CTRLQ_INT_STS, +}; + +static const struct unic_res_regs_group unic_res_reg_arr[] = { + { + UNIC_TAG_CMDQ, cmdq_regs_addr, ARRAY_SIZE(cmdq_regs_addr), + NULL + }, { + UNIC_TAG_CTRLQ, ctrlq_regs_addr, ARRAY_SIZE(ctrlq_regs_addr), + ubase_adev_ctrlq_supported + }, +}; + +static bool unic_dfx_reg_support(struct unic_dev *unic_dev, u32 property) +{ + if (((property & UBASE_SUP_UBL) && unic_dev_ubl_supported(unic_dev)) || + ((property & UBASE_SUP_ETH) && unic_dev_eth_mac_supported(unic_dev))) + return true; + + return false; +} + +static struct unic_dfx_regs_group unic_dfx_reg_arr[] = { + { + UNIC_REG_NUM_IDX_TA, UNIC_TAG_TA, UBASE_OPC_DFX_TA_REG, + UBASE_SUP_UBL_ETH, unic_dfx_reg_support + }, { + UNIC_REG_NUM_IDX_TP, UNIC_TAG_TP, UBASE_OPC_DFX_TP_REG, + UBASE_SUP_UBL_ETH, unic_dfx_reg_support + }, { + UNIC_REG_NUM_IDX_BA, UNIC_TAG_BA, UBASE_OPC_DFX_BA_REG, + UBASE_SUP_UBL_ETH, unic_dfx_reg_support + }, { + UNIC_REG_NUM_IDX_NL, UNIC_TAG_NL, UBASE_OPC_DFX_NL_REG, + UBASE_SUP_UBL_ETH, unic_dfx_reg_support + }, { + UNIC_REG_NUM_IDX_DL, UNIC_TAG_DL, UBASE_OPC_DFX_DL_REG, + UBASE_SUP_UBL, unic_dfx_reg_support + }, +}; + +static int unic_get_dfx_reg_num(struct unic_dev *unic_dev, u32 *reg_num, + u32 reg_arr_size) +{ + struct ubase_cmd_buf in, out; + int ret; + + ubase_fill_inout_buf(&in, UBASE_OPC_DFX_REG_NUM, true, 0, NULL); + ubase_fill_inout_buf(&out, UBASE_OPC_DFX_REG_NUM, true, + reg_arr_size * sizeof(u32), reg_num); + ret = ubase_cmd_send_inout(unic_dev->comdev.adev, &in, &out); + if (ret && ret != -EPERM) + unic_err(unic_dev, + "failed to query dfx reg num, ret = %d.\n", ret); + + return ret; +} + +static int unic_get_res_regs_len(struct unic_dev *unic_dev, + const struct unic_res_regs_group *reg_arr, + u32 reg_arr_size) +{ + u32 i, count = 0; + + for (i = 0; i < reg_arr_size; i++) { + if (reg_arr[i].is_supported && + !reg_arr[i].is_supported(unic_dev->comdev.adev)) + continue; + + count += reg_arr[i].regs_count * sizeof(u32) + + sizeof(struct unic_tlv_hdr); + } + + return count; +} + +static int unic_get_dfx_regs_len(struct unic_dev *unic_dev, + struct unic_dfx_regs_group *reg_arr, + u32 reg_arr_size, u32 *reg_num) +{ + u32 i, count = 0; + + for (i = 0; i < reg_arr_size; i++) { + if (!reg_arr[i].is_supported(unic_dev, reg_arr[i].property)) + continue; + + count += sizeof(struct unic_tlv_hdr) + sizeof(u32) * + reg_num[reg_arr[i].regs_idx]; + } + + return count; +} + +int unic_get_regs_len(struct net_device *netdev) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + u32 reg_arr_size; + int count = 0; + u32 *reg_num; + int ret; + + if (unic_resetting(netdev)) + return -EBUSY; + + count += unic_get_res_regs_len(unic_dev, unic_res_reg_arr, + ARRAY_SIZE(unic_res_reg_arr)); + reg_arr_size = ARRAY_SIZE(unic_dfx_reg_arr); + reg_num = kcalloc(reg_arr_size, sizeof(u32), GFP_KERNEL); + if (!reg_num) + return -ENOMEM; + + ret = unic_get_dfx_reg_num(unic_dev, reg_num, reg_arr_size); + if (!ret) { + count += unic_get_dfx_regs_len(unic_dev, unic_dfx_reg_arr, + reg_arr_size, reg_num); + } else if (ret != -EPERM) { + unic_err(unic_dev, + "failed to get dfx regs length, ret = %d.\n", ret); + kfree(reg_num); + + return -EBUSY; + } + + kfree(reg_num); + + return count; +} + +static u16 unic_fetch_res_regs(struct unic_dev *unic_dev, u8 *data, u16 tag, + u32 *regs_addr_arr, u32 reg_num) +{ + struct unic_tlv_hdr *tlv = (struct unic_tlv_hdr *)data; + u32 *reg = (u32 *)(data + sizeof(struct unic_tlv_hdr)); + u32 i; + + tlv->tag = tag; + tlv->len = sizeof(struct unic_tlv_hdr) + reg_num * sizeof(u32); + + for (i = 0; i < reg_num; i++) + *reg++ = unic_read_reg(unic_dev, regs_addr_arr[i]); + + return tlv->len; +} + +static u32 unic_get_res_regs(struct unic_dev *unic_dev, u8 *data) +{ + u32 i, data_len = 0; + + for (i = 0; i < ARRAY_SIZE(unic_res_reg_arr); i++) { + if (unic_res_reg_arr[i].is_supported && + !unic_res_reg_arr[i].is_supported(unic_dev->comdev.adev)) + continue; + + data_len += unic_fetch_res_regs(unic_dev, data + data_len, + unic_res_reg_arr[i].tag, + unic_res_reg_arr[i].regs_addr, + unic_res_reg_arr[i].regs_count); + } + + return data_len; +} + +static int unic_query_regs_data(struct unic_dev *unic_dev, u8 *data, + u32 reg_num, u16 opcode) +{ + u32 *reg = (u32 *)(data + sizeof(struct unic_tlv_hdr)); + struct ubase_cmd_buf in, out; + u32 *out_regs; + int ret; + u32 i; + + out_regs = kcalloc(reg_num, sizeof(u32), GFP_KERNEL); + if (!out_regs) + return -ENOMEM; + + ubase_fill_inout_buf(&in, opcode, true, 0, NULL); + ubase_fill_inout_buf(&out, opcode, true, reg_num * sizeof(u32), + out_regs); + ret = ubase_cmd_send_inout(unic_dev->comdev.adev, &in, &out); + if (ret) { + unic_err(unic_dev, + "failed to send getting reg cmd(0x%x), ret = %d.\n", + opcode, ret); + goto err_send_cmd; + } + + for (i = 0; i < reg_num; i++) + *reg++ = le32_to_cpu(*(out_regs + i)); + +err_send_cmd: + kfree(out_regs); + + return ret; +} + +static int unic_get_dfx_regs(struct unic_dev *unic_dev, u8 *data, + struct unic_dfx_regs_group *reg_arr, + u32 reg_arr_size, u32 *reg_num) +{ + struct unic_tlv_hdr *tlv; + u16 idx; + int ret; + u32 i; + + for (i = 0; i < reg_arr_size; i++) { + if (!reg_arr[i].is_supported(unic_dev, reg_arr[i].property)) + continue; + + idx = reg_arr[i].regs_idx; + ret = unic_query_regs_data(unic_dev, data, reg_num[idx], + reg_arr[i].opcode); + if (ret) { + unic_err(unic_dev, + "failed to query dfx regs, ret = %d.\n", ret); + return ret; + } + + tlv = (struct unic_tlv_hdr *)data; + tlv->tag = reg_arr[i].tag; + tlv->len = sizeof(*tlv) + reg_num[idx] * sizeof(u32); + data += tlv->len; + } + + return 0; +} + +void unic_get_regs(struct net_device *netdev, struct ethtool_regs *cmd, + void *data) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + u8 *pdata = (u8 *)data; + u32 reg_arr_size; + u32 *reg_num; + int ret; + + if (unic_resetting(netdev)) { + unic_err(unic_dev, "dev resetting, could not get regs.\n"); + return; + } + + reg_arr_size = ARRAY_SIZE(unic_dfx_reg_arr); + reg_num = kcalloc(reg_arr_size, sizeof(u32), GFP_KERNEL); + if (!reg_num) { + unic_err(unic_dev, "failed to alloc reg num array.\n"); + return; + } + + pdata += unic_get_res_regs(unic_dev, pdata); + ret = unic_get_dfx_reg_num(unic_dev, reg_num, reg_arr_size); + if (!ret) { + ret = unic_get_dfx_regs(unic_dev, pdata, unic_dfx_reg_arr, + reg_arr_size, reg_num); + if (ret) + unic_err(unic_dev, + "failed to get dfx regs, ret = %d.\n", ret); + } else if (ret != -EPERM) { + unic_err(unic_dev, + "failed to get dfx reg num, ret = %d.\n", ret); + } + + kfree(reg_num); +} + static void unic_get_fec_stats_total(struct unic_dev *unic_dev, u8 stats_flags, struct ethtool_fec_stats *fec_stats) { diff --git a/drivers/net/ub/unic/unic_stats.h b/drivers/net/ub/unic/unic_stats.h index d9d9f0b0ee3b..2a2a8746d838 100644 --- a/drivers/net/ub/unic/unic_stats.h +++ b/drivers/net/ub/unic/unic_stats.h @@ -16,6 +16,76 @@ #define UNIC_FEC_UNCORR_BLOCKS BIT(1) #define UNIC_FEC_CORR_BITS BIT(2) +#define UNIC_TX_CMDQ_DEPTH UBASE_CSQ_DEPTH_REG +#define UNIC_TX_CMDQ_TAIL UBASE_CSQ_TAIL_REG +#define UNIC_TX_CMDQ_HEAD UBASE_CSQ_HEAD_REG +#define UNIC_RX_CMDQ_DEPTH UBASE_CRQ_DEPTH_REG +#define UNIC_RX_CMDQ_TAIL UBASE_CRQ_TAIL_REG +#define UNIC_RX_CMDQ_HEAD UBASE_CRQ_HEAD_REG +#define UNIC_CMDQ_INT_GEN 0x18000 +#define UNIC_CMDQ_INT_SCR 0x18004 +#define UNIC_CMDQ_INT_MASK 0x18008 +#define UNIC_CMDQ_INT_STS 0x1800c + +#define UNIC_TX_CTRLQ_DEPTH UBASE_CTRLQ_CSQ_DEPTH_REG +#define UNIC_TX_CTRLQ_TAIL UBASE_CTRLQ_CSQ_TAIL_REG +#define UNIC_TX_CTRLQ_HEAD UBASE_CTRLQ_CSQ_HEAD_REG +#define UNIC_RX_CTRLQ_DEPTH UBASE_CTRLQ_CRQ_DEPTH_REG +#define UNIC_RX_CTRLQ_TAIL UBASE_CTRLQ_CRQ_TAIL_REG +#define UNIC_RX_CTRLQ_HEAD UBASE_CTRLQ_CRQ_HEAD_REG +#define UNIC_CTRLQ_INT_GEN 0x18010 +#define UNIC_CTRLQ_INT_SCR 0x18014 +#define UNIC_CTRLQ_INT_MASK 0x18018 +#define UNIC_CTRLQ_INT_STS 0x1801c + +enum unic_reg_num_idx { + UNIC_REG_NUM_IDX_DL = 0, + UNIC_REG_NUM_IDX_NL, + UNIC_REG_NUM_IDX_BA, + UNIC_REG_NUM_IDX_TP, + UNIC_REG_NUM_IDX_TA, + UNIC_REG_NUM_IDX_MAX, +}; + +enum unic_reg_tag { + UNIC_TAG_CMDQ = 0, + UNIC_TAG_CTRLQ, + UNIC_TAG_DL, + UNIC_TAG_NL, + UNIC_TAG_BA, + UNIC_TAG_TP, + UNIC_TAG_TA, + UNIC_TAG_MAX, +}; + +struct unic_res_regs_group { + u16 tag; + u32 *regs_addr; + u32 regs_count; + bool (*is_supported)(struct auxiliary_device *adev); +}; + +struct unic_dump_reg_hdr { + u8 flag; + u8 rsv[3]; +}; + +struct unic_tlv_hdr { + u16 tag; + u16 len; +}; + +struct unic_dfx_regs_group { + u16 regs_idx; + u16 tag; + u16 opcode; + u32 property; + bool (*is_supported)(struct unic_dev *unic_dev, u32 property); +}; + +int unic_get_regs_len(struct net_device *netdev); +void unic_get_regs(struct net_device *netdev, struct ethtool_regs *cmd, + void *data); void unic_get_fec_stats(struct net_device *ndev, struct ethtool_fec_stats *fec_stats); diff --git a/include/ub/ubase/ubase_comm_cmd.h b/include/ub/ubase/ubase_comm_cmd.h index 311a309d10bd..4eb3c435a8f9 100644 --- a/include/ub/ubase/ubase_comm_cmd.h +++ b/include/ub/ubase/ubase_comm_cmd.h @@ -36,6 +36,12 @@ enum ubase_opcode_type { UBASE_OPC_CFG_MTU = 0x0033, UBASE_OPC_QUERY_NET_GUID = 0x0035, UBASE_OPC_STATS_MAC_ALL = 0x0038, + UBASE_OPC_DFX_REG_NUM = 0x0039, + UBASE_OPC_DFX_DL_REG = 0x0040, + UBASE_OPC_DFX_NL_REG = 0x0042, + UBASE_OPC_DFX_BA_REG = 0x0043, + UBASE_OPC_DFX_TP_REG = 0x0044, + UBASE_OPC_DFX_TA_REG = 0x0045, UBASE_OPC_QUERY_BUS_EID = 0x0047, UBASE_OPC_QUERY_UBCL_CONFIG = 0x0050, -- Gitee From dedaafc9147117b18adda39b32a8c1ff1f75cb2f Mon Sep 17 00:00:00 2001 From: Junxin Chen Date: Sat, 30 Aug 2025 15:20:46 +0800 Subject: [PATCH 053/103] net: unic: Add debugfs for JFS/JFR/JFC context. commit 615725081a2520ed66c0265c65964fd718f563dd openEuler This patch adds debugfs support for JFS, JFR, and JFC contexts in the UNIC driver. The new debugfs interface allows users to dump and inspect the software and hardware configurations of these contexts, including their states, registers, and related parameters. The implementation includes: 1. New debugfs files (unic_ctx_debugfs.c and unic_ctx_debugfs.h) to handle context dumping. 2. Extended debugfs commands to support JFS, JFR, and JFC contexts in both software and hardware modes. 3. Integration with the existing debugfs framework to expose these new debug features. This enhancement improves the debugging and troubleshooting capabilities for the UNIC driver by providing detailed visibility into the internal states of JFS, JFR, and JFC contexts. Signed-off-by: Peng Li Signed-off-by: Xiongchuan Zhou Signed-off-by: Haibin Lu Signed-off-by: Junxin Chen Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/net/ub/unic/Makefile | 1 + .../net/ub/unic/debugfs/unic_ctx_debugfs.c | 365 ++++++++++++++++++ .../net/ub/unic/debugfs/unic_ctx_debugfs.h | 19 + drivers/net/ub/unic/debugfs/unic_debugfs.c | 62 +++ drivers/net/ub/unic/debugfs/unic_debugfs.h | 1 + 5 files changed, 448 insertions(+) create mode 100644 drivers/net/ub/unic/debugfs/unic_ctx_debugfs.c create mode 100644 drivers/net/ub/unic/debugfs/unic_ctx_debugfs.h diff --git a/drivers/net/ub/unic/Makefile b/drivers/net/ub/unic/Makefile index 1419ee569595..67ecd0ad8c11 100644 --- a/drivers/net/ub/unic/Makefile +++ b/drivers/net/ub/unic/Makefile @@ -9,4 +9,5 @@ ccflags-y += -I$(srctree)/drivers/net/ub/unic/debugfs obj-$(CONFIG_UB_UNIC) += unic.o unic-objs = unic_main.o unic_ethtool.o unic_hw.o unic_guid.o unic_netdev.o unic_dev.o unic_qos_hw.o unic_event.o unic_crq.o unic-objs += unic_channel.o debugfs/unic_debugfs.o unic_rx.o unic_tx.o unic_txrx.o unic_comm_addr.o unic_rack_ip.o unic_stats.o +unic-objs += debugfs/unic_ctx_debugfs.o unic-$(CONFIG_UB_UNIC_DCB) += unic_dcbnl.o diff --git a/drivers/net/ub/unic/debugfs/unic_ctx_debugfs.c b/drivers/net/ub/unic/debugfs/unic_ctx_debugfs.c new file mode 100644 index 000000000000..fc0d19fee038 --- /dev/null +++ b/drivers/net/ub/unic/debugfs/unic_ctx_debugfs.c @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. + * + */ + +#include +#include +#include +#include + +#include "unic_ctx_debugfs.h" +#include "unic_debugfs.h" +#include "unic_dev.h" + +static inline void unic_jfs_ctx_titles_print(struct seq_file *s) +{ + seq_puts(s, "SQ_ID SQE_BB_SHIFT STATE JFS_MODE TX_JFCN\n"); +} + +static void unic_dump_jfs_ctx_info_sw(struct unic_sq *sq, struct seq_file *s, + u32 index) +{ + struct unic_jfs_ctx *ctx = &sq->jfs_ctx; + + seq_printf(s, "%-7u", index); + seq_printf(s, "%-14u", ctx->sqe_bb_shift); + seq_printf(s, "%-7u", ctx->state); + seq_printf(s, "%-10u", ctx->jfs_mode); + seq_printf(s, "%-9u\n", ctx->tx_jfcn); +} + +static inline void unic_jfr_ctx_titles_print(struct seq_file *s) +{ + seq_puts(s, "RQ_ID STATE RQE_SHIFT RX_JFCN PI CI"); + seq_puts(s, "RECORD_DB_EN\n"); +} + +static void unic_dump_jfr_ctx_info_sw(struct unic_rq *rq, struct seq_file *s, + u32 index) +{ + struct unic_jfr_ctx *ctx = &rq->jfr_ctx; + u32 jfcn; + + jfcn = ctx->jfcn_l | (ctx->jfcn_h << UNIC_JFR_JFCN_H_OFFSET); + + seq_printf(s, "%-7u", index); + seq_printf(s, "%-7u", ctx->state); + seq_printf(s, "%-11u", ctx->rqe_shift); + seq_printf(s, "%-9u", jfcn); + seq_printf(s, "%-7u", ctx->pi); + seq_printf(s, "%-7u", ctx->ci); + seq_printf(s, "%-14u\n", ctx->record_db_en); +} + +static inline void unic_jfc_ctx_titles_print(struct seq_file *s) +{ + seq_puts(s, "CQ_ID ARM_ST STATE INLINE_EN SHIFT CQE_COAL_CNT"); + seq_puts(s, "CEQN RECORD_DB_EN CQE_COAL_PEIRIOD\n"); +} + +static void unic_dump_jfc_ctx_info_sw(struct unic_cq *cq, struct seq_file *s, + u32 index) +{ + struct unic_jfc_ctx *ctx = &cq->jfc_ctx; + + seq_printf(s, "%-7u", index); + seq_printf(s, "%-8u", ctx->arm_st); + seq_printf(s, "%-7u", ctx->state); + seq_printf(s, "%-11u", ctx->inline_en); + seq_printf(s, "%-7u", ctx->shift); + seq_printf(s, "%-14u", ctx->cqe_coalesce_cnt); + seq_printf(s, "%-6u", ctx->ceqn); + seq_printf(s, "%-14u", ctx->record_db_en); + seq_printf(s, "%-18u\n", ctx->cqe_coalesce_period); +} + +static void unic_get_jfs_ctx_sw(struct unic_channels *channels, + struct seq_file *s, u32 index) +{ + struct unic_channel *channel = &channels->c[index]; + + unic_dump_jfs_ctx_info_sw(channel->sq, s, index); +} + +static void unic_get_jfr_ctx_sw(struct unic_channels *channels, + struct seq_file *s, u32 index) +{ + struct unic_channel *channel = &channels->c[index]; + + unic_dump_jfr_ctx_info_sw(channel->rq, s, index); +} + +static void unic_get_sq_jfc_ctx_sw(struct unic_channels *channels, + struct seq_file *s, u32 index) +{ + struct unic_channel *channel = &channels->c[index]; + + unic_dump_jfc_ctx_info_sw(channel->sq->cq, s, index); +} + +static void unic_get_rq_jfc_ctx_sw(struct unic_channels *channels, + struct seq_file *s, u32 index) +{ + struct unic_channel *channel = &channels->c[index]; + + unic_dump_jfc_ctx_info_sw(channel->rq->cq, s, index); +} + +enum unic_dbg_ctx_type { + UNIC_DBG_JFS_CTX = 0, + UNIC_DBG_JFR_CTX, + UNIC_DBG_SQ_JFC_CTX, + UNIC_DBG_RQ_JFC_CTX, +}; + +static int unic_dbg_dump_ctx_sw(struct seq_file *s, void *data, + enum unic_dbg_ctx_type ctx_type) +{ + struct unic_dbg_context { + void (*print_ctx_titles)(struct seq_file *s); + void (*get_ctx)(struct unic_channels *channels, struct seq_file *s, u32 index); + } dbg_ctx[] = { + {unic_jfs_ctx_titles_print, unic_get_jfs_ctx_sw}, + {unic_jfr_ctx_titles_print, unic_get_jfr_ctx_sw}, + {unic_jfc_ctx_titles_print, unic_get_sq_jfc_ctx_sw}, + {unic_jfc_ctx_titles_print, unic_get_rq_jfc_ctx_sw}, + }; + struct unic_dev *unic_dev = dev_get_drvdata(s->private); + int ret = 0; + u32 i; + + dbg_ctx[ctx_type].print_ctx_titles(s); + + if (!mutex_trylock(&unic_dev->channels.mutex)) + return -EBUSY; + + if (__unic_resetting(unic_dev) || !unic_dev->channels.c) { + ret = -EBUSY; + goto out; + } + + for (i = 0; i < unic_dev->channels.num; i++) + dbg_ctx[ctx_type].get_ctx(&unic_dev->channels, s, i); + +out: + mutex_unlock(&unic_dev->channels.mutex); + + return ret; +} + +int unic_dbg_dump_jfs_ctx_sw(struct seq_file *s, void *data) +{ + return unic_dbg_dump_ctx_sw(s, data, UNIC_DBG_JFS_CTX); +} + +int unic_dbg_dump_jfr_ctx_sw(struct seq_file *s, void *data) +{ + return unic_dbg_dump_ctx_sw(s, data, UNIC_DBG_JFR_CTX); +} + +int unic_dbg_dump_rq_jfc_ctx_sw(struct seq_file *s, void *data) +{ + return unic_dbg_dump_ctx_sw(s, data, UNIC_DBG_RQ_JFC_CTX); +} + +int unic_dbg_dump_sq_jfc_ctx_sw(struct seq_file *s, void *data) +{ + return unic_dbg_dump_ctx_sw(s, data, UNIC_DBG_SQ_JFC_CTX); +} + +struct unic_ctx_info { + u32 start_idx; + u32 ctx_size; + u8 op; + const char *ctx_name; +}; + +static int unic_get_ctx_info(struct unic_dev *unic_dev, + enum unic_dbg_ctx_type ctx_type, + struct unic_ctx_info *ctx_info) +{ + struct ubase_adev_caps *unic_caps = ubase_get_unic_caps(unic_dev->comdev.adev); + + if (!unic_caps) { + unic_err(unic_dev, "failed to get unic caps.\n"); + return -ENODATA; + } + + switch (ctx_type) { + case UNIC_DBG_JFS_CTX: + ctx_info->start_idx = unic_caps->jfs.start_idx; + ctx_info->ctx_size = UBASE_JFS_CTX_SIZE; + ctx_info->op = UBASE_MB_QUERY_JFS_CONTEXT; + ctx_info->ctx_name = "jfs"; + break; + case UNIC_DBG_JFR_CTX: + ctx_info->start_idx = unic_caps->jfr.start_idx; + ctx_info->ctx_size = UBASE_JFR_CTX_SIZE; + ctx_info->op = UBASE_MB_QUERY_JFR_CONTEXT; + ctx_info->ctx_name = "jfr"; + break; + case UNIC_DBG_SQ_JFC_CTX: + ctx_info->start_idx = unic_caps->jfc.start_idx; + ctx_info->ctx_size = UBASE_JFC_CTX_SIZE; + ctx_info->op = UBASE_MB_QUERY_JFC_CONTEXT; + ctx_info->ctx_name = "sq_jfc"; + break; + case UNIC_DBG_RQ_JFC_CTX: + ctx_info->start_idx = unic_caps->jfc.start_idx + + unic_dev->channels.num; + ctx_info->ctx_size = UBASE_JFC_CTX_SIZE; + ctx_info->op = UBASE_MB_QUERY_JFC_CONTEXT; + ctx_info->ctx_name = "rq_jfc"; + break; + default: + unic_err(unic_dev, "failed to get ctx info, ctx_type = %u.\n", + ctx_type); + return -ENODATA; + } + + return 0; +} + +static void unic_mask_jfs_ctx_key_words(void *buf) +{ + struct unic_jfs_ctx *jfs = (struct unic_jfs_ctx *)buf; + + jfs->sqe_token_id_l = 0; + jfs->sqe_token_id_h = 0; + jfs->sqe_base_addr_l = 0; + jfs->sqe_base_addr_h = 0; + jfs->sqe_pld_tokenid = 0; + jfs->rmt_tokenid = 0; + jfs->user_data_l = 0; + jfs->user_data_h = 0; +} + +static void unic_mask_jfr_ctx_key_words(void *buf) +{ + struct unic_jfr_ctx *jfr = (struct unic_jfr_ctx *)buf; + + jfr->rqe_token_id_l = 0; + jfr->rqe_token_id_h = 0; + jfr->rqe_base_addr_l = 0; + jfr->rqe_base_addr_h = 0; + jfr->pld_token_id = 0; + jfr->token_value = 0; + jfr->user_data_l = 0; + jfr->user_data_h = 0; + jfr->idx_que_addr_l = 0; + jfr->idx_que_addr_h = 0; + jfr->record_db_addr_l = 0; + jfr->record_db_addr_m = 0; + jfr->record_db_addr_h = 0; +} + +static void unic_mask_jfc_ctx_key_words(void *buf) +{ + struct unic_jfc_ctx *jfc = (struct unic_jfc_ctx *)buf; + + jfc->cqe_base_addr_l = 0; + jfc->cqe_base_addr_h = 0; + jfc->queue_token_id = 0; + jfc->record_db_addr_l = 0; + jfc->record_db_addr_h = 0; + jfc->rmt_token_id = 0; + jfc->remote_token_value = 0; +} + +static void unic_mask_ctx_key_words(void *buf, + enum unic_dbg_ctx_type ctx_type) +{ + switch (ctx_type) { + case UNIC_DBG_JFS_CTX: + unic_mask_jfs_ctx_key_words(buf); + break; + case UNIC_DBG_JFR_CTX: + unic_mask_jfr_ctx_key_words(buf); + break; + case UNIC_DBG_SQ_JFC_CTX: + case UNIC_DBG_RQ_JFC_CTX: + unic_mask_jfc_ctx_key_words(buf); + break; + default: + break; + } +} + +static int unic_dbg_dump_context_hw(struct seq_file *s, void *data, + enum unic_dbg_ctx_type ctx_type) +{ + struct unic_dev *unic_dev = dev_get_drvdata(s->private); + struct auxiliary_device *adev = unic_dev->comdev.adev; + struct unic_ctx_info ctx_info = {0}; + struct ubase_cmd_mailbox *mailbox; + struct ubase_mbx_attr attr = {0}; + int ret = 0; + u32 i; + + if (!mutex_trylock(&unic_dev->channels.mutex)) + return -EBUSY; + + if (__unic_resetting(unic_dev) || + !unic_dev->channels.c) { + ret = -EBUSY; + goto channel_ready_err; + } + + mailbox = ubase_alloc_cmd_mailbox(adev); + if (IS_ERR_OR_NULL(mailbox)) { + unic_err(unic_dev, "failed to alloc mailbox for dump context.\n"); + ret = -ENOMEM; + goto channel_ready_err; + } + + ret = unic_get_ctx_info(unic_dev, ctx_type, &ctx_info); + if (ret) + goto upgrade_ctx_err; + + for (i = 0; i < unic_dev->channels.num; i++) { + ubase_fill_mbx_attr(&attr, i + ctx_info.start_idx, ctx_info.op, + 0); + ret = ubase_hw_upgrade_ctx_ex(adev, &attr, mailbox); + if (ret) { + unic_err(unic_dev, + "failed to post query %s ctx mbx, ret = %d.\n", + ctx_info.ctx_name, ret); + goto upgrade_ctx_err; + } + + seq_printf(s, "offset\t%s", ctx_info.ctx_name); + seq_printf(s, "%u\n", i); + unic_mask_ctx_key_words(mailbox->buf, ctx_type); + ubase_print_context_hw(s, mailbox->buf, ctx_info.ctx_size); + seq_puts(s, "\n"); + } + +upgrade_ctx_err: + ubase_free_cmd_mailbox(adev, mailbox); +channel_ready_err: + mutex_unlock(&unic_dev->channels.mutex); + + return ret; +} + +int unic_dbg_dump_jfs_context_hw(struct seq_file *s, void *data) +{ + return unic_dbg_dump_context_hw(s, data, UNIC_DBG_JFS_CTX); +} + +int unic_dbg_dump_jfr_context_hw(struct seq_file *s, void *data) +{ + return unic_dbg_dump_context_hw(s, data, UNIC_DBG_JFR_CTX); +} + +int unic_dbg_dump_sq_jfc_context_hw(struct seq_file *s, void *data) +{ + return unic_dbg_dump_context_hw(s, data, UNIC_DBG_SQ_JFC_CTX); +} + +int unic_dbg_dump_rq_jfc_context_hw(struct seq_file *s, void *data) +{ + return unic_dbg_dump_context_hw(s, data, UNIC_DBG_RQ_JFC_CTX); +} diff --git a/drivers/net/ub/unic/debugfs/unic_ctx_debugfs.h b/drivers/net/ub/unic/debugfs/unic_ctx_debugfs.h new file mode 100644 index 000000000000..cb6b08c80d8e --- /dev/null +++ b/drivers/net/ub/unic/debugfs/unic_ctx_debugfs.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. + * + */ + +#ifndef __UNIC_CTX_DEBUGFS_H__ +#define __UNIC_CTX_DEBUGFS_H__ + +int unic_dbg_dump_jfs_ctx_sw(struct seq_file *s, void *data); +int unic_dbg_dump_jfr_ctx_sw(struct seq_file *s, void *data); +int unic_dbg_dump_sq_jfc_ctx_sw(struct seq_file *s, void *data); +int unic_dbg_dump_rq_jfc_ctx_sw(struct seq_file *s, void *data); +int unic_dbg_dump_jfs_context_hw(struct seq_file *s, void *data); +int unic_dbg_dump_jfr_context_hw(struct seq_file *s, void *data); +int unic_dbg_dump_sq_jfc_context_hw(struct seq_file *s, void *data); +int unic_dbg_dump_rq_jfc_context_hw(struct seq_file *s, void *data); + +#endif diff --git a/drivers/net/ub/unic/debugfs/unic_debugfs.c b/drivers/net/ub/unic/debugfs/unic_debugfs.c index 112e64c25a34..29fc8917eaa2 100644 --- a/drivers/net/ub/unic/debugfs/unic_debugfs.c +++ b/drivers/net/ub/unic/debugfs/unic_debugfs.c @@ -11,6 +11,7 @@ #include #include "unic_dev.h" +#include "unic_ctx_debugfs.h" #include "unic_hw.h" #include "unic_debugfs.h" @@ -198,6 +199,11 @@ static bool unic_dbg_dentry_support(struct device *dev, u32 property) } static struct ubase_dbg_dentry_info unic_dbg_dentry[] = { + { + .name = "context", + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + }, /* keep unic at the bottom and add new directory above */ { .name = "unic", @@ -208,6 +214,34 @@ static struct ubase_dbg_dentry_info unic_dbg_dentry[] = { static struct ubase_dbg_cmd_info unic_dbg_cmd[] = { { + .name = "jfs_context", + .dentry_index = UNIC_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_jfs_ctx_sw, + }, { + .name = "jfr_context", + .dentry_index = UNIC_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_jfr_ctx_sw, + }, { + .name = "sq_jfc_context", + .dentry_index = UNIC_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_sq_jfc_ctx_sw, + }, { + .name = "rq_jfc_context", + .dentry_index = UNIC_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_rq_jfc_ctx_sw, + }, { .name = "dev_info", .dentry_index = UNIC_DBG_DENTRY_ROOT, .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, @@ -228,6 +262,34 @@ static struct ubase_dbg_cmd_info unic_dbg_cmd[] = { .support = unic_dbg_dentry_support, .init = ubase_dbg_seq_file_init, .read_func = unic_dbg_dump_page_pool_info, + }, { + .name = "jfs_context_hw", + .dentry_index = UNIC_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_jfs_context_hw, + }, { + .name = "jfr_context_hw", + .dentry_index = UNIC_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_jfr_context_hw, + }, { + .name = "sq_jfc_context_hw", + .dentry_index = UNIC_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_sq_jfc_context_hw, + }, { + .name = "rq_jfc_context_hw", + .dentry_index = UNIC_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_rq_jfc_context_hw, }, { .name = "rss_cfg_hw", .dentry_index = UNIC_DBG_DENTRY_ROOT, diff --git a/drivers/net/ub/unic/debugfs/unic_debugfs.h b/drivers/net/ub/unic/debugfs/unic_debugfs.h index 6efd739d2c5b..1afba40382d6 100644 --- a/drivers/net/ub/unic/debugfs/unic_debugfs.h +++ b/drivers/net/ub/unic/debugfs/unic_debugfs.h @@ -13,6 +13,7 @@ #define unic_get_ubase_root_dentry(adev) ubase_diag_debugfs_root(adev) enum unic_dbg_dentry_type { + UNIC_DBG_DENTRY_CONTEXT, /* must be the last entry. */ UNIC_DBG_DENTRY_ROOT }; -- Gitee From 6c5be793f8518df620f5fc23267555fbfbe241ca Mon Sep 17 00:00:00 2001 From: Haibin Lu Date: Thu, 21 Aug 2025 21:50:58 +0800 Subject: [PATCH 054/103] net: unic: support querying and configuring coalesce parameters. commit e0ccc63cc72ec634fffe4107cd60e620c462ad0e openEuler Coalesce parameters determine the interrupt reporting frequency, which can be adjusted in different scenarios to achieve service objectives. To adapt to the ub protocol, This patch adds the capability of querying and configuring coalesce parameters for UNIC driver. Users can use the ethtool to query or configure coalesce parameters. Signed-off-by: Fengyan Mu Signed-off-by: Haibin Lu Signed-off-by: Xiongchuan Zhou --- drivers/net/ub/unic/unic_dev.c | 24 ++++ drivers/net/ub/unic/unic_dev.h | 1 + drivers/net/ub/unic/unic_ethtool.c | 171 +++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) diff --git a/drivers/net/ub/unic/unic_dev.c b/drivers/net/ub/unic/unic_dev.c index a0ea8edee2ef..f039151844c2 100644 --- a/drivers/net/ub/unic/unic_dev.c +++ b/drivers/net/ub/unic/unic_dev.c @@ -293,6 +293,30 @@ static void unic_uninit_channels_attr(struct unic_dev *unic_dev) mutex_destroy(&channels->mutex); } +u16 unic_cqe_period_round_down(u16 cqe_period) +{ + u16 period[] = { + UNIC_CQE_PERIOD_0, + UNIC_CQE_PERIOD_4, + UNIC_CQE_PERIOD_16, + UNIC_CQE_PERIOD_64, + UNIC_CQE_PERIOD_256, + UNIC_CQE_PERIOD_1024, + UNIC_CQE_PERIOD_4096, + UNIC_CQE_PERIOD_16384, + UNIC_CQE_PERIOD_ERR + }; + u16 i; + + for (i = 0; i < ARRAY_SIZE(period) - 1; i++) { + if (cqe_period >= period[i] && + cqe_period < period[i + 1]) + return period[i]; + } + + return UNIC_CQE_PERIOD_ERR; +} + int unic_init_tx(struct unic_dev *unic_dev, u32 num) { struct unic_channel *c; diff --git a/drivers/net/ub/unic/unic_dev.h b/drivers/net/ub/unic/unic_dev.h index 8654aa9a819e..f014164c8e31 100644 --- a/drivers/net/ub/unic/unic_dev.h +++ b/drivers/net/ub/unic/unic_dev.h @@ -247,6 +247,7 @@ void unic_start_period_task(struct net_device *netdev); void unic_remove_period_task(struct unic_dev *unic_dev); int unic_init_wq(void); void unic_destroy_wq(void); +u16 unic_cqe_period_round_down(u16 cqe_period); int unic_init_rx(struct unic_dev *unic_dev, u32 num); int unic_init_tx(struct unic_dev *unic_dev, u32 num); void unic_destroy_rx(struct unic_dev *unic_dev, u32 num); diff --git a/drivers/net/ub/unic/unic_ethtool.c b/drivers/net/ub/unic/unic_ethtool.c index 474626833d89..eb90121ad6fb 100644 --- a/drivers/net/ub/unic/unic_ethtool.c +++ b/drivers/net/ub/unic/unic_ethtool.c @@ -109,6 +109,175 @@ static int unic_set_fecparam(struct net_device *ndev, return 0; } +static int unic_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *cmd, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + struct unic_coalesce *tx_coal = &unic_dev->channels.unic_coal.tx_coal; + struct unic_coalesce *rx_coal = &unic_dev->channels.unic_coal.rx_coal; + + if (unic_resetting(netdev)) + return -EBUSY; + + cmd->tx_coalesce_usecs = tx_coal->int_gl; + cmd->rx_coalesce_usecs = rx_coal->int_gl; + + cmd->tx_max_coalesced_frames = tx_coal->int_ql; + cmd->rx_max_coalesced_frames = rx_coal->int_ql; + + return 0; +} + +static int unic_check_gl_coalesce_para(struct net_device *netdev, + struct ethtool_coalesce *cmd) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + u32 rx_gl, tx_gl; + + if (cmd->rx_coalesce_usecs > unic_dev->caps.max_int_gl) { + unic_err(unic_dev, + "invalid rx-usecs value, rx-usecs range is [0, %u].\n", + unic_dev->caps.max_int_gl); + return -EINVAL; + } + + if (cmd->tx_coalesce_usecs > unic_dev->caps.max_int_gl) { + unic_err(unic_dev, + "invalid tx-usecs value, tx-usecs range is [0, %u].\n", + unic_dev->caps.max_int_gl); + return -EINVAL; + } + + rx_gl = unic_cqe_period_round_down(cmd->rx_coalesce_usecs); + if (rx_gl != cmd->rx_coalesce_usecs) { + unic_err(unic_dev, + "invalid rx_usecs(%u), because it must be power of 4.\n", + cmd->rx_coalesce_usecs); + return -EINVAL; + } + + tx_gl = unic_cqe_period_round_down(cmd->tx_coalesce_usecs); + if (tx_gl != cmd->tx_coalesce_usecs) { + unic_err(unic_dev, + "invalid tx_usecs(%u), because it must be power of 4.\n", + cmd->tx_coalesce_usecs); + return -EINVAL; + } + + return 0; +} + +static int unic_check_ql_coalesce_para(struct net_device *netdev, + struct ethtool_coalesce *cmd) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + + if ((cmd->tx_max_coalesced_frames || cmd->rx_max_coalesced_frames) && + !unic_dev->caps.max_int_ql) { + unic_err(unic_dev, "coalesced frames is not supported.\n"); + return -EOPNOTSUPP; + } + + if (cmd->tx_max_coalesced_frames > unic_dev->caps.max_int_ql || + cmd->rx_max_coalesced_frames > unic_dev->caps.max_int_ql) { + unic_err(unic_dev, + "invalid coalesced frames value, range is [0, %u].\n", + unic_dev->caps.max_int_ql); + return -ERANGE; + } + + return 0; +} + +static int +unic_check_coalesce_para(struct net_device *netdev, + struct ethtool_coalesce *cmd, + struct kernel_ethtool_coalesce *kernel_coal) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + int ret; + + if (cmd->use_adaptive_rx_coalesce || cmd->use_adaptive_tx_coalesce) { + unic_err(unic_dev, + "not support to enable adaptive coalesce.\n"); + return -EINVAL; + } + + ret = unic_check_gl_coalesce_para(netdev, cmd); + if (ret) { + unic_err(unic_dev, + "failed to check gl coalesce param, ret = %d.\n", ret); + return ret; + } + + ret = unic_check_ql_coalesce_para(netdev, cmd); + if (ret) + unic_err(unic_dev, + "failed to check ql coalesce param, ret = %d.\n", ret); + + return ret; +} + +static int unic_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *cmd, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + struct unic_coal_txrx *unic_coal = &unic_dev->channels.unic_coal; + struct unic_coalesce *tx_coal = &unic_coal->tx_coal; + struct unic_coalesce *rx_coal = &unic_coal->rx_coal; + struct unic_coalesce old_tx_coal, old_rx_coal; + int ret, ret1; + + if (test_bit(UNIC_STATE_DEACTIVATE, &unic_dev->state)) { + unic_err(unic_dev, + "failed to set coalesce, due to dev deacitve.\n"); + return -EBUSY; + } + + if (unic_resetting(netdev)) + return -EBUSY; + + ret = unic_check_coalesce_para(netdev, cmd, kernel_coal); + if (ret) + return ret; + + memcpy(&old_tx_coal, tx_coal, sizeof(struct unic_coalesce)); + memcpy(&old_rx_coal, rx_coal, sizeof(struct unic_coalesce)); + + tx_coal->int_gl = cmd->tx_coalesce_usecs; + rx_coal->int_gl = cmd->rx_coalesce_usecs; + + tx_coal->int_ql = cmd->tx_max_coalesced_frames; + rx_coal->int_ql = cmd->rx_max_coalesced_frames; + + unic_net_stop_no_link_change(netdev); + unic_uninit_channels(unic_dev); + + ret = unic_init_channels(unic_dev, unic_dev->channels.num); + if (ret) { + netdev_err(netdev, "failed to init channels, ret = %d.\n", ret); + memcpy(tx_coal, &old_tx_coal, sizeof(struct unic_coalesce)); + memcpy(rx_coal, &old_rx_coal, sizeof(struct unic_coalesce)); + ret1 = unic_init_channels(unic_dev, unic_dev->channels.num); + if (ret1) { + unic_err(unic_dev, + "failed to recover old channels, ret = %d.\n", + ret1); + return ret; + } + } + + ret1 = unic_net_open_no_link_change(netdev); + if (ret1) + unic_err(unic_dev, "failed to set net open, ret = %d.\n", ret1); + + return ret; +} + #define UNIC_ETHTOOL_RING (ETHTOOL_RING_USE_RX_BUF_LEN | \ ETHTOOL_RING_USE_TX_PUSH) #define UNIC_ETHTOOL_COALESCE (ETHTOOL_COALESCE_USECS | \ @@ -131,6 +300,8 @@ static const struct ethtool_ops unic_ethtool_ops = { .get_fecparam = unic_get_fecparam, .set_fecparam = unic_set_fecparam, .get_fec_stats = unic_get_fec_stats, + .get_coalesce = unic_get_coalesce, + .set_coalesce = unic_set_coalesce, }; void unic_set_ethtool_ops(struct net_device *netdev) -- Gitee From f8939c55495d8dcbbfc76cc9ef62661bf18b1921 Mon Sep 17 00:00:00 2001 From: Xiongchuan Zhou Date: Sun, 24 Aug 2025 10:16:25 +0800 Subject: [PATCH 055/103] net: unic: Support to query and clear historical NIC link status information commit 4420dfeed31d751757b64677336fe906295a7d51 openEuler In debugfs, Added query interface to get the historical NIC link information, Includes the accumulated link up/down times and the latest ten NIC link status changes. Provided interface to clear these information stored in the memory when specified file is read (no parameter is required). Signed-off-by: Xiongchuan Zhou --- drivers/net/ub/unic/debugfs/unic_debugfs.c | 71 ++++++++++++++++++++++ drivers/net/ub/unic/unic_dev.c | 16 ++++- drivers/net/ub/unic/unic_dev.h | 12 ++++ drivers/net/ub/unic/unic_netdev.c | 23 +++++++ 4 files changed, 120 insertions(+), 2 deletions(-) diff --git a/drivers/net/ub/unic/debugfs/unic_debugfs.c b/drivers/net/ub/unic/debugfs/unic_debugfs.c index 29fc8917eaa2..e61e782b044d 100644 --- a/drivers/net/ub/unic/debugfs/unic_debugfs.c +++ b/drivers/net/ub/unic/debugfs/unic_debugfs.c @@ -191,6 +191,63 @@ static int unic_dbg_dump_promisc_cfg_hw(struct seq_file *s, void *data) return 0; } +static int unic_dbg_query_link_record(struct seq_file *s, void *data) +{ + struct unic_dev *unic_dev = dev_get_drvdata(s->private); + struct unic_link_stats *record = &unic_dev->stats.link_record; + u8 cnt = 1, stats_cnt; + u64 total, idx; + + mutex_lock(&record->lock); + + seq_puts(s, "current time : "); + ubase_dbg_format_time(ktime_get_real_seconds(), s); + seq_printf(s, "\nlink up count : %llu\n", record->link_up_cnt); + seq_printf(s, "link down count : %llu\n", record->link_down_cnt); + + total = record->link_up_cnt + record->link_down_cnt; + if (!total) { + seq_puts(s, "link change records : NA\n"); + mutex_unlock(&record->lock); + + return 0; + } + + seq_puts(s, "link change records :\n"); + seq_puts(s, "\tNo.\tTIME\t\t\t\tSTATUS\n"); + + stats_cnt = min(total, LINK_STAT_MAX_IDX); + while (cnt <= stats_cnt) { + total--; + idx = total % LINK_STAT_MAX_IDX; + seq_printf(s, "\t%-2d\t", cnt); + ubase_dbg_format_time(ktime_get_real_seconds(), s); + seq_printf(s, "\t%s\n", + record->stats[idx].link_status ? "LINK UP" : "LINK DOWN"); + cnt++; + } + + mutex_unlock(&record->lock); + + return 0; +} + +static int unic_dbg_clear_link_record(struct seq_file *s, void *data) +{ + struct unic_dev *unic_dev = dev_get_drvdata(s->private); + struct unic_link_stats *record = &unic_dev->stats.link_record; + + mutex_lock(&record->lock); + record->link_up_cnt = 0; + record->link_down_cnt = 0; + memset(record->stats, 0, sizeof(record->stats)); + mutex_unlock(&record->lock); + + seq_puts(s, "Link status records have been cleared!\n"); + + return 0; +} + static bool unic_dbg_dentry_support(struct device *dev, u32 property) { struct unic_dev *unic_dev = dev_get_drvdata(dev); @@ -304,6 +361,20 @@ static struct ubase_dbg_cmd_info unic_dbg_cmd[] = { .support = unic_dbg_dentry_support, .init = ubase_dbg_seq_file_init, .read_func = unic_dbg_dump_promisc_cfg_hw, + }, { + .name = "link_status_record", + .dentry_index = UNIC_DBG_DENTRY_ROOT, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_query_link_record, + }, { + .name = "clear_link_status_record", + .dentry_index = UNIC_DBG_DENTRY_ROOT, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_clear_link_record, } }; diff --git a/drivers/net/ub/unic/unic_dev.c b/drivers/net/ub/unic/unic_dev.c index f039151844c2..7ed3525837e9 100644 --- a/drivers/net/ub/unic/unic_dev.c +++ b/drivers/net/ub/unic/unic_dev.c @@ -574,6 +574,7 @@ static int unic_dev_init_mtu(struct unic_dev *unic_dev) static int unic_init_mac(struct unic_dev *unic_dev) { + struct unic_link_stats *record = &unic_dev->stats.link_record; struct unic_mac *mac = &unic_dev->hw.mac; int ret; @@ -601,9 +602,17 @@ static int unic_init_mac(struct unic_dev *unic_dev) return ret; } + mutex_init(&record->lock); return 0; } +static void unic_uninit_mac(struct unic_dev *unic_dev) +{ + struct unic_link_stats *record = &unic_dev->stats.link_record; + + mutex_destroy(&record->lock); +} + int unic_set_mtu(struct unic_dev *unic_dev, int new_mtu) { u16 max_frame_size; @@ -822,11 +831,11 @@ static int unic_init_netdev_priv(struct net_device *netdev, ret = unic_init_dev_addr(priv); if (ret) - goto err_uninit_vport; + goto unic_unint_mac; ret = unic_init_channels_attr(priv); if (ret) - goto err_uninit_vport; + goto unic_unint_mac; ret = unic_init_channels(priv, priv->channels.num); if (ret) { @@ -840,6 +849,8 @@ static int unic_init_netdev_priv(struct net_device *netdev, err_uninit_channels_attr: unic_uninit_channels_attr(priv); +unic_unint_mac: + unic_uninit_mac(priv); err_uninit_vport: unic_uninit_vport(priv); destroy_lock: @@ -854,6 +865,7 @@ static void unic_uninit_netdev_priv(struct net_device *netdev) unic_uninit_channels(priv); unic_uninit_channels_attr(priv); + unic_uninit_mac(priv); unic_uninit_vport(priv); mutex_destroy(&priv->act_info.mutex); } diff --git a/drivers/net/ub/unic/unic_dev.h b/drivers/net/ub/unic/unic_dev.h index f014164c8e31..af20b72168ee 100644 --- a/drivers/net/ub/unic/unic_dev.h +++ b/drivers/net/ub/unic/unic_dev.h @@ -182,8 +182,20 @@ struct unic_fec_stats { struct unic_fec_stats_item lane[UNIC_FEC_STATS_MAX_LANE]; }; +#define LINK_STAT_MAX_IDX 10U +struct unic_link_stats { + u64 link_up_cnt; + u64 link_down_cnt; + struct { + bool link_status; + time64_t link_tv_sec; + } stats[LINK_STAT_MAX_IDX]; + struct mutex lock; /* protects link record */ +}; + struct unic_stats { struct unic_fec_stats fec_stats; + struct unic_link_stats link_record; }; struct unic_addr_tbl { diff --git a/drivers/net/ub/unic/unic_netdev.c b/drivers/net/ub/unic/unic_netdev.c index d8680ff9f894..d2d213c90d0b 100644 --- a/drivers/net/ub/unic/unic_netdev.c +++ b/drivers/net/ub/unic/unic_netdev.c @@ -164,6 +164,27 @@ static int unic_net_up(struct net_device *netdev) return 0; } +static void unic_link_status_record(struct net_device *netdev, bool linkup) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + struct unic_link_stats *record = &unic_dev->stats.link_record; + u64 idx, total; + + mutex_lock(&record->lock); + + if (linkup) + record->link_up_cnt++; + else + record->link_down_cnt++; + + total = record->link_up_cnt + record->link_down_cnt; + idx = (total - 1) % LINK_STAT_MAX_IDX; + record->stats[idx].link_tv_sec = ktime_get_real_seconds(); + record->stats[idx].link_status = linkup; + + mutex_unlock(&record->lock); +} + static void unic_clear_fec_stats(struct unic_dev *unic_dev) { struct unic_fec_stats *fec_stats = &unic_dev->stats.fec_stats; @@ -194,6 +215,8 @@ void unic_link_status_change(struct net_device *netdev, bool linkup) out: if (netif_msg_link(unic_dev)) unic_info(unic_dev, "%s.\n", linkup ? "link up" : "link down"); + + unic_link_status_record(netdev, linkup); } void unic_link_status_update(struct unic_dev *unic_dev) -- Gitee From 7e8fb9a0d9bb951d7a137df21e8c7fcdb8c9e461 Mon Sep 17 00:00:00 2001 From: Haibin Lu Date: Tue, 16 Sep 2025 10:22:41 +0800 Subject: [PATCH 056/103] net: unic: Drive supports ub entity reset. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b395a4f7347c243a1ed6fdd02d8aa87a94af3c58 openEuler In this patch, add a unified interface to tigger ELR reset by ubus, adapt ehtool\tx_timeout\ubus to use this reset interface, now we can use "ethtool --reset ublx dedicated"、"echo 1 > /sys/class/net /ublx/device/reset" to trigger ELR reset. Signed-off-by: Yixi Shen Signed-off-by: Xiongchuan Zhou Signed-off-by: Haibin Lu --- drivers/net/ub/unic/Makefile | 2 +- drivers/net/ub/unic/unic_ethtool.c | 37 ++++++++ drivers/net/ub/unic/unic_event.c | 25 ++++++ drivers/net/ub/unic/unic_reset.c | 130 +++++++++++++++++++++++++++++ drivers/net/ub/unic/unic_reset.h | 14 ++++ 5 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ub/unic/unic_reset.c create mode 100644 drivers/net/ub/unic/unic_reset.h diff --git a/drivers/net/ub/unic/Makefile b/drivers/net/ub/unic/Makefile index 67ecd0ad8c11..7098242033eb 100644 --- a/drivers/net/ub/unic/Makefile +++ b/drivers/net/ub/unic/Makefile @@ -9,5 +9,5 @@ ccflags-y += -I$(srctree)/drivers/net/ub/unic/debugfs obj-$(CONFIG_UB_UNIC) += unic.o unic-objs = unic_main.o unic_ethtool.o unic_hw.o unic_guid.o unic_netdev.o unic_dev.o unic_qos_hw.o unic_event.o unic_crq.o unic-objs += unic_channel.o debugfs/unic_debugfs.o unic_rx.o unic_tx.o unic_txrx.o unic_comm_addr.o unic_rack_ip.o unic_stats.o -unic-objs += debugfs/unic_ctx_debugfs.o +unic-objs += debugfs/unic_ctx_debugfs.o unic_reset.o unic-$(CONFIG_UB_UNIC_DCB) += unic_dcbnl.o diff --git a/drivers/net/ub/unic/unic_ethtool.c b/drivers/net/ub/unic/unic_ethtool.c index eb90121ad6fb..c9593ba74fe4 100644 --- a/drivers/net/ub/unic/unic_ethtool.c +++ b/drivers/net/ub/unic/unic_ethtool.c @@ -278,6 +278,42 @@ static int unic_set_coalesce(struct net_device *netdev, return ret; } +static const struct unic_reset_type_map unic_ethtool_reset_map[] = { + {ETH_RESET_DEDICATED, UBASE_UE_RESET}, +}; + +static int unic_reset(struct net_device *ndev, u32 *flags) +{ + enum ubase_reset_type reset_type = UBASE_NO_RESET; + struct unic_dev *unic_dev = netdev_priv(ndev); + enum ethtool_reset_flags reset_flags; + u32 i; + + if (unic_resetting(ndev)) { + unic_err(unic_dev, "failed to reset, due to dev resetting.\n"); + return -EBUSY; + } + + for (i = 0; i < ARRAY_SIZE(unic_ethtool_reset_map); i++) { + if (unic_ethtool_reset_map[i].reset_flags == *flags) { + reset_type = unic_ethtool_reset_map[i].reset_type; + reset_flags = unic_ethtool_reset_map[i].reset_flags; + break; + } + } + + if (reset_type == UBASE_NO_RESET) + return -EOPNOTSUPP; + + unic_info(unic_dev, + "ethtool setting reset type, type = %u.\n", reset_type); + + ubase_reset_event(unic_dev->comdev.adev, reset_type); + *flags &= ~reset_flags; + + return 0; +} + #define UNIC_ETHTOOL_RING (ETHTOOL_RING_USE_RX_BUF_LEN | \ ETHTOOL_RING_USE_TX_PUSH) #define UNIC_ETHTOOL_COALESCE (ETHTOOL_COALESCE_USECS | \ @@ -302,6 +338,7 @@ static const struct ethtool_ops unic_ethtool_ops = { .get_fec_stats = unic_get_fec_stats, .get_coalesce = unic_get_coalesce, .set_coalesce = unic_set_coalesce, + .reset = unic_reset, }; void unic_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ub/unic/unic_event.c b/drivers/net/ub/unic/unic_event.c index bcd1e210f447..2f24cd423e2b 100644 --- a/drivers/net/ub/unic/unic_event.c +++ b/drivers/net/ub/unic/unic_event.c @@ -23,6 +23,7 @@ #include "unic_netdev.h" #include "unic_qos_hw.h" #include "unic_rack_ip.h" +#include "unic_reset.h" #include "unic_event.h" int unic_comp_handler(struct notifier_block *nb, unsigned long jfcn, void *data) @@ -52,6 +53,25 @@ int unic_comp_handler(struct notifier_block *nb, unsigned long jfcn, void *data) return 0; } +static void unic_rack_port_reset(struct unic_dev *unic_dev, bool link_up) +{ + if (link_up) + unic_dev->hw.mac.link_status = UNIC_LINK_STATUS_UP; + else + unic_dev->hw.mac.link_status = UNIC_LINK_STATUS_DOWN; +} + +static void unic_port_handler(struct auxiliary_device *adev, bool link_up) +{ + struct unic_dev *unic_dev = dev_get_drvdata(&adev->dev); + struct net_device *netdev = unic_dev->comdev.netdev; + + if (!netif_running(netdev)) + return; + + unic_rack_port_reset(unic_dev, link_up); +} + static struct ubase_ctrlq_event_nb unic_ctrlq_events[] = { { .service_type = UBASE_CTRLQ_SER_TYPE_IP_ACL, @@ -140,6 +160,9 @@ int unic_register_event(struct auxiliary_device *adev) if (ret) goto unregister_crq; + ubase_port_register(adev, unic_port_handler); + ubase_reset_register(adev, unic_reset_handler); + return 0; unregister_crq: @@ -149,6 +172,8 @@ int unic_register_event(struct auxiliary_device *adev) void unic_unregister_event(struct auxiliary_device *adev) { + ubase_reset_unregister(adev); + ubase_port_unregister(adev); unic_unregister_ctrlq_event(adev, ARRAY_SIZE(unic_ctrlq_events)); unic_unregister_crq_event(adev, ARRAY_SIZE(unic_crq_events)); } diff --git a/drivers/net/ub/unic/unic_reset.c b/drivers/net/ub/unic/unic_reset.c new file mode 100644 index 000000000000..ff1239cc5131 --- /dev/null +++ b/drivers/net/ub/unic/unic_reset.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. + * + */ + +#include + +#include "unic_cmd.h" +#include "unic_dev.h" +#include "unic_hw.h" +#include "unic_netdev.h" +#include "unic_rack_ip.h" +#include "unic_reset.h" + +static void unic_dev_suspend(struct unic_dev *unic_dev) +{ + unic_uninit_channels(unic_dev); +} + +static void unic_reset_down(struct auxiliary_device *adev) +{ + struct unic_dev *priv = (struct unic_dev *)dev_get_drvdata(&adev->dev); + struct net_device *netdev = priv->comdev.netdev; + bool if_running; + int ret; + + if (!test_bit(UNIC_STATE_INITED, &priv->state) || + test_and_set_bit(UNIC_STATE_DISABLED, &priv->state)) { + unic_warn(priv, "failed to reset unic, device is not ready.\n"); + return; + } + + set_bit(UNIC_STATE_RESETTING, &priv->state); + if_running = netif_running(netdev); + + unic_info(priv, "unic reset start.\n"); + + unic_remove_period_task(priv); + + /* due to lack of cmdq when resetting, need to close promisc first, + * to prevent that concurrent deactivate event ubable to close promisc + * when resetting + */ + ret = unic_activate_promisc_mode(priv, false); + if (ret) + unic_warn(priv, "failed to close promisc, ret = %d.\n", ret); + else + set_bit(UNIC_VPORT_STATE_PROMISC_CHANGE, &priv->vport.state); + + rtnl_lock(); + ret = if_running ? unic_net_stop(netdev) : 0; + rtnl_unlock(); + if (ret) + unic_err(priv, "failed to stop unic net, ret = %d.\n", ret); +} + +static void unic_reset_uninit(struct auxiliary_device *adev) +{ + struct unic_dev *priv = (struct unic_dev *)dev_get_drvdata(&adev->dev); + + if (!test_bit(UNIC_STATE_RESETTING, &priv->state)) + return; + + unic_dev_suspend(priv); +} + +static int unic_dev_resume(struct unic_dev *unic_dev) +{ + int ret; + + ret = unic_init_channels(unic_dev, unic_dev->channels.num); + if (ret) + unic_err(unic_dev, "failed to init channels, ret = %d.\n", ret); + + return ret; +} + +static void unic_reset_init(struct auxiliary_device *adev) +{ + struct unic_dev *priv = (struct unic_dev *)dev_get_drvdata(&adev->dev); + struct net_device *netdev = priv->comdev.netdev; + bool if_running; + int ret; + + if (!test_bit(UNIC_STATE_RESETTING, &priv->state)) + return; + + ret = unic_dev_resume(priv); + if (ret) + goto err_unic_resume; + + unic_query_rack_ip(adev); + unic_start_period_task(netdev); + + if_running = netif_running(netdev); + clear_bit(UNIC_STATE_RESETTING, &priv->state); + clear_bit(UNIC_STATE_DISABLED, &priv->state); + rtnl_lock(); + ret = if_running ? unic_net_open(netdev) : 0; + rtnl_unlock(); + if (ret) + unic_err(priv, "failed to up net, ret = %d.\n", ret); + + unic_info(priv, "unic reset done.\n"); + + return; + +err_unic_resume: + clear_bit(UNIC_STATE_RESETTING, &priv->state); + clear_bit(UNIC_STATE_DISABLED, &priv->state); +} + +void unic_reset_handler(struct auxiliary_device *adev, + enum ubase_reset_stage stage) +{ + switch (stage) { + case UBASE_RESET_STAGE_DOWN: + unic_reset_down(adev); + break; + case UBASE_RESET_STAGE_UNINIT: + unic_reset_uninit(adev); + break; + case UBASE_RESET_STAGE_INIT: + unic_reset_init(adev); + break; + default: + break; + } +} diff --git a/drivers/net/ub/unic/unic_reset.h b/drivers/net/ub/unic/unic_reset.h new file mode 100644 index 000000000000..4ce313ac58aa --- /dev/null +++ b/drivers/net/ub/unic/unic_reset.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. + * + */ + +#ifndef __UNIC_RESET_H__ +#define __UNIC_RESET_H__ + +#include + +void unic_reset_handler(struct auxiliary_device *adev, enum ubase_reset_stage stage); + +#endif -- Gitee From 99f7cd515eaaec70f364c8e91351952acb2c9d4b Mon Sep 17 00:00:00 2001 From: Haibin Lu Date: Sat, 30 Aug 2025 10:03:33 +0800 Subject: [PATCH 057/103] net: unic: Support RAS commit 339b55a00771bd1379427c7afcf0b417c0e5b781 openEuler RAS is an important feature of the system. UB also supports RAS function. UB protocol defines multiple types of ras, and different types of ras are processed in different ways to ensure system stability. This patch provides the support of the UNIC driver for ras. As an auxiliary device of the UBSAE driver, the UNIC driver registers the corresponding RAS processing function with the UBASE. After receiving the corresponding RAS, UBASE routes the RAS to UNIC for processing. Signed-off-by: Yaoyao Tu Signed-off-by: Haibin Lu Signed-off-by: Xiongchuan Zhou --- drivers/net/ub/unic/unic_event.c | 73 +++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/drivers/net/ub/unic/unic_event.c b/drivers/net/ub/unic/unic_event.c index 2f24cd423e2b..faa91a99badc 100644 --- a/drivers/net/ub/unic/unic_event.c +++ b/drivers/net/ub/unic/unic_event.c @@ -148,14 +148,81 @@ static int unic_register_crq_event(struct auxiliary_device *adev) return 0; } +static void unic_unregister_ae_event(struct auxiliary_device *adev, + u8 asyn_event_num) +{ + struct unic_dev *unic_dev = dev_get_drvdata(&adev->dev); + u8 i; + + for (i = 0; i < asyn_event_num; i++) + ubase_event_unregister(adev, &unic_dev->ae_nbs[i]); +} + +static int unic_ae_jetty_level_error(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct ubase_event_nb *ev_nb = container_of(nb, + struct ubase_event_nb, nb); + struct auxiliary_device *adev = (struct auxiliary_device *)ev_nb->back; + struct unic_dev *unic_dev = dev_get_drvdata(&adev->dev); + struct ubase_aeq_notify_info *info = data; + u32 queue_num; + + /* Normally, UNIC does not report such abnormal events, + * but in order to maintain its scalability, + * unic reserves the reset processing of such events. + */ + queue_num = info->aeqe->event.queue_event.num; + unic_err(unic_dev, + "recv jetty level error, event_type = 0x%x, sub_type = 0x%x, queue_num = %u.\n", + info->event_type, info->sub_type, queue_num); + + ubase_reset_event(adev, UBASE_UE_RESET); + + return 0; +} + +static int unic_register_ae_event(struct auxiliary_device *adev) +{ + struct ubase_event_nb unic_ae_nbs[UNIC_AE_LEVEL_NUM] = { + { + UBASE_DRV_UNIC, + UBASE_EVENT_TYPE_JETTY_LEVEL_ERROR, + { unic_ae_jetty_level_error }, + adev + }, + }; + struct unic_dev *unic_dev = dev_get_drvdata(&adev->dev); + int ret; + u8 i; + + for (i = 0; i < ARRAY_SIZE(unic_ae_nbs); i++) { + unic_dev->ae_nbs[i] = unic_ae_nbs[i]; + ret = ubase_event_register(adev, &unic_dev->ae_nbs[i]); + if (ret) { + dev_err(adev->dev.parent, + "failed to register asyn event[%u], ret = %d.\n", + unic_dev->ae_nbs[i].event_type, ret); + unic_unregister_ae_event(adev, i); + return ret; + } + } + + return ret; +} + int unic_register_event(struct auxiliary_device *adev) { int ret; - ret = unic_register_crq_event(adev); + ret = unic_register_ae_event(adev); if (ret) return ret; + ret = unic_register_crq_event(adev); + if (ret) + goto unregister_ae; + ret = unic_register_ctrlq_event(adev); if (ret) goto unregister_crq; @@ -167,6 +234,9 @@ int unic_register_event(struct auxiliary_device *adev) unregister_crq: unic_unregister_crq_event(adev, ARRAY_SIZE(unic_crq_events)); +unregister_ae: + unic_unregister_ae_event(adev, UNIC_AE_LEVEL_NUM); + return ret; } @@ -176,4 +246,5 @@ void unic_unregister_event(struct auxiliary_device *adev) ubase_port_unregister(adev); unic_unregister_ctrlq_event(adev, ARRAY_SIZE(unic_ctrlq_events)); unic_unregister_crq_event(adev, ARRAY_SIZE(unic_crq_events)); + unic_unregister_ae_event(adev, UNIC_AE_LEVEL_NUM); } -- Gitee From 32d20be61e78c27815ae3702ee477c94978d6c1d Mon Sep 17 00:00:00 2001 From: Haibin Lu Date: Tue, 16 Sep 2025 11:06:51 +0800 Subject: [PATCH 058/103] net: unic: support config/query the mapping between dscp and tc commit c20baa942215749ed839e4fc02b3d197e3e3d142 openEuler This patch introduces support for configuring and querying the mapping between DSCP (Differentiated Services Code Point) and TC (Traffic Class) in the UNIC driver. The new functionality allows users to set and retrieve the DSCP-to-TC mappings, enhancing the driver's ability to manage network traffic prioritization. Signed-off-by: Haiqing Fang Signed-off-by: Xiaobo Zhang Signed-off-by: Haibin Lu Signed-off-by: Xiongchuan Zhou --- drivers/net/ub/unic/unic_dcbnl.c | 138 +++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/drivers/net/ub/unic/unic_dcbnl.c b/drivers/net/ub/unic/unic_dcbnl.c index 3110277da020..9e44d74f3b38 100644 --- a/drivers/net/ub/unic/unic_dcbnl.c +++ b/drivers/net/ub/unic/unic_dcbnl.c @@ -10,7 +10,145 @@ #include "unic_netdev.h" #include "unic_dcbnl.h" +static int unic_dscp_prio_check(struct net_device *netdev, struct dcb_app *app) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + + if (!unic_dev_ets_supported(unic_dev)) + return -EOPNOTSUPP; + + if (netif_running(netdev)) { + unic_err(unic_dev, + "failed to set dscp-prio, due to network interface is up, pls down it first and try again.\n"); + return -EBUSY; + } + + if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP || + app->protocol >= UBASE_MAX_DSCP || + app->priority >= UNIC_MAX_PRIO_NUM) + return -EINVAL; + + if (unic_resetting(netdev)) + return -EBUSY; + + return 0; +} + +static int unic_set_app(struct net_device *netdev, struct dcb_app *app, + struct unic_dev *unic_dev, struct unic_vl *vl) +{ + struct dcb_app old_app; + int ret; + + unic_info(unic_dev, "setapp dscp = %u, priority = %u.\n", + app->protocol, app->priority); + + ret = dcb_ieee_setapp(netdev, app); + if (ret) { + unic_err(unic_dev, "failed to add app, ret = %d.\n", ret); + return ret; + } + + old_app.selector = IEEE_8021QAZ_APP_SEL_DSCP; + old_app.protocol = app->protocol; + old_app.priority = vl->dscp_prio[app->protocol]; + + vl->dscp_prio[app->protocol] = app->priority; + ret = unic_set_vl_map(unic_dev, vl->dscp_prio, vl->prio_vl, + UNIC_DSCP_VL_MAP); + if (ret) { + vl->dscp_prio[app->protocol] = old_app.priority; + dcb_ieee_delapp(netdev, app); + return ret; + } + + if (old_app.priority == UNIC_INVALID_PRIORITY) { + vl->dscp_app_cnt++; + } else { + ret = dcb_ieee_delapp(netdev, &old_app); + if (ret) + unic_err(unic_dev, + "failed to delete old app, ret = %d.\n", ret); + } + + return ret; +} + +static int unic_dcbnl_ieee_setapp(struct net_device *netdev, + struct dcb_app *app) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + struct unic_vl *vl = &unic_dev->channels.vl; + int ret; + + ret = unic_dscp_prio_check(netdev, app); + if (ret) { + unic_err(unic_dev, "failed to set dscp-prio, ret = %d\n", ret); + return ret; + } + + /* dscp-prio already set */ + if (vl->dscp_prio[app->protocol] == app->priority) + return 0; + + return unic_set_app(netdev, app, unic_dev, vl); +} + +static int unic_del_app(struct net_device *netdev, struct dcb_app *app, + struct unic_dev *unic_dev, struct unic_vl *vl) +{ + u8 map_type = UNIC_DSCP_VL_MAP; + int ret; + + unic_info(unic_dev, "delapp dscp = %u, priority = %u\n", + app->protocol, app->priority); + + ret = dcb_ieee_delapp(netdev, app); + if (ret) + return ret; + + if (vl->dscp_app_cnt <= 1) + map_type = UNIC_PRIO_VL_MAP; + + vl->dscp_prio[app->protocol] = UNIC_INVALID_PRIORITY; + ret = unic_set_vl_map(unic_dev, vl->dscp_prio, vl->prio_vl, + map_type); + if (ret) { + vl->dscp_prio[app->protocol] = app->priority; + dcb_ieee_setapp(netdev, app); + return ret; + } + + if (vl->dscp_app_cnt) + vl->dscp_app_cnt--; + + return 0; +} + +static int unic_dcbnl_ieee_delapp(struct net_device *netdev, + struct dcb_app *app) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + struct unic_vl *vl = &unic_dev->channels.vl; + int ret; + + ret = unic_dscp_prio_check(netdev, app); + if (ret) { + unic_err(unic_dev, "failed to del dscp-prio, ret = %d.\n", ret); + return ret; + } + + if (app->priority != vl->dscp_prio[app->protocol]) { + unic_err(unic_dev, "failed to del no match dscp-prio.\n"); + return -EINVAL; + } + + return unic_del_app(netdev, app, unic_dev, vl); +} + static const struct dcbnl_rtnl_ops unic_dcbnl_ops = { + .ieee_setapp = unic_dcbnl_ieee_setapp, + .ieee_delapp = unic_dcbnl_ieee_delapp, }; void unic_set_dcbnl_ops(struct net_device *netdev) -- Gitee From 477c6541c6b940007a7baaa452e1af6a7e730c54 Mon Sep 17 00:00:00 2001 From: Haibin Lu Date: Tue, 23 Sep 2025 17:25:20 +0800 Subject: [PATCH 059/103] net: unic: Add debugfs support for QoS configuration and query. commit 3a3016996e8e5ffff95b290866fc0899409a4e2d openEuler This patch introduces debugfs support for configuring and querying QoS (Quality of Service) mappings in the UNIC driver. The new functionality allows users to inspect and manage DSCP (Differentiated Services Code Point) to TC (Traffic Class) mappings, as well as VLAN queue configurations. Signed-off-by: Haiqing Fang Signed-off-by: Xiaobo Zhang Signed-off-by: Haibin Lu Signed-off-by: Xiongchuan Zhou --- drivers/net/ub/unic/Makefile | 2 +- drivers/net/ub/unic/debugfs/unic_debugfs.c | 35 ++++- drivers/net/ub/unic/debugfs/unic_debugfs.h | 1 + .../net/ub/unic/debugfs/unic_qos_debugfs.c | 148 ++++++++++++++++++ .../net/ub/unic/debugfs/unic_qos_debugfs.h | 15 ++ drivers/net/ub/unic/unic_hw.h | 1 + drivers/net/ub/unic/unic_qos_hw.c | 18 +++ drivers/net/ub/unic/unic_qos_hw.h | 2 + 8 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ub/unic/debugfs/unic_qos_debugfs.c create mode 100644 drivers/net/ub/unic/debugfs/unic_qos_debugfs.h diff --git a/drivers/net/ub/unic/Makefile b/drivers/net/ub/unic/Makefile index 7098242033eb..fa5de4255e68 100644 --- a/drivers/net/ub/unic/Makefile +++ b/drivers/net/ub/unic/Makefile @@ -9,5 +9,5 @@ ccflags-y += -I$(srctree)/drivers/net/ub/unic/debugfs obj-$(CONFIG_UB_UNIC) += unic.o unic-objs = unic_main.o unic_ethtool.o unic_hw.o unic_guid.o unic_netdev.o unic_dev.o unic_qos_hw.o unic_event.o unic_crq.o unic-objs += unic_channel.o debugfs/unic_debugfs.o unic_rx.o unic_tx.o unic_txrx.o unic_comm_addr.o unic_rack_ip.o unic_stats.o -unic-objs += debugfs/unic_ctx_debugfs.o unic_reset.o +unic-objs += debugfs/unic_ctx_debugfs.o unic_reset.o debugfs/unic_qos_debugfs.o unic-$(CONFIG_UB_UNIC_DCB) += unic_dcbnl.o diff --git a/drivers/net/ub/unic/debugfs/unic_debugfs.c b/drivers/net/ub/unic/debugfs/unic_debugfs.c index e61e782b044d..f9cc6e887ce0 100644 --- a/drivers/net/ub/unic/debugfs/unic_debugfs.c +++ b/drivers/net/ub/unic/debugfs/unic_debugfs.c @@ -10,9 +10,10 @@ #include #include -#include "unic_dev.h" #include "unic_ctx_debugfs.h" +#include "unic_dev.h" #include "unic_hw.h" +#include "unic_qos_debugfs.h" #include "unic_debugfs.h" static int unic_dbg_dump_dev_info(struct seq_file *s, void *data) @@ -260,6 +261,10 @@ static struct ubase_dbg_dentry_info unic_dbg_dentry[] = { .name = "context", .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, .support = unic_dbg_dentry_support, + }, { + .name = "qos", + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, }, /* keep unic at the bottom and add new directory above */ { @@ -347,6 +352,13 @@ static struct ubase_dbg_cmd_info unic_dbg_cmd[] = { .support = unic_dbg_dentry_support, .init = ubase_dbg_seq_file_init, .read_func = unic_dbg_dump_rq_jfc_context_hw, + }, { + .name = "vl_queue", + .dentry_index = UNIC_DBG_DENTRY_QOS, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_vl_queue, }, { .name = "rss_cfg_hw", .dentry_index = UNIC_DBG_DENTRY_ROOT, @@ -361,6 +373,27 @@ static struct ubase_dbg_cmd_info unic_dbg_cmd[] = { .support = unic_dbg_dentry_support, .init = ubase_dbg_seq_file_init, .read_func = unic_dbg_dump_promisc_cfg_hw, + }, { + .name = "dscp_vl_map", + .dentry_index = UNIC_DBG_DENTRY_QOS, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_dscp_vl_map, + }, { + .name = "prio_vl_map", + .dentry_index = UNIC_DBG_DENTRY_QOS, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_prio_vl_map, + }, { + .name = "dscp_prio", + .dentry_index = UNIC_DBG_DENTRY_QOS, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_dscp_prio, }, { .name = "link_status_record", .dentry_index = UNIC_DBG_DENTRY_ROOT, diff --git a/drivers/net/ub/unic/debugfs/unic_debugfs.h b/drivers/net/ub/unic/debugfs/unic_debugfs.h index 1afba40382d6..065630fbd35e 100644 --- a/drivers/net/ub/unic/debugfs/unic_debugfs.h +++ b/drivers/net/ub/unic/debugfs/unic_debugfs.h @@ -14,6 +14,7 @@ enum unic_dbg_dentry_type { UNIC_DBG_DENTRY_CONTEXT, + UNIC_DBG_DENTRY_QOS, /* must be the last entry. */ UNIC_DBG_DENTRY_ROOT }; diff --git a/drivers/net/ub/unic/debugfs/unic_qos_debugfs.c b/drivers/net/ub/unic/debugfs/unic_qos_debugfs.c new file mode 100644 index 000000000000..85b3288f0bec --- /dev/null +++ b/drivers/net/ub/unic/debugfs/unic_qos_debugfs.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. + * + */ + +#include "unic_dcbnl.h" +#include "unic_debugfs.h" +#include "unic_hw.h" +#include "unic_qos_debugfs.h" + +int unic_dbg_dump_vl_queue(struct seq_file *s, void *data) +{ + struct unic_dev *unic_dev = dev_get_drvdata(s->private); + struct unic_vl *vl = &unic_dev->channels.vl; + u8 i; + + seq_puts(s, "VL_ID Q_OFFSET Q_COUNT\n"); + + for (i = 0; i < unic_dev->channels.rss_vl_num; i++) { + seq_printf(s, "%-7d", i); + seq_printf(s, "%-12u", vl->queue_offset[i]); + seq_printf(s, "%-11u\n", vl->queue_count[i]); + } + + return 0; +} + +static void unic_dump_dscp_vl_map(struct unic_dev *unic_dev, + struct seq_file *s, u8 dscp, u8 hw_vl) +{ + struct auxiliary_device *adev = unic_dev->comdev.adev; + struct ubase_adev_qos *qos = ubase_get_adev_qos(adev); + struct unic_vl *vl = &unic_dev->channels.vl; + u8 prio, sw_vl = 0; + + prio = vl->dscp_prio[dscp]; + if (prio == UNIC_INVALID_PRIORITY || + vl->prio_vl[prio] >= unic_dev->channels.rss_vl_num) + sw_vl = qos->nic_vl[0]; + else + sw_vl = qos->nic_vl[vl->prio_vl[prio]]; + + seq_printf(s, "%-6u", dscp); + seq_printf(s, "%-7u", sw_vl); + + if (!unic_dev_ubl_supported(unic_dev) && + unic_dev_ets_supported(unic_dev)) + seq_printf(s, "%-7u", hw_vl); + else + seq_puts(s, "--"); + + seq_puts(s, "\n"); +} + +int unic_dbg_dump_dscp_vl_map(struct seq_file *s, void *data) +{ + struct unic_dev *unic_dev = dev_get_drvdata(s->private); + struct unic_config_vl_map_cmd resp = {0}; + int ret; + u8 i; + + if (__unic_resetting(unic_dev)) + return -EBUSY; + + if (!unic_dev_ubl_supported(unic_dev) && + unic_dev_ets_supported(unic_dev)) { + ret = unic_query_vl_map(unic_dev, &resp); + if (ret) + return ret; + } + + seq_puts(s, "DSCP SW_VL HW_VL\n"); + + for (i = 0; i < UBASE_MAX_DSCP; i++) + unic_dump_dscp_vl_map(unic_dev, s, i, resp.dscp_vl[i]); + + return 0; +} + +static void unic_dump_prio_vl_map(struct unic_dev *unic_dev, + struct seq_file *s, u8 prio, u8 hw_vl) +{ + struct auxiliary_device *adev = unic_dev->comdev.adev; + struct ubase_adev_qos *qos = ubase_get_adev_qos(adev); + struct unic_vl *vl = &unic_dev->channels.vl; + u8 sw_vl = 0; + + if (vl->prio_vl[prio] >= unic_dev->channels.rss_vl_num) + sw_vl = qos->nic_vl[0]; + else + sw_vl = qos->nic_vl[vl->prio_vl[prio]]; + + seq_printf(s, "%-6u", prio); + seq_printf(s, "%-7u", sw_vl); + + if (!unic_dev_ubl_supported(unic_dev) && + unic_dev_ets_supported(unic_dev)) + seq_printf(s, "%-7u", hw_vl); + else + seq_puts(s, "--"); + + seq_puts(s, "\n"); +} + +int unic_dbg_dump_prio_vl_map(struct seq_file *s, void *data) +{ + struct unic_dev *unic_dev = dev_get_drvdata(s->private); + struct unic_config_vl_map_cmd resp = {0}; + int ret; + u8 i; + + if (__unic_resetting(unic_dev)) + return -EBUSY; + + if (!unic_dev_ubl_supported(unic_dev) && + unic_dev_ets_supported(unic_dev)) { + ret = unic_query_vl_map(unic_dev, &resp); + if (ret) + return ret; + } + + seq_puts(s, "PRIO SW_VL HW_VL\n"); + + for (i = 0; i < UNIC_MAX_PRIO_NUM; i++) + unic_dump_prio_vl_map(unic_dev, s, i, resp.prio_vl[i]); + + return 0; +} + +int unic_dbg_dump_dscp_prio(struct seq_file *s, void *data) +{ + struct unic_dev *unic_dev = dev_get_drvdata(s->private); + struct unic_vl *vl = &unic_dev->channels.vl; + u16 i; + + if (__unic_resetting(unic_dev)) + return -EBUSY; + + seq_puts(s, "DSCP PRIO\n"); + + for (i = 0; i < UBASE_MAX_DSCP; i++) { + seq_printf(s, "%-6u", i); + seq_printf(s, "%-7u\n", vl->dscp_prio[i]); + } + + return 0; +} diff --git a/drivers/net/ub/unic/debugfs/unic_qos_debugfs.h b/drivers/net/ub/unic/debugfs/unic_qos_debugfs.h new file mode 100644 index 000000000000..f55616ab1617 --- /dev/null +++ b/drivers/net/ub/unic/debugfs/unic_qos_debugfs.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. + * + */ + +#ifndef __UNIC_QOS_DEBUGFS_H__ +#define __UNIC_QOS_DEBUGFS_H__ + +int unic_dbg_dump_vl_queue(struct seq_file *s, void *data); +int unic_dbg_dump_dscp_vl_map(struct seq_file *s, void *data); +int unic_dbg_dump_prio_vl_map(struct seq_file *s, void *data); +int unic_dbg_dump_dscp_prio(struct seq_file *s, void *data); + +#endif diff --git a/drivers/net/ub/unic/unic_hw.h b/drivers/net/ub/unic/unic_hw.h index ebe0c714549d..cfd46b6eadf4 100644 --- a/drivers/net/ub/unic/unic_hw.h +++ b/drivers/net/ub/unic/unic_hw.h @@ -11,6 +11,7 @@ #include #include "unic_dev.h" +#include "unic_qos_hw.h" #define UNIC_DL_CONFIG_MODE_TX_EN_B 0 #define UNIC_DL_CONFIG_MODE_RX_EN_B 1 diff --git a/drivers/net/ub/unic/unic_qos_hw.c b/drivers/net/ub/unic/unic_qos_hw.c index 2f463be3d324..79fb7271c08e 100644 --- a/drivers/net/ub/unic/unic_qos_hw.c +++ b/drivers/net/ub/unic/unic_qos_hw.c @@ -29,6 +29,24 @@ int unic_set_hw_vl_map(struct unic_dev *unic_dev, u8 *dscp_vl, u8 *prio_vl, return ret; } +int unic_query_vl_map(struct unic_dev *unic_dev, + struct unic_config_vl_map_cmd *resp) +{ + struct unic_config_vl_map_cmd req = {0}; + struct ubase_cmd_buf in, out; + int ret; + + ubase_fill_inout_buf(&in, UBASE_OPC_CFG_VL_MAP, true, sizeof(req), + &req); + ubase_fill_inout_buf(&out, UBASE_OPC_CFG_VL_MAP, false, sizeof(*resp), + resp); + ret = ubase_cmd_send_inout(unic_dev->comdev.adev, &in, &out); + if (ret) + unic_err(unic_dev, "failed to query vl map, ret = %d.\n", ret); + + return ret; +} + /* vl_maxrate: byte per second */ int unic_config_vl_rate_limit(struct unic_dev *unic_dev, u64 *vl_maxrate, u16 vl_bitmap) diff --git a/drivers/net/ub/unic/unic_qos_hw.h b/drivers/net/ub/unic/unic_qos_hw.h index 9f6947463349..82822cc871b6 100644 --- a/drivers/net/ub/unic/unic_qos_hw.h +++ b/drivers/net/ub/unic/unic_qos_hw.h @@ -13,6 +13,8 @@ int unic_set_hw_vl_map(struct unic_dev *unic_dev, u8 *dscp_vl, u8 *prio_vl, u8 map_type); +int unic_query_vl_map(struct unic_dev *unic_dev, + struct unic_config_vl_map_cmd *resp); int unic_config_vl_rate_limit(struct unic_dev *unic_dev, u64 *vl_maxrate, u16 vl_bitmap); -- Gitee From fde2f28a626f10224e4433aec8590230e00af4ab Mon Sep 17 00:00:00 2001 From: Haibin Lu Date: Tue, 16 Sep 2025 11:55:53 +0800 Subject: [PATCH 060/103] net: unic: support config/query ets parameters commit d6b4c7258c23f655f7d0509c1cd80361abfc245d openEuler This patch enhances the UNIC driver's support for DCB (Data Center Bridging) by adding functionality to configure and query ETS (Enhanced Transmission Selection) parameters, as well as manage VLAN queues. The changes include: 1. New DCBnl Commands: - `ieee_getets`: Retrieves current ETS configuration. - `ieee_setets`: Sets ETS parameters, including priority-to-TC mappings, TC bandwidth, and TSA (Traffic Shaping Algorithm). 2. ETS Configuration Management: - Adds validation for ETS parameters to ensure compatibility with hardware capabilities. - Implements logic to update VLAN mappings and traffic scheduling based on ETS settings. 3. VLAN Queue Adjustments: - Introduces functions to detect changes in VLAN queue numbers and adjust RSS (Receive Side Scaling) queue sizes accordingly, optimizing network performance. 4. Integration with Existing Framework: - Registers new DCBnl commands with the netlink interface for configuration and querying. - Updates internal structures and functions to support the new ETS and VLAN queue management features. This enhancement improves the UNIC driver's ability to manage network traffic prioritization and scheduling, providing greater flexibility and performance in data center environments. Signed-off-by: Haiqing Fang Signed-off-by: Xiaobo Zhang Signed-off-by: Haibin Lu Signed-off-by: Xiongchuan Zhou --- drivers/net/ub/unic/unic_dcbnl.c | 244 ++++++++++++++++++++++++++++++ drivers/net/ub/unic/unic_dev.c | 22 +++ drivers/net/ub/unic/unic_dev.h | 12 ++ include/ub/ubase/ubase_comm_dev.h | 2 + 4 files changed, 280 insertions(+) diff --git a/drivers/net/ub/unic/unic_dcbnl.c b/drivers/net/ub/unic/unic_dcbnl.c index 9e44d74f3b38..2b50901d8434 100644 --- a/drivers/net/ub/unic/unic_dcbnl.c +++ b/drivers/net/ub/unic/unic_dcbnl.c @@ -5,11 +5,253 @@ */ #include +#include #include "unic_hw.h" #include "unic_netdev.h" #include "unic_dcbnl.h" +#define UNIC_PRIO_VL_MAP_CHANGED BIT(0) +#define UNIC_TC_TSA_CHANGED BIT(1) +#define UNIC_TC_BW_CHANGED BIT(2) + +static int unic_ets_prio_tc_validate(struct unic_dev *unic_dev, + struct ieee_ets *ets, u8 *changed, + u8 *vl_num) +{ + struct auxiliary_device *adev = unic_dev->comdev.adev; + struct ubase_caps *caps = ubase_get_dev_caps(adev); + u32 max_queue = unic_channels_max_num(adev); + u8 i, max_vl = 0; + + for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { + if (ets->prio_tc[i] != unic_dev->channels.vl.prio_vl[i]) + *changed |= UNIC_PRIO_VL_MAP_CHANGED; + + max_vl = max(max_vl, ets->prio_tc[i] + 1); + } + + if (max_vl > caps->vl_num) { + unic_err(unic_dev, "tc num(%u) can't exceed max tc(%u).\n", + max_vl, caps->vl_num); + return -EINVAL; + } + + if (unic_get_rss_vl_num(unic_dev, max_vl) > max_queue) { + unic_err(unic_dev, + "tc num can't exceed queue num(%u).\n", max_queue); + return -EINVAL; + } + + *vl_num = max_vl; + + return 0; +} + +static int unic_ets_tc_bw_validate(struct unic_dev *unic_dev, + struct ieee_ets *ets, u8 *changed) +{ + struct auxiliary_device *adev = unic_dev->comdev.adev; + struct ubase_caps *caps = ubase_get_dev_caps(adev); + struct unic_vl *vl = &unic_dev->channels.vl; + /* continuous bitmap configured by the dcb tool */ + u16 tc_bitmap = (1 << caps->vl_num) - 1; + int ret; + u8 i; + + ret = ubase_check_qos_sch_param(adev, tc_bitmap, ets->tc_tx_bw, + ets->tc_tsa, false); + if (ret) + return ret; + + for (i = 0; i < caps->vl_num; i++) { + if (vl->vl_tsa[i] != ets->tc_tsa[i]) + *changed |= UNIC_TC_TSA_CHANGED; + + if (vl->vl_bw[i] != ets->tc_tx_bw[i]) + *changed |= UNIC_TC_BW_CHANGED; + } + + return 0; +} + +static int unic_setets_params_validate(struct unic_dev *unic_dev, + struct ieee_ets *ets, u8 *changed, + u8 *vl_num) +{ + int ret; + + ret = unic_ets_prio_tc_validate(unic_dev, ets, changed, vl_num); + if (ret) + return ret; + + return unic_ets_tc_bw_validate(unic_dev, ets, changed); +} + +static int unic_dcbnl_ieee_getets(struct net_device *ndev, struct ieee_ets *ets) +{ + struct unic_dev *unic_dev = netdev_priv(ndev); + struct auxiliary_device *adev = unic_dev->comdev.adev; + struct ubase_caps *caps = ubase_get_dev_caps(adev); + struct unic_vl *vl = &unic_dev->channels.vl; + + if (unic_resetting(ndev)) + return -EBUSY; + + if (!unic_dev_ets_supported(unic_dev)) + return -EOPNOTSUPP; + + memset(ets, 0, sizeof(*ets)); + ets->willing = 1; + ets->ets_cap = caps->vl_num; + + memcpy(ets->prio_tc, vl->prio_vl, sizeof(ets->prio_tc)); + memcpy(ets->tc_tx_bw, vl->vl_bw, sizeof(ets->tc_tx_bw)); + memcpy(ets->tc_tsa, vl->vl_tsa, sizeof(ets->tc_tsa)); + + return 0; +} + +static int unic_setets_preconditions(struct net_device *net_dev) +{ + struct unic_dev *unic_dev = netdev_priv(net_dev); + + if (!unic_dev_ets_supported(unic_dev)) + return -EOPNOTSUPP; + + if (netif_running(net_dev)) { + unic_err(unic_dev, + "failed to set ets, due to network interface is up, pls down it first and try again.\n"); + return -EBUSY; + } + + if (!(unic_dev->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) + return -EINVAL; + + if (unic_resetting(net_dev)) + return -EBUSY; + + return 0; +} + +static int unic_handle_prio_vl_change(struct unic_dev *unic_dev, + struct ieee_ets *ets, u8 changed) +{ + struct unic_vl *vl = &unic_dev->channels.vl; + u8 map_type; + int ret; + + if (!(changed & UNIC_PRIO_VL_MAP_CHANGED)) + return 0; + + map_type = vl->dscp_app_cnt ? UNIC_DSCP_VL_MAP : UNIC_PRIO_VL_MAP; + ret = unic_set_vl_map(unic_dev, vl->dscp_prio, ets->prio_tc, + map_type); + if (ret) + return ret; + + memcpy(vl->prio_vl, ets->prio_tc, sizeof(ets->prio_tc)); + + return 0; +} + +static inline void unic_convert_vl_sch_bw(struct ubase_caps *caps, u8 *vl_bw, + struct ieee_ets *ets) +{ + u8 i; + + for (i = 0; i < caps->vl_num; i++) { + vl_bw[caps->req_vl[i]] = ets->tc_tx_bw[i]; + vl_bw[caps->resp_vl[i]] = ets->tc_tx_bw[i]; + } +} + +static int unic_handle_tm_vl_sch_change(struct unic_dev *unic_dev, + struct ubase_caps *caps, + struct ieee_ets *ets) +{ + struct auxiliary_device *adev = unic_dev->comdev.adev; + struct unic_vl *vl = &unic_dev->channels.vl; + u8 vl_tsa[UBASE_MAX_VL_NUM] = {0}; + u8 vl_bw[UBASE_MAX_VL_NUM] = {0}; + u32 i; + + unic_convert_vl_sch_bw(caps, vl_bw, ets); + + for (i = 0; i < caps->vl_num; i++) { + if (ets->tc_tsa[i]) { + vl_tsa[caps->req_vl[i]] = ets->tc_tsa[i]; + vl_tsa[caps->resp_vl[i]] = ets->tc_tsa[i]; + } + } + + return ubase_config_tm_vl_sch(adev, vl->vl_bitmap, vl_bw, vl_tsa); +} + +static int unic_handle_vl_tsa_bw_change(struct unic_dev *unic_dev, + struct ieee_ets *ets, u8 changed) +{ + u8 *vl_tsa = unic_dev->channels.vl.vl_tsa; + u8 *vl_bw = unic_dev->channels.vl.vl_bw; + int ret; + + struct ubase_caps *caps = ubase_get_dev_caps(unic_dev->comdev.adev); + + if (!(changed & UNIC_TC_TSA_CHANGED || changed & UNIC_TC_BW_CHANGED)) + return 0; + + ret = unic_handle_tm_vl_sch_change(unic_dev, caps, ets); + if (ret) + return ret; + + memcpy(vl_tsa, ets->tc_tsa, sizeof(ets->tc_tsa)); + memcpy(vl_bw, ets->tc_tx_bw, sizeof(ets->tc_tx_bw)); + + return 0; +} + +static int unic_setets_config(struct net_device *ndev, struct ieee_ets *ets, + u8 changed, u8 vl_num) +{ + struct unic_dev *unic_dev = netdev_priv(ndev); + int ret; + + ret = unic_handle_prio_vl_change(unic_dev, ets, changed); + if (ret) + return ret; + + ret = unic_handle_vl_tsa_bw_change(unic_dev, ets, changed); + if (ret) + return ret; + + unic_dev->channels.vl.vl_num = vl_num; + if (unic_rss_vl_num_changed(unic_dev, vl_num)) + return unic_update_channels(unic_dev, vl_num); + + return 0; +} + +static int unic_dcbnl_ieee_setets(struct net_device *ndev, struct ieee_ets *ets) +{ + struct unic_dev *unic_dev = netdev_priv(ndev); + u8 changed = 0; + u8 vl_num = 0; + int ret; + + ret = unic_setets_preconditions(ndev); + if (ret) + return ret; + + ret = unic_setets_params_validate(unic_dev, ets, &changed, &vl_num); + if (ret) + return ret; + + if (!changed) + return 0; + + return unic_setets_config(ndev, ets, changed, vl_num); +} + static int unic_dscp_prio_check(struct net_device *netdev, struct dcb_app *app) { struct unic_dev *unic_dev = netdev_priv(netdev); @@ -147,6 +389,8 @@ static int unic_dcbnl_ieee_delapp(struct net_device *netdev, } static const struct dcbnl_rtnl_ops unic_dcbnl_ops = { + .ieee_getets = unic_dcbnl_ieee_getets, + .ieee_setets = unic_dcbnl_ieee_setets, .ieee_setapp = unic_dcbnl_ieee_setapp, .ieee_delapp = unic_dcbnl_ieee_delapp, }; diff --git a/drivers/net/ub/unic/unic_dev.c b/drivers/net/ub/unic/unic_dev.c index 7ed3525837e9..ef79194c24bb 100644 --- a/drivers/net/ub/unic/unic_dev.c +++ b/drivers/net/ub/unic/unic_dev.c @@ -905,6 +905,13 @@ void unic_remove_period_task(struct unic_dev *unic_dev) cancel_delayed_work_sync(&unic_dev->service_task); } +bool unic_rss_vl_num_changed(struct unic_dev *unic_dev, u8 vl_num) +{ + struct unic_channels *channels = &unic_dev->channels; + + return channels->rss_vl_num != unic_get_rss_vl_num(unic_dev, vl_num); +} + int unic_change_rss_size(struct unic_dev *unic_dev, u32 new_rss_size, u32 org_rss_size) { @@ -932,6 +939,21 @@ int unic_change_rss_size(struct unic_dev *unic_dev, u32 new_rss_size, return ret; } +int unic_update_channels(struct unic_dev *unic_dev, u8 vl_num) +{ + struct auxiliary_device *adev = unic_dev->comdev.adev; + struct unic_channels *channels = &unic_dev->channels; + u32 new_rss_size, old_rss_size = channels->rss_size; + + channels->rss_vl_num = unic_get_rss_vl_num(unic_dev, vl_num); + if (old_rss_size * channels->rss_vl_num > unic_channels_max_num(adev)) + new_rss_size = unic_get_max_rss_size(unic_dev); + else + new_rss_size = old_rss_size; + + return unic_change_rss_size(unic_dev, new_rss_size, old_rss_size); +} + static struct net_device *unic_alloc_netdev(struct auxiliary_device *adev) { struct ubase_caps *caps = ubase_get_dev_caps(adev); diff --git a/drivers/net/ub/unic/unic_dev.h b/drivers/net/ub/unic/unic_dev.h index af20b72168ee..a20744b810e8 100644 --- a/drivers/net/ub/unic/unic_dev.h +++ b/drivers/net/ub/unic/unic_dev.h @@ -257,6 +257,7 @@ int unic_init_channels(struct unic_dev *unic_dev, u32 channels_num); void unic_uninit_channels(struct unic_dev *unic_dev); void unic_start_period_task(struct net_device *netdev); void unic_remove_period_task(struct unic_dev *unic_dev); +void unic_update_queue_info(struct unic_dev *unic_dev); int unic_init_wq(void); void unic_destroy_wq(void); u16 unic_cqe_period_round_down(u16 cqe_period); @@ -264,8 +265,10 @@ int unic_init_rx(struct unic_dev *unic_dev, u32 num); int unic_init_tx(struct unic_dev *unic_dev, u32 num); void unic_destroy_rx(struct unic_dev *unic_dev, u32 num); void unic_destroy_tx(struct unic_dev *unic_dev, u32 num); +bool unic_rss_vl_num_changed(struct unic_dev *unic_dev, u8 vl_num); int unic_change_rss_size(struct unic_dev *unic_dev, u32 new_rss_size, u32 org_rss_size); +int unic_update_channels(struct unic_dev *unic_dev, u8 vl_num); int unic_set_vl_map(struct unic_dev *unic_dev, u8 *dscp_prio, u8 *prio_vl, u8 map_type); int unic_dbg_log(void); @@ -357,6 +360,15 @@ static inline u32 unic_read_reg(struct unic_dev *unic_dev, u32 reg) return readl(reg_addr + reg); } +static inline u8 unic_get_rss_vl_num(struct unic_dev *unic_dev, u8 max_vl) +{ + struct auxiliary_device *adev = unic_dev->comdev.adev; + struct ubase_adev_qos *qos = ubase_get_adev_qos(adev); + u8 vl_num = min(UNIC_RSS_MAX_VL_NUM, qos->nic_vl_num); + + return max_vl < vl_num ? max_vl : vl_num; +} + static inline u32 unic_get_sq_cqe_mask(struct unic_dev *unic_dev) { return unic_dev->channels.sq_cqe_depth - 1; diff --git a/include/ub/ubase/ubase_comm_dev.h b/include/ub/ubase/ubase_comm_dev.h index 81b2c98af17f..ac85c20311dd 100644 --- a/include/ub/ubase/ubase_comm_dev.h +++ b/include/ub/ubase/ubase_comm_dev.h @@ -24,6 +24,8 @@ struct iova_slot; #error "UBASE_MAX_VL_NUM can't less than IEEE_8021QAZ_MAX_TCS" #endif +#define UBASE_NIC_MAX_VL_NUM (2) + #define UBASE_SUP_UBL BIT(0) #define UBASE_SUP_ETH BIT(1) #define UBASE_SUP_UNIC BIT(2) -- Gitee From 62fd812338a2ecb84b7b3e70a12ea8044d6578d0 Mon Sep 17 00:00:00 2001 From: Xiaobo Zhang Date: Mon, 1 Sep 2025 13:39:35 +0800 Subject: [PATCH 061/103] net: unic: support config/query traffic class parameters commit daea31ba9a6cd73a57dff9769b34b4d3fd673017 openEuler This patch enhances the UNIC driver's DCB (Data Center Bridging) support by adding the following features: 1. DCBX Mode Configuration: - Introduces `unic_dcbnl_getdcbx` and `unic_dcbnl_setdcbx` functions to retrieve and set the DCBX mode, enabling compatibility with different DCBX versions and management modes. 2. Max Rate Management: - Adds `unic_ieee_getmaxrate` and `unic_ieee_setmaxrate` functions to query and configure the maximum transmission rates for each Traffic Class (TC), ensuring optimal network performance. - Includes `unic_check_maxrate` to validate rate settings, ensuring they fall within supported hardware limits. 3. Integration with DCBnl Interface: - Registers the new functions with the DCBnl netlink interface, allowing users to configure and query DCBX and max rate settings via standard network management tools. These enhancements improve the UNIC driver's ability to manage advanced QoS configurations, providing greater flexibility and control over network traffic prioritization and rate limiting. Signed-off-by: Haiqing Fang Signed-off-by: Xiaobo Zhang Signed-off-by: Xiongchuan Zhou --- drivers/net/ub/unic/unic_dcbnl.c | 93 ++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/drivers/net/ub/unic/unic_dcbnl.c b/drivers/net/ub/unic/unic_dcbnl.c index 2b50901d8434..5f14cebac540 100644 --- a/drivers/net/ub/unic/unic_dcbnl.c +++ b/drivers/net/ub/unic/unic_dcbnl.c @@ -388,11 +388,104 @@ static int unic_dcbnl_ieee_delapp(struct net_device *netdev, return unic_del_app(netdev, app, unic_dev, vl); } +static u8 unic_dcbnl_getdcbx(struct net_device *ndev) +{ + struct unic_dev *unic_dev = netdev_priv(ndev); + + return unic_dev->dcbx_cap; +} + +static u8 unic_dcbnl_setdcbx(struct net_device *ndev, u8 mode) +{ + struct unic_dev *unic_dev = netdev_priv(ndev); + + if ((mode & DCB_CAP_DCBX_LLD_MANAGED) || + (mode & DCB_CAP_DCBX_VER_CEE) || + !(mode & DCB_CAP_DCBX_HOST)) + return 1; + + unic_info(unic_dev, "set dcbx mode = %u\n.", mode); + + unic_dev->dcbx_cap = mode; + + return 0; +} + +static int unic_ieee_getmaxrate(struct net_device *ndev, + struct ieee_maxrate *maxrate) +{ + struct unic_dev *unic_dev = netdev_priv(ndev); + + if (!unic_dev_ets_supported(unic_dev) || + !unic_dev_tc_speed_limit_supported(unic_dev)) + return -EOPNOTSUPP; + + memcpy(maxrate->tc_maxrate, unic_dev->channels.vl.vl_maxrate, + sizeof(maxrate->tc_maxrate)); + return 0; +} + +static int unic_check_maxrate(struct unic_dev *unic_dev, + struct ieee_maxrate *maxrate) +{ + u32 max_speed = unic_dev->hw.mac.max_speed; + int i; + + for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { + if (!maxrate->tc_maxrate[i]) + continue; + + if (maxrate->tc_maxrate[i] / UNIC_MBYTE_PER_SEND > max_speed || + maxrate->tc_maxrate[i] < UNIC_MBYTE_PER_SEND) { + unic_err(unic_dev, + "invalid max_rate(%llubit), the range is [1Mbit, %uMbit].\n", + maxrate->tc_maxrate[i] * BITS_PER_BYTE, + max_speed); + return -EINVAL; + } + } + + return 0; +} + +static int unic_ieee_setmaxrate(struct net_device *ndev, + struct ieee_maxrate *maxrate) +{ + struct unic_dev *unic_dev = netdev_priv(ndev); + struct unic_vl *vl = &unic_dev->channels.vl; + int ret; + + if (!unic_dev_ets_supported(unic_dev) || + !unic_dev_tc_speed_limit_supported(unic_dev)) + return -EOPNOTSUPP; + + if (!(unic_dev->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) + return -EINVAL; + + ret = unic_check_maxrate(unic_dev, maxrate); + if (ret) + return ret; + + ret = unic_config_vl_rate_limit(unic_dev, maxrate->tc_maxrate, + vl->vl_bitmap); + if (ret) + return ret; + + memcpy(vl->vl_maxrate, maxrate->tc_maxrate, + sizeof(maxrate->tc_maxrate)); + + return 0; +} + static const struct dcbnl_rtnl_ops unic_dcbnl_ops = { .ieee_getets = unic_dcbnl_ieee_getets, .ieee_setets = unic_dcbnl_ieee_setets, + .ieee_getmaxrate = unic_ieee_getmaxrate, + .ieee_setmaxrate = unic_ieee_setmaxrate, .ieee_setapp = unic_dcbnl_ieee_setapp, .ieee_delapp = unic_dcbnl_ieee_delapp, + .getdcbx = unic_dcbnl_getdcbx, + .setdcbx = unic_dcbnl_setdcbx, }; void unic_set_dcbnl_ops(struct net_device *netdev) -- Gitee From d7ee0f48247bfb8a1feae4d80d9a5f4e69d0e7e2 Mon Sep 17 00:00:00 2001 From: Haibin Lu Date: Tue, 16 Sep 2025 16:30:21 +0800 Subject: [PATCH 062/103] net: unic: support subscribes to the RX stream stop and recovery interface. commit 58daddb6f308b8a305b2fe3b3d35065b150aac4e openEuler The ub system allows the aux driver to deliver the deactivate/activate dev command to ensure system robustness. The deactivate/activate command requires close cooperation between components. This patch allows the unic to complete its configuration when deactivate or deactivate. Signed-off-by: Zhenyu Wan Signed-off-by: Xiaobo Zhang Signed-off-by: Haibin Lu Signed-off-by: Xiongchuan Zhou --- drivers/net/ub/unic/unic_event.c | 101 +++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/drivers/net/ub/unic/unic_event.c b/drivers/net/ub/unic/unic_event.c index faa91a99badc..1785e0aad7f1 100644 --- a/drivers/net/ub/unic/unic_event.c +++ b/drivers/net/ub/unic/unic_event.c @@ -53,6 +53,105 @@ int unic_comp_handler(struct notifier_block *nb, unsigned long jfcn, void *data) return 0; } +static void unic_activate_event_process(struct unic_dev *unic_dev) +{ + struct unic_act_info *act_info = &unic_dev->act_info; + struct net_device *netdev = unic_dev->comdev.netdev; + int ret; + + if (test_bit(UNIC_STATE_DISABLED, &unic_dev->state)) { + unic_err(unic_dev, + "failed to process activate event, device is not ready.\n"); + return; + } + + rtnl_lock(); + + if (!test_bit(UNIC_STATE_DEACTIVATE, &unic_dev->state)) + goto unlock; + + /* if network interface has already been stopped, + * no need to open by activate event + */ + if (test_bit(UNIC_STATE_DOWN, &unic_dev->state)) + goto out; + + ret = unic_net_open_no_link_change(netdev); + if (ret) + unic_warn(unic_dev, "failed to open net, ret = %d.\n", ret); + + ret = unic_activate_promisc_mode(unic_dev, true); + if (ret) + unic_warn(unic_dev, "failed to open promisc, ret = %d.\n", ret); + else + clear_bit(UNIC_VPORT_STATE_PROMISC_CHANGE, &unic_dev->vport.state); + +out: + mutex_lock(&act_info->mutex); + act_info->deactivate = false; + mutex_unlock(&act_info->mutex); + clear_bit(UNIC_STATE_DEACTIVATE, &unic_dev->state); +unlock: + rtnl_unlock(); +} + +static void unic_deactivate_event_process(struct unic_dev *unic_dev) +{ + struct unic_act_info *act_info = &unic_dev->act_info; + struct net_device *netdev = unic_dev->comdev.netdev; + int ret; + + if (test_bit(UNIC_STATE_DISABLED, &unic_dev->state)) { + unic_err(unic_dev, + "failed to process deactivate event, device is not ready.\n"); + return; + } + + rtnl_lock(); + + if (test_bit(UNIC_STATE_DEACTIVATE, &unic_dev->state)) + goto unlock; + + /* when deactivate event occurs, set flag to true to prevent + * periodic tasks changing promisc + */ + mutex_lock(&act_info->mutex); + act_info->deactivate = true; + mutex_unlock(&act_info->mutex); + + ret = unic_activate_promisc_mode(unic_dev, false); + if (ret) + unic_warn(unic_dev, "failed to close promisc, ret = %d.\n", ret); + else + set_bit(UNIC_VPORT_STATE_PROMISC_CHANGE, &unic_dev->vport.state); + + /* if network interface has already been stopped, + * no need to stop again by deactivate event + */ + if (test_bit(UNIC_STATE_DOWN, &unic_dev->state)) + goto out; + + unic_net_stop_no_link_change(netdev); + +out: + set_bit(UNIC_STATE_DEACTIVATE, &unic_dev->state); +unlock: + rtnl_unlock(); +} + +static void unic_activate_handler(struct auxiliary_device *adev, bool activate) +{ + struct unic_dev *unic_dev = dev_get_drvdata(&adev->dev); + + unic_info(unic_dev, "receive %s event callback.\n", + activate ? "activate" : "deactivate"); + + if (activate) + unic_activate_event_process(unic_dev); + else + unic_deactivate_event_process(unic_dev); +} + static void unic_rack_port_reset(struct unic_dev *unic_dev, bool link_up) { if (link_up) @@ -229,6 +328,7 @@ int unic_register_event(struct auxiliary_device *adev) ubase_port_register(adev, unic_port_handler); ubase_reset_register(adev, unic_reset_handler); + ubase_activate_register(adev, unic_activate_handler); return 0; @@ -242,6 +342,7 @@ int unic_register_event(struct auxiliary_device *adev) void unic_unregister_event(struct auxiliary_device *adev) { + ubase_activate_unregister(adev); ubase_reset_unregister(adev); ubase_port_unregister(adev); unic_unregister_ctrlq_event(adev, ARRAY_SIZE(unic_ctrlq_events)); -- Gitee From d7c7bedd40c79775d273fc97d8f00a2ae31650ae Mon Sep 17 00:00:00 2001 From: Xiongchuan Zhou Date: Sat, 23 Aug 2025 15:53:06 +0800 Subject: [PATCH 063/103] net: unic: Debugfs supports querying IP specifications and IP entries. commit 48ffd57b4028d48472921c13d77630dc7f5b8777 openEuler This patch adds the ability to query IP table entries and their specifications. Users can use standard tools to query IP table entries and their specifications. Signed-off-by: Xiongchuan Zhou --- drivers/net/ub/unic/Makefile | 2 +- drivers/net/ub/unic/debugfs/unic_debugfs.c | 19 ++++++ drivers/net/ub/unic/debugfs/unic_debugfs.h | 1 + .../net/ub/unic/debugfs/unic_entry_debugfs.c | 59 +++++++++++++++++++ .../net/ub/unic/debugfs/unic_entry_debugfs.h | 16 +++++ 5 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ub/unic/debugfs/unic_entry_debugfs.c create mode 100644 drivers/net/ub/unic/debugfs/unic_entry_debugfs.h diff --git a/drivers/net/ub/unic/Makefile b/drivers/net/ub/unic/Makefile index fa5de4255e68..041815219e0c 100644 --- a/drivers/net/ub/unic/Makefile +++ b/drivers/net/ub/unic/Makefile @@ -9,5 +9,5 @@ ccflags-y += -I$(srctree)/drivers/net/ub/unic/debugfs obj-$(CONFIG_UB_UNIC) += unic.o unic-objs = unic_main.o unic_ethtool.o unic_hw.o unic_guid.o unic_netdev.o unic_dev.o unic_qos_hw.o unic_event.o unic_crq.o unic-objs += unic_channel.o debugfs/unic_debugfs.o unic_rx.o unic_tx.o unic_txrx.o unic_comm_addr.o unic_rack_ip.o unic_stats.o -unic-objs += debugfs/unic_ctx_debugfs.o unic_reset.o debugfs/unic_qos_debugfs.o +unic-objs += debugfs/unic_ctx_debugfs.o unic_reset.o debugfs/unic_qos_debugfs.o debugfs/unic_entry_debugfs.o unic-$(CONFIG_UB_UNIC_DCB) += unic_dcbnl.o diff --git a/drivers/net/ub/unic/debugfs/unic_debugfs.c b/drivers/net/ub/unic/debugfs/unic_debugfs.c index f9cc6e887ce0..63703934613d 100644 --- a/drivers/net/ub/unic/debugfs/unic_debugfs.c +++ b/drivers/net/ub/unic/debugfs/unic_debugfs.c @@ -14,6 +14,7 @@ #include "unic_dev.h" #include "unic_hw.h" #include "unic_qos_debugfs.h" +#include "unic_entry_debugfs.h" #include "unic_debugfs.h" static int unic_dbg_dump_dev_info(struct seq_file *s, void *data) @@ -258,6 +259,10 @@ static bool unic_dbg_dentry_support(struct device *dev, u32 property) static struct ubase_dbg_dentry_info unic_dbg_dentry[] = { { + .name = "ip_tbl", + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + }, { .name = "context", .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, .support = unic_dbg_dentry_support, @@ -276,6 +281,20 @@ static struct ubase_dbg_dentry_info unic_dbg_dentry[] = { static struct ubase_dbg_cmd_info unic_dbg_cmd[] = { { + .name = "ip_tbl_spec", + .dentry_index = UNIC_DBG_DENTRY_IP, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_ip_tbl_spec, + }, { + .name = "ip_tbl_list", + .dentry_index = UNIC_DBG_DENTRY_IP, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_ip_tbl_list, + }, { .name = "jfs_context", .dentry_index = UNIC_DBG_DENTRY_CONTEXT, .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, diff --git a/drivers/net/ub/unic/debugfs/unic_debugfs.h b/drivers/net/ub/unic/debugfs/unic_debugfs.h index 065630fbd35e..73a75b091b4b 100644 --- a/drivers/net/ub/unic/debugfs/unic_debugfs.h +++ b/drivers/net/ub/unic/debugfs/unic_debugfs.h @@ -13,6 +13,7 @@ #define unic_get_ubase_root_dentry(adev) ubase_diag_debugfs_root(adev) enum unic_dbg_dentry_type { + UNIC_DBG_DENTRY_IP = 0, UNIC_DBG_DENTRY_CONTEXT, UNIC_DBG_DENTRY_QOS, /* must be the last entry. */ diff --git a/drivers/net/ub/unic/debugfs/unic_entry_debugfs.c b/drivers/net/ub/unic/debugfs/unic_entry_debugfs.c new file mode 100644 index 000000000000..74b5fdb95aaa --- /dev/null +++ b/drivers/net/ub/unic/debugfs/unic_entry_debugfs.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. + * + */ + +#include +#include + +#include "unic_comm_addr.h" +#include "unic_dev.h" +#include "unic_debugfs.h" +#include "unic_entry_debugfs.h" + +static const char * const unic_entry_state_str[] = { + "TO_ADD", "TO_DEL", "ACTIVE" +}; + +int unic_dbg_dump_ip_tbl_spec(struct seq_file *s, void *data) +{ + struct unic_dev *unic_dev = dev_get_drvdata(s->private); + u32 total_ip_tbl_size, total_ue_num; + struct ubase_caps *ubase_caps; + + ubase_caps = ubase_get_dev_caps(unic_dev->comdev.adev); + total_ue_num = ubase_caps->total_ue_num; + total_ip_tbl_size = unic_dev->caps.total_ip_tbl_size; + + seq_printf(s, "total_ue_num\t: %u\n", total_ue_num); + seq_printf(s, "total_ip_tbl_size\t: %u\n", total_ip_tbl_size); + + return 0; +} + +int unic_dbg_dump_ip_tbl_list(struct seq_file *s, void *data) +{ + struct unic_dev *unic_dev = dev_get_drvdata(s->private); + struct unic_comm_addr_node *ip_node; + struct unic_addr_tbl *ip_tbl; + struct list_head *list; + u16 i = 0; + + seq_printf(s, "No %-43sSTATE IP_MASK\n", "IP_ADDR"); + + ip_tbl = &unic_dev->vport.addr_tbl; + list = &ip_tbl->ip_list; + spin_lock_bh(&ip_tbl->ip_list_lock); + list_for_each_entry(ip_node, list, node) { + seq_printf(s, "%-4d", i++); + seq_printf(s, "%-43pI6c", &ip_node->ip_addr.s6_addr); + seq_printf(s, "%-9s", unic_entry_state_str[ip_node->state]); + seq_printf(s, "%-3u", ip_node->node_mask); + + seq_puts(s, "\n"); + } + spin_unlock_bh(&ip_tbl->ip_list_lock); + + return 0; +} diff --git a/drivers/net/ub/unic/debugfs/unic_entry_debugfs.h b/drivers/net/ub/unic/debugfs/unic_entry_debugfs.h new file mode 100644 index 000000000000..73ab85f4d5f3 --- /dev/null +++ b/drivers/net/ub/unic/debugfs/unic_entry_debugfs.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. + * + */ + +#ifndef __UNIC_ENTRY_DEBUGFS_H__ +#define __UNIC_ENTRY_DEBUGFS_H__ + +#include +#include + +int unic_dbg_dump_ip_tbl_spec(struct seq_file *s, void *data); +int unic_dbg_dump_ip_tbl_list(struct seq_file *s, void *data); + +#endif /* _UNIC_ENTRY_DEBUGFS_H */ -- Gitee From f60626c8929b281877bd526665e9b150860bd084 Mon Sep 17 00:00:00 2001 From: Jianquan Lin Date: Thu, 20 Nov 2025 11:25:40 +0800 Subject: [PATCH 064/103] ub:hisi-ubus: Adding compatibility Interfaces for ub memory commit 56bce93e4090d11862d320e1025418bad27d1f45 openEuler Adding southbound and northbound compatibility Interfaces for ub memory Signed-off-by: Jianquan Lin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/ubus/memory.c | 4 +- drivers/ub/ubus/memory.h | 4 +- drivers/ub/ubus/vendor/hisilicon/hisi-ubus.h | 4 + drivers/ub/ubus/vendor/hisilicon/memory.c | 90 +++++++++++++++----- 4 files changed, 79 insertions(+), 23 deletions(-) diff --git a/drivers/ub/ubus/memory.c b/drivers/ub/ubus/memory.c index e7b3144db4bd..e7fcdf76f28e 100644 --- a/drivers/ub/ubus/memory.c +++ b/drivers/ub/ubus/memory.c @@ -114,7 +114,7 @@ void ub_mem_drain_start(u32 scna) } if (mem_device->ops && mem_device->ops->mem_drain_start) - mem_device->ops->mem_drain_start(mem_device); + mem_device->ops->mem_drain_start(ubc); else dev_warn(mem_device->dev, "ub mem_device ops mem_drain_start is null.\n"); } @@ -138,7 +138,7 @@ int ub_mem_drain_state(u32 scna) } if (mem_device->ops && mem_device->ops->mem_drain_state) - return mem_device->ops->mem_drain_state(mem_device); + return mem_device->ops->mem_drain_state(ubc); dev_warn(mem_device->dev, "ub memory decoder ops mem_drain_state is null.\n"); return 0; diff --git a/drivers/ub/ubus/memory.h b/drivers/ub/ubus/memory.h index 7c841b466f3e..f96f7a290616 100644 --- a/drivers/ub/ubus/memory.h +++ b/drivers/ub/ubus/memory.h @@ -29,8 +29,8 @@ struct ub_mem_ras_ctx { }; struct ub_mem_device_ops { - void (*mem_drain_start)(struct ub_mem_device *mem_device); - int (*mem_drain_state)(struct ub_mem_device *mem_device); + void (*mem_drain_start)(struct ub_bus_controller *ubc); + int (*mem_drain_state)(struct ub_bus_controller *ubc); bool (*mem_validate_pa)(struct ub_bus_controller *ubc, u64 pa_start, u64 pa_end, bool cacheable); diff --git a/drivers/ub/ubus/vendor/hisilicon/hisi-ubus.h b/drivers/ub/ubus/vendor/hisilicon/hisi-ubus.h index 9aa3ba5521c1..092695e9d43c 100644 --- a/drivers/ub/ubus/vendor/hisilicon/hisi-ubus.h +++ b/drivers/ub/ubus/vendor/hisilicon/hisi-ubus.h @@ -12,6 +12,10 @@ #define MB_SIZE_OFFSET 20 #define HI_UBC_PRIVATE_DATA_RESERVED 3 #define HI_UBC_PRIVATE_DATA_RESERVED2 111 +#define UB_MEM_VERSION_INVALID 0xffffffff +#define UB_MEM_VERSION_0 0 +#define UB_MEM_VERSION_1 1 +#define UB_MEM_VERSION_2 2 struct hi_mem_pa_info { u64 decode_addr; diff --git a/drivers/ub/ubus/vendor/hisilicon/memory.c b/drivers/ub/ubus/vendor/hisilicon/memory.c index 4d4f80f847fc..fa9747171eea 100644 --- a/drivers/ub/ubus/vendor/hisilicon/memory.c +++ b/drivers/ub/ubus/vendor/hisilicon/memory.c @@ -24,9 +24,13 @@ #define MEM_EVENT_MAX_NUM 16 #define MAR_ERR_ADDR_COUNT 10 #define MAR_ERR_ADDR_SIZE 2 +#define MEM_DECODER_NUMBER_V1 5 +#define MEM_DECODER_NUMBER_V2 2 #define hpa_gen(addr_h, addr_l) (((u64)(addr_h) << 32) | (addr_l)) +static u8 ub_mem_num; + struct ub_mem_decoder { struct device *dev; struct ub_entity *uent; @@ -58,25 +62,26 @@ struct hi_get_ubmem_event_pld { static bool hi_mem_validate_pa(struct ub_bus_controller *ubc, u64 pa_start, u64 pa_end, bool cacheable); -static void hi_mem_drain_start(struct ub_mem_device *mem_device) +static void hi_mem_drain_start(struct ub_bus_controller *ubc) { - struct ub_mem_decoder *decoder, *data = mem_device->priv_data; + struct ub_mem_decoder *decoder, *data = ubc->mem_device->priv_data; if (!data) { - dev_err(mem_device->dev, "ubc mem_decoder is null.\n"); + dev_err(&ubc->dev, "ubc mem_decoder is null.\n"); return; } - for (int i = 0; i < MEM_INFO_NUM; i++) { + for (int i = 0; i < ub_mem_num; i++) { decoder = &data[i]; writel(0, decoder->base_reg + DRAIN_ENABLE_REG_OFFSET); writel(1, decoder->base_reg + DRAIN_ENABLE_REG_OFFSET); } } -static int hi_mem_drain_state(struct ub_mem_device *mem_device) +static int hi_mem_drain_state(struct ub_bus_controller *ubc) { - struct ub_mem_decoder *decoder, *data = mem_device->priv_data; + struct ub_mem_decoder *decoder, *data = ubc->mem_device->priv_data; + struct ub_mem_device *mem_device = ubc->mem_device; int val = 0; if (!data) { @@ -84,7 +89,7 @@ static int hi_mem_drain_state(struct ub_mem_device *mem_device) return 0; } - for (int i = 0; i < MEM_INFO_NUM; i++) { + for (int i = 0; i < ub_mem_num; i++) { decoder = &data[i]; val = readb(decoder->base_reg + DRAIN_STATE_REG_OFFSET) & 0x1; dev_info_ratelimited(decoder->dev, "ub memory decoder[%d] drain state, val=%d\n", @@ -246,16 +251,25 @@ static irqreturn_t hi_mem_ras_irq(int irq, void *context) return IRQ_WAKE_THREAD; } -static int hi_mem_decoder_create_one(struct ub_bus_controller *ubc, int mar_id) +static bool is_ub_mem_version_valid(struct ub_bus_controller *ubc) +{ + struct hi_ubc_private_data *data = ubc->data; + + if (!data || data->ub_mem_version == UB_MEM_VERSION_INVALID) + return false; + return true; +} + +static int hi_mem_decoder_create_one(struct ub_bus_controller *ubc, int index) { - struct hi_ubc_private_data *data = (struct hi_ubc_private_data *)ubc->data; struct ub_mem_decoder *decoder, *priv_data = ubc->mem_device->priv_data; + struct hi_ubc_private_data *data = ubc->data; - decoder = &priv_data[mar_id]; + decoder = &priv_data[index]; decoder->dev = &ubc->dev; decoder->uent = ubc->uent; - decoder->base_reg = ioremap(data->mem_pa_info[mar_id].decode_addr, + decoder->base_reg = ioremap(data->mem_pa_info[index].decode_addr, SZ_64); if (!decoder->base_reg) { dev_err(decoder->dev, "ub mem decoder base reg ioremap failed.\n"); @@ -265,24 +279,47 @@ static int hi_mem_decoder_create_one(struct ub_bus_controller *ubc, int mar_id) return 0; } -static void hi_mem_decoder_remove_one(struct ub_bus_controller *ubc, int mar_id) +static void hi_mem_decoder_remove_one(struct ub_bus_controller *ubc, int index) { struct ub_mem_decoder *priv_data = ubc->mem_device->priv_data; - iounmap(priv_data[mar_id].base_reg); + iounmap(priv_data[index].base_reg); +} + +static u8 get_mem_decoder_number(struct hi_ubc_private_data *data) +{ + switch (data->ub_mem_version) { + case UB_MEM_VERSION_0: + case UB_MEM_VERSION_1: + return MEM_DECODER_NUMBER_V1; + case UB_MEM_VERSION_2: + return MEM_DECODER_NUMBER_V2; + default: + return 0; + } } int hi_mem_decoder_create(struct ub_bus_controller *ubc) { struct ub_mem_device *mem_device; + struct hi_ubc_private_data *data; void *priv_data; int ret; + if (!is_ub_mem_version_valid(ubc)) { + dev_info(&ubc->dev, "Don't need to create mem decoder\n"); + return 0; + } + + ub_mem_num = get_mem_decoder_number(data); + if (!ub_mem_num) + return -EINVAL; + mem_device = kzalloc(sizeof(*mem_device), GFP_KERNEL); if (!mem_device) return -ENOMEM; - priv_data = kcalloc(MEM_INFO_NUM, sizeof(struct ub_mem_decoder), + priv_data = kcalloc(ub_mem_num, sizeof(struct ub_mem_decoder), GFP_KERNEL); if (!priv_data) { kfree(mem_device); @@ -296,7 +333,7 @@ int hi_mem_decoder_create(struct ub_bus_controller *ubc) mem_device->priv_data = priv_data; ubc->mem_device = mem_device; - for (int i = 0; i < MEM_INFO_NUM; i++) { + for (int i = 0; i < ub_mem_num; i++) { ret = hi_mem_decoder_create_one(ubc, i); if (ret) { dev_err(&ubc->dev, "hi mem create decoder %d failed\n", i); @@ -318,7 +355,12 @@ void hi_mem_decoder_remove(struct ub_bus_controller *ubc) if (!ubc->mem_device) return; - for (int i = 0; i < MEM_INFO_NUM; i++) + if (!is_ub_mem_version_valid(ubc)) { + dev_info(&ubc->dev, "Don't need to remove mem decoder\n"); + return; + } + + for (int i = 0; i < ub_mem_num; i++) hi_mem_decoder_remove_one(ubc, i); kfree(ubc->mem_device->priv_data); @@ -333,7 +375,12 @@ void hi_register_ubmem_irq(struct ub_bus_controller *ubc) u32 usi_idx; if (!ubc->mem_device) { - pr_err("mem device is NULL!\n"); + pr_err("register ubmem irq failed, mem device is NULL!\n"); + return; + } + + if (!is_ub_mem_version_valid(ubc)) { + dev_info(&ubc->dev, "Don't need to register_ubmem_irq\n"); return; } @@ -371,6 +418,11 @@ void hi_unregister_ubmem_irq(struct ub_bus_controller *ubc) return; } + if (!is_ub_mem_version_valid(ubc)) { + dev_info(&ubc->dev, "Don't need to unregister_ubmem_irq\n"); + return; + } + irq_num = ubc->mem_device->ubmem_irq_num; if (irq_num < 0) return; @@ -404,8 +456,8 @@ static bool hi_mem_validate_pa(struct ub_bus_controller *ubc, return false; } - data = (struct hi_ubc_private_data *)ubc->data; - for (u16 i = 0; i < MEM_INFO_NUM; i++) { + data = ubc->data; + for (u16 i = 0; i < ub_mem_num; i++) { if (ub_hpa_valid(pa_start, pa_end, data->mem_pa_info[i].cc_base_addr, data->mem_pa_info[i].cc_base_size) && -- Gitee From 838b18a08ac744b6145e187a4dbdf51ac8906ce5 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 10:11:22 +0800 Subject: [PATCH 065/103] ub: udma: Support query jfs and jetty context from hw. commit ba0d9456a61f3f559ea978da1639302deb0182c7 openEuler This patch adds the ability to query jfs and jetty context from hardware. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_dfx.c | 281 +++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_dfx.h | 4 + drivers/ub/urma/hw/udma/udma_jetty.h | 143 ++++++++++++++ drivers/ub/urma/hw/udma/udma_jfr.h | 50 +++++ drivers/ub/urma/hw/udma/udma_main.c | 2 + 5 files changed, 480 insertions(+) diff --git a/drivers/ub/urma/hw/udma/udma_dfx.c b/drivers/ub/urma/hw/udma/udma_dfx.c index f6920f879eea..5580fc474b9d 100644 --- a/drivers/ub/urma/hw/udma/udma_dfx.c +++ b/drivers/ub/urma/hw/udma/udma_dfx.c @@ -13,6 +13,172 @@ bool dfx_switch; +static int to_udma_trans_mode(uint32_t type, struct udma_dev *dev, + enum ubcore_transport_mode *trans_mode) +{ + switch (type) { + case JETTY_UM: + *trans_mode = UBCORE_TP_UM; + break; + case JETTY_RC: + *trans_mode = UBCORE_TP_RC; + break; + case JETTY_RM: + *trans_mode = UBCORE_TP_RM; + break; + default: + dev_err(dev->dev, "transport mode error, type = %u.\n", type); + return -EINVAL; + } + + return 0; +} + +static int to_udma_jetty_ctx_state(uint32_t state, struct udma_dev *dev, + enum ubcore_jetty_state *jetty_state) +{ + switch (state) { + case JETTY_RESET: + *jetty_state = UBCORE_JETTY_STATE_RESET; + break; + case JETTY_READY: + *jetty_state = UBCORE_JETTY_STATE_READY; + break; + case JETTY_ERROR: + *jetty_state = UBCORE_JETTY_STATE_ERROR; + break; + case JETTY_SUSPEND: + *jetty_state = UBCORE_JETTY_STATE_SUSPENDED; + break; + default: + dev_err(dev->dev, "JFS context state error, state = %u.\n", state); + return -EINVAL; + } + + return 0; +} + +int udma_query_jfs(struct ubcore_jfs *jfs, struct ubcore_jfs_cfg *cfg, + struct ubcore_jfs_attr *attr) +{ + struct udma_dev *udma_dev = to_udma_dev(jfs->ub_dev); + struct udma_jfs *udma_jfs = to_udma_jfs(jfs); + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + struct udma_jetty_ctx *jfs_ctx; + uint32_t wqe_bb_depth; + int ret; + + mbox_attr.tag = jfs->jfs_id.id; + mbox_attr.op = UDMA_CMD_QUERY_JFS_CONTEXT; + mailbox = udma_mailbox_query_ctx(udma_dev, &mbox_attr); + if (!mailbox) + return -ENOMEM; + + jfs_ctx = (struct udma_jetty_ctx *)mailbox->buf; + + ret = to_udma_jetty_ctx_state(jfs_ctx->state, udma_dev, &attr->state); + if (ret) + goto err_jfs_ctx; + + cfg->priority = jfs_ctx->sl; + cfg->flag = jfs->jfs_cfg.flag; + cfg->max_sge = jfs->jfs_cfg.max_sge; + cfg->max_rsge = jfs->jfs_cfg.max_rsge; + cfg->err_timeout = jfs_ctx->ta_timeout; + wqe_bb_depth = 1 << jfs_ctx->sqe_bb_shift; + cfg->depth = wqe_bb_depth / udma_jfs->sq.sqe_bb_cnt; + cfg->rnr_retry = jfs_ctx->rnr_retry_num; + cfg->max_inline_data = jfs->jfs_cfg.max_inline_data; + + ret = to_udma_trans_mode(jfs_ctx->type, udma_dev, &cfg->trans_mode); + if (ret) + goto err_jfs_ctx; + + if (udma_jfs->sq.buf.kva) { + cfg->jfc = jfs->jfs_cfg.jfc; + cfg->eid_index = jfs_ctx->seid_idx; + } + +err_jfs_ctx: + udma_free_cmd_mailbox(udma_dev, mailbox); + + return ret; +} + +int udma_query_jetty(struct ubcore_jetty *jetty, struct ubcore_jetty_cfg *cfg, + struct ubcore_jetty_attr *attr) +{ + struct udma_dev *udma_dev = to_udma_dev(jetty->ub_dev); + struct udma_jetty *udma_jetty = to_udma_jetty(jetty); + struct ubase_mbx_attr jfr_mbox_attr = {}; + struct ubase_cmd_mailbox *jetty_mailbox; + struct ubase_cmd_mailbox *jfr_mailbox; + struct ubase_mbx_attr mbox_attr = {}; + struct udma_jetty_ctx *jetty_ctx; + struct udma_jfr_ctx *jfr_ctx; + uint32_t wqe_bb_depth; + int ret; + + mbox_attr.tag = jetty->jetty_id.id; + mbox_attr.op = UDMA_CMD_QUERY_JFS_CONTEXT; + jetty_mailbox = udma_mailbox_query_ctx(udma_dev, &mbox_attr); + if (!jetty_mailbox) + return -ENOMEM; + + jfr_mbox_attr.tag = udma_jetty->jfr->ubcore_jfr.jfr_id.id; + jfr_mbox_attr.op = UDMA_CMD_QUERY_JFR_CONTEXT; + jfr_mailbox = udma_mailbox_query_ctx(udma_dev, &jfr_mbox_attr); + if (!jfr_mailbox) { + udma_free_cmd_mailbox(udma_dev, jetty_mailbox); + return -ENOMEM; + } + + jetty_ctx = (struct udma_jetty_ctx *)jetty_mailbox->buf; + jfr_ctx = (struct udma_jfr_ctx *)jfr_mailbox->buf; + + wqe_bb_depth = 1 << jetty_ctx->sqe_bb_shift; + cfg->id = jetty->jetty_id.id; + cfg->jfs_depth = wqe_bb_depth / udma_jetty->sq.sqe_bb_cnt; + cfg->jfr_depth = 1 << jfr_ctx->rqe_shift; + cfg->flag = jetty->jetty_cfg.flag; + cfg->max_send_sge = jetty->jetty_cfg.max_send_sge; + cfg->max_send_rsge = jetty->jetty_cfg.max_send_rsge; + cfg->max_recv_sge = jetty->jetty_cfg.max_recv_sge; + cfg->max_inline_data = jetty->jetty_cfg.max_inline_data; + cfg->priority = jetty_ctx->sl; + cfg->rnr_retry = jetty_ctx->rnr_retry_num; + cfg->err_timeout = jetty_ctx->ta_timeout; + cfg->min_rnr_timer = jetty->jetty_cfg.min_rnr_timer; + + ret = to_udma_trans_mode(jetty_ctx->type, udma_dev, &cfg->trans_mode); + if (ret) + goto err_jetty_ctx; + + cfg->token_value.token = 0; + + ret = to_udma_jetty_ctx_state(jetty_ctx->state, udma_dev, &attr->state); + if (ret) + goto err_jetty_ctx; + + attr->rx_threshold = to_udma_rx_threshold(jfr_ctx->limit_wl); + + if (udma_jetty->sq.buf.kva) { + cfg->eid_index = jetty_ctx->seid_idx; + cfg->send_jfc = jetty->jetty_cfg.send_jfc; + cfg->recv_jfc = jetty->jetty_cfg.recv_jfc; + cfg->jfr = jetty->jetty_cfg.jfr; + cfg->jetty_grp = jetty->jetty_cfg.jetty_grp; + } + +err_jetty_ctx: + jfr_ctx->token_value = 0; + udma_free_cmd_mailbox(udma_dev, jfr_mailbox); + udma_free_cmd_mailbox(udma_dev, jetty_mailbox); + + return ret; +} + static int udma_query_res_list(struct udma_dev *udma_dev, struct udma_dfx_entity *entity, struct ubcore_res_val *val, @@ -139,6 +305,119 @@ static int udma_query_res_rc(struct udma_dev *udma_dev, return 0; } +static int udma_query_res_jetty(struct udma_dev *udma_dev, + struct ubcore_res_key *key, + struct ubcore_res_val *val) +{ + struct ubcore_res_jetty_val *res_jetty = (struct ubcore_res_jetty_val *)val->addr; + struct ubase_mbx_attr mbox_attr = {}; + enum ubcore_jetty_state jetty_state; + struct ubase_cmd_mailbox *mailbox; + struct udma_jetty_ctx *jettyc; + struct udma_dfx_jetty *jetty; + int ret; + + if (key->key_cnt == 0) + return udma_query_res_list(udma_dev, &udma_dev->dfx_info->jetty, val, "jetty"); + + read_lock(&udma_dev->dfx_info->jetty.rwlock); + jetty = (struct udma_dfx_jetty *)xa_load(&udma_dev->dfx_info->jetty.table, key->key); + if (!jetty) { + read_unlock(&udma_dev->dfx_info->jetty.rwlock); + dev_err(udma_dev->dev, "failed to query jetty, jetty_id = %u.\n", + key->key); + return -EINVAL; + } + res_jetty->jfs_depth = jetty->jfs_depth; + read_unlock(&udma_dev->dfx_info->jetty.rwlock); + + mbox_attr.tag = key->key; + mbox_attr.op = UDMA_CMD_QUERY_JFS_CONTEXT; + mailbox = udma_mailbox_query_ctx(udma_dev, &mbox_attr); + if (!mailbox) + return -ENOMEM; + + jettyc = (struct udma_jetty_ctx *)mailbox->buf; + res_jetty->jetty_id = key->key; + + ret = to_udma_jetty_ctx_state(jettyc->state, udma_dev, &jetty_state); + if (ret) + goto err_res_jetty_ctx; + + res_jetty->state = jetty_state; + res_jetty->recv_jfc_id = jettyc->rx_jfcn; + res_jetty->send_jfc_id = jettyc->tx_jfcn; + res_jetty->priority = jettyc->sl; + res_jetty->jfr_id = jettyc->jfrn_l | + jettyc->jfrn_h << JETTY_CTX_JFRN_H_OFFSET; + jettyc->sqe_base_addr_l = 0; + jettyc->sqe_base_addr_h = 0; + jettyc->user_data_l = 0; + jettyc->user_data_h = 0; + + udma_dfx_ctx_print(udma_dev, "Jetty", key->key, sizeof(*jettyc) / sizeof(uint32_t), + (uint32_t *)jettyc); +err_res_jetty_ctx: + udma_free_cmd_mailbox(udma_dev, mailbox); + + return ret; +} + +static int udma_query_res_jfs(struct udma_dev *udma_dev, + struct ubcore_res_key *key, + struct ubcore_res_val *val) +{ + struct ubcore_res_jfs_val *res_jfs = (struct ubcore_res_jfs_val *)val->addr; + struct ubase_mbx_attr mbox_attr = {}; + enum ubcore_jetty_state jfs_state; + struct ubase_cmd_mailbox *mailbox; + struct udma_jetty_ctx *jfsc; + struct udma_dfx_jfs *jfs; + int ret; + + if (key->key_cnt == 0) + return udma_query_res_list(udma_dev, &udma_dev->dfx_info->jfs, val, "jfs"); + + read_lock(&udma_dev->dfx_info->jfs.rwlock); + jfs = (struct udma_dfx_jfs *)xa_load(&udma_dev->dfx_info->jfs.table, key->key); + if (!jfs) { + read_unlock(&udma_dev->dfx_info->jfs.rwlock); + dev_err(udma_dev->dev, "failed to query jfs, jfs_id = %u.\n", + key->key); + return -EINVAL; + } + res_jfs->depth = jfs->depth; + read_unlock(&udma_dev->dfx_info->jfs.rwlock); + + mbox_attr.tag = key->key; + mbox_attr.op = UDMA_CMD_QUERY_JFS_CONTEXT; + mailbox = udma_mailbox_query_ctx(udma_dev, &mbox_attr); + if (!mailbox) + return -ENOMEM; + + jfsc = (struct udma_jetty_ctx *)mailbox->buf; + res_jfs->jfs_id = key->key; + + ret = to_udma_jetty_ctx_state(jfsc->state, udma_dev, &jfs_state); + if (ret) + goto err_res_jetty_ctx; + + res_jfs->state = jfs_state; + res_jfs->priority = jfsc->sl; + res_jfs->jfc_id = jfsc->tx_jfcn; + jfsc->sqe_base_addr_l = 0; + jfsc->sqe_base_addr_h = 0; + jfsc->user_data_l = 0; + jfsc->user_data_h = 0; + + udma_dfx_ctx_print(udma_dev, "JFS", key->key, sizeof(*jfsc) / sizeof(uint32_t), + (uint32_t *)jfsc); +err_res_jetty_ctx: + udma_free_cmd_mailbox(udma_dev, mailbox); + + return ret; +} + static int udma_query_res_seg(struct udma_dev *udma_dev, struct ubcore_res_key *key, struct ubcore_res_val *val) { @@ -208,6 +487,8 @@ typedef int (*udma_query_res_handler)(struct udma_dev *udma_dev, static udma_query_res_handler g_udma_query_res_handlers[] = { [0] = NULL, + [UBCORE_RES_KEY_JFS] = udma_query_res_jfs, + [UBCORE_RES_KEY_JETTY] = udma_query_res_jetty, [UBCORE_RES_KEY_RC] = udma_query_res_rc, [UBCORE_RES_KEY_SEG] = udma_query_res_seg, [UBCORE_RES_KEY_DEV_TA] = udma_query_res_dev_ta, diff --git a/drivers/ub/urma/hw/udma/udma_dfx.h b/drivers/ub/urma/hw/udma/udma_dfx.h index 92c0db1aa744..febfde3b84ec 100644 --- a/drivers/ub/urma/hw/udma/udma_dfx.h +++ b/drivers/ub/urma/hw/udma/udma_dfx.h @@ -47,6 +47,10 @@ static inline uint32_t to_udma_rx_threshold(uint32_t limit_wl) } } +int udma_query_jfs(struct ubcore_jfs *jfs, struct ubcore_jfs_cfg *cfg, + struct ubcore_jfs_attr *attr); +int udma_query_jetty(struct ubcore_jetty *jetty, struct ubcore_jetty_cfg *cfg, + struct ubcore_jetty_attr *attr); int udma_query_res(struct ubcore_device *dev, struct ubcore_res_key *key, struct ubcore_res_val *val); int udma_dfx_init(struct udma_dev *udma_dev); diff --git a/drivers/ub/urma/hw/udma/udma_jetty.h b/drivers/ub/urma/hw/udma/udma_jetty.h index 00a3c41b39b6..5ee8f8f4403b 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.h +++ b/drivers/ub/urma/hw/udma/udma_jetty.h @@ -6,6 +6,16 @@ #include "udma_common.h" +#define JETTY_CTX_JFRN_H_OFFSET 12 + +enum jetty_state { + JETTY_RESET, + JETTY_READY, + JETTY_ERROR, + JETTY_SUSPEND, + STATE_NUM, +}; + struct udma_jetty { struct ubcore_jetty ubcore_jetty; struct udma_jfr *jfr; @@ -17,6 +27,139 @@ struct udma_jetty { bool ue_rx_closed; }; +enum jetty_type { + JETTY_RAW_OR_NIC, + JETTY_UM, + JETTY_RC, + JETTY_RM, + JETTY_TYPE_RESERVED, +}; + +struct udma_jetty_ctx { + /* DW0 */ + uint32_t ta_timeout : 2; + uint32_t rnr_retry_num : 3; + uint32_t type : 3; + uint32_t sqe_bb_shift : 4; + uint32_t sl : 4; + uint32_t state : 3; + uint32_t jfs_mode : 1; + uint32_t sqe_token_id_l : 12; + /* DW1 */ + uint32_t sqe_token_id_h : 8; + uint32_t err_mode : 1; + uint32_t rsv : 1; + uint32_t cmp_odr : 1; + uint32_t rsv1 : 1; + uint32_t sqe_base_addr_l : 20; + /* DW2 */ + uint32_t sqe_base_addr_h; + /* DW3 */ + uint32_t rsv2; + /* DW4 */ + uint32_t tx_jfcn : 20; + uint32_t jfrn_l : 12; + /* DW5 */ + uint32_t jfrn_h : 8; + uint32_t rsv3 : 4; + uint32_t rx_jfcn : 20; + /* DW6 */ + uint32_t seid_idx : 10; + uint32_t pi_type : 1; + uint32_t rsv4 : 21; + /* DW7 */ + uint32_t user_data_l; + /* DW8 */ + uint32_t user_data_h; + /* DW9 */ + uint32_t sqe_position : 1; + uint32_t sqe_pld_position : 1; + uint32_t sqe_pld_tokenid : 20; + uint32_t rsv5 : 10; + /* DW10 */ + uint32_t tpn : 24; + uint32_t rsv6 : 8; + /* DW11 */ + uint32_t rmt_eid : 20; + uint32_t rsv7 : 12; + /* DW12 */ + uint32_t rmt_tokenid : 20; + uint32_t rsv8 : 12; + /* DW13 - DW15 */ + uint32_t rsv8_1[3]; + /* DW16 */ + uint32_t next_send_ssn : 16; + uint32_t src_order_wqe : 16; + /* DW17 */ + uint32_t src_order_ssn : 16; + uint32_t src_order_sgme_cnt : 16; + /* DW18 */ + uint32_t src_order_sgme_send_cnt : 16; + uint32_t CI : 16; + /* DW19 */ + uint32_t wqe_sgmt_send_cnt : 20; + uint32_t src_order_wqebb_num : 4; + uint32_t src_order_wqe_vld : 1; + uint32_t no_wqe_send_cnt : 4; + uint32_t so_lp_vld : 1; + uint32_t fence_lp_vld : 1; + uint32_t strong_fence_lp_vld : 1; + /* DW20 */ + uint32_t PI : 16; + uint32_t sq_db_doing : 1; + uint32_t ost_rce_credit : 15; + /* DW21 */ + uint32_t sq_db_retrying : 1; + uint32_t wmtp_rsv0 : 31; + /* DW22 */ + uint32_t wait_ack_timeout : 1; + uint32_t wait_rnr_timeout : 1; + uint32_t cqe_ie : 1; + uint32_t cqe_sz : 1; + uint32_t wml_rsv0 : 28; + /* DW23 */ + uint32_t wml_rsv1 : 32; + /* DW24 */ + uint32_t next_rcv_ssn : 16; + uint32_t next_cpl_bb_idx : 16; + /* DW25 */ + uint32_t next_cpl_sgmt_num : 20; + uint32_t we_rsv0 : 12; + /* DW26 */ + uint32_t next_cpl_bb_num : 4; + uint32_t next_cpl_cqe_en : 1; + uint32_t next_cpl_info_vld : 1; + uint32_t rpting_cqe : 1; + uint32_t not_rpt_cqe : 1; + uint32_t flush_ssn : 16; + uint32_t flush_ssn_vld : 1; + uint32_t flush_vld : 1; + uint32_t flush_cqe_done : 1; + uint32_t we_rsv1 : 5; + /* DW27 */ + uint32_t rcved_cont_ssn_num : 20; + uint32_t we_rsv2 : 12; + /* DW28 */ + uint32_t sq_timer; + /* DW29 */ + uint32_t rnr_cnt : 3; + uint32_t abt_ssn : 16; + uint32_t abt_ssn_vld : 1; + uint32_t taack_timeout_flag : 1; + uint32_t we_rsv3 : 9; + uint32_t err_type_l : 2; + /* DW30 */ + uint32_t err_type_h : 7; + uint32_t sq_flush_ssn : 16; + uint32_t we_rsv4 : 9; + /* DW31 */ + uint32_t avail_sgmt_ost : 10; + uint32_t read_op_cnt : 10; + uint32_t we_rsv5 : 12; + /* DW32 - DW63 */ + uint32_t taack_nack_bm[32]; +}; + static inline struct udma_jetty *to_udma_jetty(struct ubcore_jetty *jetty) { return container_of(jetty, struct udma_jetty, ubcore_jetty); diff --git a/drivers/ub/urma/hw/udma/udma_jfr.h b/drivers/ub/urma/hw/udma/udma_jfr.h index cb1ecbaf3572..858e36d3a27a 100644 --- a/drivers/ub/urma/hw/udma/udma_jfr.h +++ b/drivers/ub/urma/hw/udma/udma_jfr.h @@ -30,6 +30,56 @@ struct udma_jfr { struct completion ae_comp; }; +struct udma_jfr_ctx { + /* DW0 */ + uint32_t state : 2; + uint32_t limit_wl : 2; + uint32_t rqe_size_shift : 3; + uint32_t token_en : 1; + uint32_t rqe_shift : 4; + uint32_t rnr_timer : 5; + uint32_t record_db_en : 1; + uint32_t rqe_token_id_l : 14; + /* DW1 */ + uint32_t rqe_token_id_h : 6; + uint32_t type : 3; + uint32_t rsv : 3; + uint32_t rqe_base_addr_l : 20; + /* DW2 */ + uint32_t rqe_base_addr_h; + /* DW3 */ + uint32_t rqe_position : 1; + uint32_t pld_position : 1; + uint32_t pld_token_id : 20; + uint32_t rsv1 : 10; + /* DW4 */ + uint32_t token_value; + /* DW5 */ + uint32_t user_data_l; + /* DW6 */ + uint32_t user_data_h; + /* DW7 */ + uint32_t pi : 16; + uint32_t ci : 16; + /* DW8 */ + uint32_t idx_que_addr_l; + /* DW9 */ + uint32_t idx_que_addr_h : 20; + uint32_t jfcn_l : 12; + /* DW10 */ + uint32_t jfcn_h : 8; + uint32_t record_db_addr_l : 24; + /* DW11 */ + uint32_t record_db_addr_m; + /* DW12 */ + uint32_t record_db_addr_h : 2; + uint32_t cqeie : 1; + uint32_t cqesz : 1; + uint32_t rsv2 : 28; + /* padding */ + uint32_t reserved[3]; +}; + static inline struct udma_jfr *to_udma_jfr(struct ubcore_jfr *jfr) { return container_of(jfr, struct udma_jfr, ubcore_jfr); diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 5bf8631260a5..ce6b9db0ea06 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -173,6 +173,8 @@ static struct ubcore_ops g_dev_ops = { .unregister_seg = udma_unregister_seg, .import_seg = udma_import_seg, .unimport_seg = udma_unimport_seg, + .query_jfs = udma_query_jfs, + .query_jetty = udma_query_jetty, }; static void udma_uninit_group_table(struct udma_dev *dev, struct udma_group_table *table) -- Gitee From 72973e44ce99e217044d6efdcfc2b283cde4a173 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 10:13:06 +0800 Subject: [PATCH 066/103] ub: udma: Support query jfr context from hw. commit b63f4fc5c01bd57625360a6580b1cfdcc0cf833c openEuler This patch adds the ability to query jfr context from hardware. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_dfx.c | 130 ++++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_dfx.h | 2 + drivers/ub/urma/hw/udma/udma_jfr.h | 2 + drivers/ub/urma/hw/udma/udma_main.c | 1 + 4 files changed, 135 insertions(+) diff --git a/drivers/ub/urma/hw/udma/udma_dfx.c b/drivers/ub/urma/hw/udma/udma_dfx.c index 5580fc474b9d..96e6185c437f 100644 --- a/drivers/ub/urma/hw/udma/udma_dfx.c +++ b/drivers/ub/urma/hw/udma/udma_dfx.c @@ -34,6 +34,27 @@ static int to_udma_trans_mode(uint32_t type, struct udma_dev *dev, return 0; } +static int to_udma_jfr_ctx_state(uint32_t state, struct udma_dev *dev, + enum ubcore_jfr_state *jfr_state) +{ + switch (state) { + case JETTY_RESET: + *jfr_state = UBCORE_JFR_STATE_RESET; + break; + case JETTY_READY: + *jfr_state = UBCORE_JFR_STATE_READY; + break; + case JETTY_ERROR: + *jfr_state = UBCORE_JFR_STATE_ERROR; + break; + default: + dev_err(dev->dev, "JFR context state error, state = %u.\n", state); + return -EINVAL; + } + + return 0; +} + static int to_udma_jetty_ctx_state(uint32_t state, struct udma_dev *dev, enum ubcore_jetty_state *jetty_state) { @@ -58,6 +79,54 @@ static int to_udma_jetty_ctx_state(uint32_t state, struct udma_dev *dev, return 0; } +int udma_query_jfr(struct ubcore_jfr *jfr, struct ubcore_jfr_cfg *cfg, + struct ubcore_jfr_attr *attr) +{ + struct udma_dev *udma_dev = to_udma_dev(jfr->ub_dev); + struct udma_jfr *udma_jfr = to_udma_jfr(jfr); + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + struct udma_jfr_ctx *jfr_ctx; + int ret; + + mbox_attr.tag = jfr->jfr_id.id; + mbox_attr.op = UDMA_CMD_QUERY_JFR_CONTEXT; + mailbox = udma_mailbox_query_ctx(udma_dev, &mbox_attr); + if (!mailbox) + return -ENOMEM; + + jfr_ctx = (struct udma_jfr_ctx *)mailbox->buf; + + attr->rx_threshold = to_udma_rx_threshold(jfr_ctx->limit_wl); + + ret = to_udma_jfr_ctx_state(jfr_ctx->state, udma_dev, &attr->state); + if (ret) + goto err_jfr_ctx; + + cfg->id = jfr->jfr_id.id; + cfg->flag = jfr->jfr_cfg.flag; + cfg->max_sge = 1 << jfr_ctx->rqe_size_shift; + cfg->depth = 1 << jfr_ctx->rqe_shift; + cfg->token_value.token = 0; + cfg->flag.bs.token_policy = UBCORE_TOKEN_NONE; + cfg->min_rnr_timer = jfr_ctx->rnr_timer; + + ret = to_udma_trans_mode(jfr_ctx->type, udma_dev, &cfg->trans_mode); + if (ret) + goto err_jfr_ctx; + + if (udma_jfr->rq.buf.kva) { + cfg->eid_index = jfr->jfr_cfg.eid_index; + cfg->jfc = jfr->jfr_cfg.jfc; + } + +err_jfr_ctx: + jfr_ctx->token_value = 0; + udma_free_cmd_mailbox(udma_dev, mailbox); + + return ret; +} + int udma_query_jfs(struct ubcore_jfs *jfs, struct ubcore_jfs_cfg *cfg, struct ubcore_jfs_attr *attr) { @@ -418,6 +487,66 @@ static int udma_query_res_jfs(struct udma_dev *udma_dev, return ret; } +static int udma_query_res_jfr(struct udma_dev *udma_dev, + struct ubcore_res_key *key, + struct ubcore_res_val *val) +{ + struct ubcore_res_jfr_val *res_jfr = (struct ubcore_res_jfr_val *)val->addr; + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + enum ubcore_jfr_state jfr_state; + struct udma_jfr_ctx *jfrc; + uint32_t *jfr_id; + int ret; + + if (key->key_cnt == 0) + return udma_query_res_list(udma_dev, &udma_dev->dfx_info->jfr, val, "jfr"); + + jfr_id = (uint32_t *)xa_load(&udma_dev->dfx_info->jfr.table, key->key); + if (!jfr_id) { + dev_err(udma_dev->dev, "failed to query jfr, jfr_id = %u.\n", + key->key); + return -EINVAL; + } + + mbox_attr.tag = key->key; + mbox_attr.op = UDMA_CMD_QUERY_JFR_CONTEXT; + mailbox = udma_mailbox_query_ctx(udma_dev, &mbox_attr); + if (!mailbox) + return -ENOMEM; + + jfrc = (struct udma_jfr_ctx *)mailbox->buf; + res_jfr->jfr_id = key->key; + + ret = to_udma_jfr_ctx_state(jfrc->state, udma_dev, &jfr_state); + if (ret) + goto err_res_jfr_ctx; + + res_jfr->state = jfr_state; + res_jfr->depth = 1 << jfrc->rqe_shift; + res_jfr->jfc_id = jfrc->jfcn_l | + jfrc->jfcn_h << JFR_JFCN_H_OFFSET; + jfrc->rqe_base_addr_l = 0; + jfrc->rqe_base_addr_h = 0; + jfrc->token_en = 0; + jfrc->token_value = 0; + jfrc->user_data_l = 0; + jfrc->user_data_h = 0; + jfrc->idx_que_addr_l = 0; + jfrc->idx_que_addr_h = 0; + jfrc->record_db_addr_l = 0; + jfrc->record_db_addr_m = 0; + jfrc->record_db_addr_h = 0; + + udma_dfx_ctx_print(udma_dev, "JFR", key->key, sizeof(*jfrc) / sizeof(uint32_t), + (uint32_t *)jfrc); +err_res_jfr_ctx: + jfrc->token_value = 0; + udma_free_cmd_mailbox(udma_dev, mailbox); + + return ret; +} + static int udma_query_res_seg(struct udma_dev *udma_dev, struct ubcore_res_key *key, struct ubcore_res_val *val) { @@ -488,6 +617,7 @@ typedef int (*udma_query_res_handler)(struct udma_dev *udma_dev, static udma_query_res_handler g_udma_query_res_handlers[] = { [0] = NULL, [UBCORE_RES_KEY_JFS] = udma_query_res_jfs, + [UBCORE_RES_KEY_JFR] = udma_query_res_jfr, [UBCORE_RES_KEY_JETTY] = udma_query_res_jetty, [UBCORE_RES_KEY_RC] = udma_query_res_rc, [UBCORE_RES_KEY_SEG] = udma_query_res_seg, diff --git a/drivers/ub/urma/hw/udma/udma_dfx.h b/drivers/ub/urma/hw/udma/udma_dfx.h index febfde3b84ec..dcdf23646c1c 100644 --- a/drivers/ub/urma/hw/udma/udma_dfx.h +++ b/drivers/ub/urma/hw/udma/udma_dfx.h @@ -47,6 +47,8 @@ static inline uint32_t to_udma_rx_threshold(uint32_t limit_wl) } } +int udma_query_jfr(struct ubcore_jfr *jfr, struct ubcore_jfr_cfg *cfg, + struct ubcore_jfr_attr *attr); int udma_query_jfs(struct ubcore_jfs *jfs, struct ubcore_jfs_cfg *cfg, struct ubcore_jfs_attr *attr); int udma_query_jetty(struct ubcore_jetty *jetty, struct ubcore_jetty_cfg *cfg, diff --git a/drivers/ub/urma/hw/udma/udma_jfr.h b/drivers/ub/urma/hw/udma/udma_jfr.h index 858e36d3a27a..bffb68b3cdbd 100644 --- a/drivers/ub/urma/hw/udma/udma_jfr.h +++ b/drivers/ub/urma/hw/udma/udma_jfr.h @@ -8,6 +8,8 @@ #include "udma_ctx.h" #include "udma_common.h" +#define JFR_JFCN_H_OFFSET 12U + struct udma_jfr_idx_que { struct udma_buf buf; struct udma_table jfr_idx_table; diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index ce6b9db0ea06..dcf0ae79d583 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -174,6 +174,7 @@ static struct ubcore_ops g_dev_ops = { .import_seg = udma_import_seg, .unimport_seg = udma_unimport_seg, .query_jfs = udma_query_jfs, + .query_jfr = udma_query_jfr, .query_jetty = udma_query_jetty, }; -- Gitee From ee8119871485bad47869f6ddcda51797f0d464aa Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 10:15:06 +0800 Subject: [PATCH 067/103] ub: udma: Support query table item from hw. commit a49e6f591920eda270ee67aa7c7a313131903714 openEuler This patch adds the ability to query table item from hardware, Such as jfc context and jetty group context. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_dfx.c | 111 +++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jetty.h | 7 ++ drivers/ub/urma/hw/udma/udma_jfc.h | 71 +++++++++++++++++ 3 files changed, 189 insertions(+) diff --git a/drivers/ub/urma/hw/udma/udma_dfx.c b/drivers/ub/urma/hw/udma/udma_dfx.c index 96e6185c437f..7d186d85531d 100644 --- a/drivers/ub/urma/hw/udma/udma_dfx.c +++ b/drivers/ub/urma/hw/udma/udma_dfx.c @@ -432,6 +432,110 @@ static int udma_query_res_jetty(struct udma_dev *udma_dev, return ret; } +static int udma_query_res_jetty_grp(struct udma_dev *udma_dev, + struct ubcore_res_key *key, + struct ubcore_res_val *val) +{ + struct ubcore_res_jetty_group_val *res_jetty_grp = + (struct ubcore_res_jetty_group_val *)val->addr; + struct udma_jetty_grp_ctx *jetty_grpc; + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + uint32_t *jetty_grp_id; + int i; + + if (key->key_cnt == 0) + return udma_query_res_list(udma_dev, &udma_dev->dfx_info->jetty_grp, + val, "jetty_grp"); + + jetty_grp_id = (uint32_t *)xa_load(&udma_dev->dfx_info->jetty_grp.table, key->key); + if (!jetty_grp_id) { + dev_err(udma_dev->dev, "failed to query jetty grp, jetty_grp_id = %u.\n", + key->key); + return -EINVAL; + } + + res_jetty_grp->jetty_cnt = 0; + res_jetty_grp->jetty_list = vmalloc(sizeof(*res_jetty_grp->jetty_list) * + NUM_JETTY_PER_GROUP); + if (!res_jetty_grp->jetty_list) + return -ENOMEM; + + mbox_attr.tag = key->key; + mbox_attr.op = UDMA_CMD_QUERY_JETTY_GROUP_CONTEXT; + mailbox = udma_mailbox_query_ctx(udma_dev, &mbox_attr); + if (!mailbox) { + vfree(res_jetty_grp->jetty_list); + res_jetty_grp->jetty_list = NULL; + return -ENOMEM; + } + + jetty_grpc = (struct udma_jetty_grp_ctx *)mailbox->buf; + for (i = 0; i < NUM_JETTY_PER_GROUP; ++i) { + if (jetty_grpc->valid & BIT(i)) { + res_jetty_grp->jetty_list[res_jetty_grp->jetty_cnt] = + jetty_grpc->start_jetty_id + i; + ++res_jetty_grp->jetty_cnt; + } + } + + if (res_jetty_grp->jetty_cnt == 0) { + vfree(res_jetty_grp->jetty_list); + res_jetty_grp->jetty_list = NULL; + } + + udma_dfx_ctx_print(udma_dev, "Jetty_grp", key->key, sizeof(*jetty_grpc) / sizeof(uint32_t), + (uint32_t *)jetty_grpc); + udma_free_cmd_mailbox(udma_dev, mailbox); + + return 0; +} + +static int udma_query_res_jfc(struct udma_dev *udma_dev, + struct ubcore_res_key *key, + struct ubcore_res_val *val) +{ + struct ubcore_res_jfc_val *res_jfc = (struct ubcore_res_jfc_val *)val->addr; + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + struct udma_jfc_ctx *jfcc; + uint32_t *jfc_id; + + if (key->key_cnt == 0) + return udma_query_res_list(udma_dev, &udma_dev->dfx_info->jfc, val, "jfc"); + + jfc_id = (uint32_t *)xa_load(&udma_dev->dfx_info->jfc.table, key->key); + if (!jfc_id) { + dev_err(udma_dev->dev, "failed to query jfc, jfc_id = %u.\n", + key->key); + return -EINVAL; + } + + mbox_attr.tag = key->key; + mbox_attr.op = UDMA_CMD_QUERY_JFC_CONTEXT; + mailbox = udma_mailbox_query_ctx(udma_dev, &mbox_attr); + if (!mailbox) + return -ENOMEM; + + jfcc = (struct udma_jfc_ctx *)mailbox->buf; + res_jfc->jfc_id = key->key; + res_jfc->state = jfcc->state; + res_jfc->depth = 1 << (jfcc->shift + UDMA_JFC_DEPTH_SHIFT_BASE); + jfcc->cqe_va_l = 0; + jfcc->cqe_va_h = 0; + jfcc->token_en = 0; + jfcc->cqe_token_value = 0; + jfcc->record_db_addr_l = 0; + jfcc->record_db_addr_h = 0; + jfcc->remote_token_value = 0; + + udma_dfx_ctx_print(udma_dev, "JFC", key->key, sizeof(*jfcc) / sizeof(uint32_t), + (uint32_t *)jfcc); + udma_free_cmd_mailbox(udma_dev, mailbox); + + return 0; +} + static int udma_query_res_jfs(struct udma_dev *udma_dev, struct ubcore_res_key *key, struct ubcore_res_val *val) @@ -616,12 +720,19 @@ typedef int (*udma_query_res_handler)(struct udma_dev *udma_dev, static udma_query_res_handler g_udma_query_res_handlers[] = { [0] = NULL, + [UBCORE_RES_KEY_VTP] = NULL, + [UBCORE_RES_KEY_TP] = NULL, + [UBCORE_RES_KEY_TPG] = NULL, + [UBCORE_RES_KEY_UTP] = NULL, [UBCORE_RES_KEY_JFS] = udma_query_res_jfs, [UBCORE_RES_KEY_JFR] = udma_query_res_jfr, [UBCORE_RES_KEY_JETTY] = udma_query_res_jetty, + [UBCORE_RES_KEY_JETTY_GROUP] = udma_query_res_jetty_grp, + [UBCORE_RES_KEY_JFC] = udma_query_res_jfc, [UBCORE_RES_KEY_RC] = udma_query_res_rc, [UBCORE_RES_KEY_SEG] = udma_query_res_seg, [UBCORE_RES_KEY_DEV_TA] = udma_query_res_dev_ta, + [UBCORE_RES_KEY_DEV_TP] = NULL, }; int udma_query_res(struct ubcore_device *dev, struct ubcore_res_key *key, diff --git a/drivers/ub/urma/hw/udma/udma_jetty.h b/drivers/ub/urma/hw/udma/udma_jetty.h index 5ee8f8f4403b..e1c578783a48 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.h +++ b/drivers/ub/urma/hw/udma/udma_jetty.h @@ -160,6 +160,13 @@ struct udma_jetty_ctx { uint32_t taack_nack_bm[32]; }; +struct udma_jetty_grp_ctx { + uint32_t start_jetty_id : 16; + uint32_t rsv : 11; + uint32_t jetty_number : 5; + uint32_t valid; +}; + static inline struct udma_jetty *to_udma_jetty(struct ubcore_jetty *jetty) { return container_of(jetty, struct udma_jetty, ubcore_jetty); diff --git a/drivers/ub/urma/hw/udma/udma_jfc.h b/drivers/ub/urma/hw/udma/udma_jfc.h index e225efdece4c..8cb7271739d7 100644 --- a/drivers/ub/urma/hw/udma/udma_jfc.h +++ b/drivers/ub/urma/hw/udma/udma_jfc.h @@ -7,6 +7,8 @@ #include "udma_dev.h" #include "udma_ctx.h" +#define UDMA_JFC_DEPTH_SHIFT_BASE 6 + struct udma_jfc { struct ubcore_jfc base; uint32_t jfcn; @@ -27,6 +29,75 @@ struct udma_jfc { uint32_t cq_shift; }; +struct udma_jfc_ctx { + /* DW0 */ + uint32_t state : 2; + uint32_t arm_st : 2; + uint32_t shift : 4; + uint32_t cqe_size : 1; + uint32_t record_db_en : 1; + uint32_t jfc_type : 1; + uint32_t inline_en : 1; + uint32_t cqe_va_l : 20; + /* DW1 */ + uint32_t cqe_va_h; + /* DW2 */ + uint32_t cqe_token_id : 20; + uint32_t cq_cnt_mode : 1; + uint32_t rsv0 : 3; + uint32_t ceqn : 8; + /* DW3 */ + uint32_t cqe_token_value : 24; + uint32_t rsv1 : 8; + /* DW4 */ + uint32_t pi : 22; + uint32_t cqe_coalesce_cnt : 10; + /* DW5 */ + uint32_t ci : 22; + uint32_t cqe_coalesce_period : 3; + uint32_t rsv2 : 7; + /* DW6 */ + uint32_t record_db_addr_l; + /* DW7 */ + uint32_t record_db_addr_h : 26; + uint32_t rsv3 : 6; + /* DW8 */ + uint32_t push_usi_en : 1; + uint32_t push_cqe_en : 1; + uint32_t token_en : 1; + uint32_t rsv4 : 9; + uint32_t tpn : 20; + /* DW9 ~ DW12 */ + uint32_t rmt_eid[4]; + /* DW13 */ + uint32_t seid_idx : 10; + uint32_t rmt_token_id : 20; + uint32_t rsv5 : 2; + /* DW14 */ + uint32_t remote_token_value; + /* DW15 */ + uint32_t int_vector : 16; + uint32_t stars_en : 1; + uint32_t rsv6 : 15; + /* DW16 */ + uint32_t poll : 1; + uint32_t cqe_report_timer : 24; + uint32_t se : 1; + uint32_t arm_sn : 2; + uint32_t rsv7 : 4; + /* DW17 */ + uint32_t se_cqe_idx : 24; + uint32_t rsv8 : 8; + /* DW18 */ + uint32_t wr_cqe_idx : 22; + uint32_t rsv9 : 10; + /* DW19 */ + uint32_t cqe_cnt : 24; + uint32_t rsv10 : 8; + /* DW20 ~ DW31 */ + uint32_t rsv11[12]; +}; + static inline struct udma_jfc *to_udma_jfc(struct ubcore_jfc *jfc) { return container_of(jfc, struct udma_jfc, base); -- Gitee From 20e8738493c8aeb21f8de8ed66422e492c950e9b Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 10:16:51 +0800 Subject: [PATCH 068/103] ub: udma: Support create jfs. commit 30b22bb34e1059055f57a01f01520afe1b104545 openEuler This patch adds the ability to create jfs, During the creation process, driver will create jfs context and send it to the hardware. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/Makefile | 2 +- drivers/ub/urma/hw/udma/udma_common.h | 16 ++ drivers/ub/urma/hw/udma/udma_dev.h | 4 + drivers/ub/urma/hw/udma/udma_jetty.c | 263 +++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jetty.h | 40 +++ drivers/ub/urma/hw/udma/udma_jfs.c | 357 ++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jfs.h | 26 ++ drivers/ub/urma/hw/udma/udma_main.c | 2 + 8 files changed, 709 insertions(+), 1 deletion(-) create mode 100644 drivers/ub/urma/hw/udma/udma_jetty.c create mode 100644 drivers/ub/urma/hw/udma/udma_jfs.c diff --git a/drivers/ub/urma/hw/udma/Makefile b/drivers/ub/urma/hw/udma/Makefile index a087da421b2e..7b1c82ab51dd 100644 --- a/drivers/ub/urma/hw/udma/Makefile +++ b/drivers/ub/urma/hw/udma/Makefile @@ -3,6 +3,6 @@ udma-$(CONFIG_UB_UDMA) := udma_main.o udma_cmd.o udma_common.o udma_ctx.o udma_db.o \ udma_rct.o udma_tid.o udma_debugfs.o udma_eq.o udma_jfc.o \ udma_ctrlq_tp.o udma_eid.o udma_ctl.o udma_segment.o \ - udma_dfx.o + udma_dfx.o udma_jfs.o udma_jetty.o obj-m := udma.o diff --git a/drivers/ub/urma/hw/udma/udma_common.h b/drivers/ub/urma/hw/udma/udma_common.h index aba7b4afddb3..b1b129ee4449 100644 --- a/drivers/ub/urma/hw/udma/udma_common.h +++ b/drivers/ub/urma/hw/udma/udma_common.h @@ -6,6 +6,7 @@ #include #include +#include "udma_ctx.h" #include "udma_dev.h" struct udma_jetty_grp { @@ -81,6 +82,21 @@ void udma_k_free_buf(struct udma_dev *udma_dev, size_t memory_size, struct udma_ void *udma_alloc_iova(struct udma_dev *udma_dev, size_t memory_size, dma_addr_t *addr); void udma_free_iova(struct udma_dev *udma_dev, size_t memory_size, void *kva_or_slot, dma_addr_t addr); + +static inline void udma_alloc_kernel_db(struct udma_dev *dev, + struct udma_jetty_queue *queue) +{ + queue->dwqe_addr = dev->k_db_base + JETTY_DSQE_OFFSET + + UDMA_HW_PAGE_SIZE * queue->id; + queue->db_addr = queue->dwqe_addr + UDMA_DOORBELL_OFFSET; +} + +static inline uint8_t to_ta_timeout(uint32_t err_timeout) +{ +#define TA_TIMEOUT_DIVISOR 8 + return err_timeout / TA_TIMEOUT_DIVISOR; +} + static inline uint64_t udma_cal_npages(uint64_t va, uint64_t len) { return (ALIGN(va + len, PAGE_SIZE) - ALIGN_DOWN(va, PAGE_SIZE)) / PAGE_SIZE; diff --git a/drivers/ub/urma/hw/udma/udma_dev.h b/drivers/ub/urma/hw/udma/udma_dev.h index 67e8847d66a6..469e55e93d7a 100644 --- a/drivers/ub/urma/hw/udma/udma_dev.h +++ b/drivers/ub/urma/hw/udma/udma_dev.h @@ -17,8 +17,12 @@ extern bool dump_aux_info; #define UBCORE_MAX_DEV_NAME 64 +#define WQE_BB_SIZE_SHIFT 6 + #define MAX_JETTY_IN_JETTY_GRP 32 +#define UDMA_USER_DATA_H_OFFSET 32U + #define MAX_WQEBB_IN_SQE 4 #define JETTY_DSQE_OFFSET 0x1000 diff --git a/drivers/ub/urma/hw/udma/udma_jetty.c b/drivers/ub/urma/hw/udma/udma_jetty.c new file mode 100644 index 000000000000..a92fbc7d5d11 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_jetty.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt +#define pr_fmt(fmt) "UDMA: " fmt + +#include +#include +#include +#include +#include "udma_dev.h" +#include +#include "udma_cmd.h" +#include "udma_jfr.h" +#include "udma_jfs.h" +#include "udma_jfc.h" +#include "udma_jetty.h" + +bool well_known_jetty_pgsz_check = true; + +static int udma_specify_rsvd_jetty_id(struct udma_dev *udma_dev, uint32_t cfg_id) +{ + struct udma_ida *ida_table = &udma_dev->rsvd_jetty_ida_table; + int id; + + id = ida_alloc_range(&ida_table->ida, cfg_id, cfg_id, GFP_KERNEL); + if (id < 0) { + dev_err(udma_dev->dev, "user specify id %u has been used, ret = %d.\n", cfg_id, id); + return id; + } + + return 0; +} + +static int udma_user_specify_jetty_id(struct udma_dev *udma_dev, uint32_t cfg_id) +{ + if (cfg_id < udma_dev->caps.jetty.start_idx) + return udma_specify_rsvd_jetty_id(udma_dev, cfg_id); + + return udma_specify_adv_id(udma_dev, &udma_dev->jetty_table.bitmap_table, + cfg_id); +} + +int udma_alloc_jetty_id(struct udma_dev *udma_dev, uint32_t *idx, + struct udma_res *jetty_res) +{ + struct udma_group_bitmap *bitmap = &udma_dev->jetty_table.bitmap_table; + struct ida *ida = &udma_dev->rsvd_jetty_ida_table.ida; + uint32_t min = jetty_res->start_idx; + uint32_t next = jetty_res->next_idx; + uint32_t max; + int ret; + + if (jetty_res->max_cnt == 0) { + dev_err(udma_dev->dev, "ida alloc failed max_cnt is 0.\n"); + return -EINVAL; + } + + max = jetty_res->start_idx + jetty_res->max_cnt - 1; + + if (jetty_res != &udma_dev->caps.jetty) { + ret = ida_alloc_range(ida, next, max, GFP_KERNEL); + if (ret < 0) { + ret = ida_alloc_range(ida, min, max, GFP_KERNEL); + if (ret < 0) { + dev_err(udma_dev->dev, + "ida alloc failed %d.\n", ret); + return ret; + } + } + + *idx = (uint32_t)ret; + } else { + ret = udma_adv_id_alloc(udma_dev, bitmap, idx, false, next); + if (ret) { + ret = udma_adv_id_alloc(udma_dev, bitmap, idx, false, min); + if (ret) { + dev_err(udma_dev->dev, + "bitmap alloc failed %d.\n", ret); + return ret; + } + } + } + + jetty_res->next_idx = (*idx + 1) > max ? min : (*idx + 1); + + return 0; +} + +static int udma_alloc_normal_jetty_id(struct udma_dev *udma_dev, uint32_t *idx) +{ + int ret; + + ret = udma_alloc_jetty_id(udma_dev, idx, &udma_dev->caps.jetty); + if (ret == 0) + return 0; + + ret = udma_alloc_jetty_id(udma_dev, idx, &udma_dev->caps.user_ctrl_normal_jetty); + if (ret == 0) + return 0; + + return udma_alloc_jetty_id(udma_dev, idx, &udma_dev->caps.public_jetty); +} + +#define CFGID_CHECK(a, b) ((a) >= (b).start_idx && (a) < (b).start_idx + (b).max_cnt) + +static int udma_verify_jetty_type_dwqe(struct udma_dev *udma_dev, + uint32_t cfg_id) +{ + if (!CFGID_CHECK(cfg_id, udma_dev->caps.stars_jetty)) { + dev_err(udma_dev->dev, + "user id %u error, cache lock st idx %u cnt %u.\n", + cfg_id, udma_dev->caps.stars_jetty.start_idx, + udma_dev->caps.stars_jetty.max_cnt); + return -EINVAL; + } + + return 0; +} + +static int udma_verify_jetty_type_ccu(struct udma_dev *udma_dev, + uint32_t cfg_id) +{ + if (!CFGID_CHECK(cfg_id, udma_dev->caps.ccu_jetty)) { + dev_err(udma_dev->dev, + "user id %u error, ccu st idx %u cnt %u.\n", + cfg_id, udma_dev->caps.ccu_jetty.start_idx, + udma_dev->caps.ccu_jetty.max_cnt); + return -EINVAL; + } + + return 0; +} + +static int udma_verify_jetty_type_normal(struct udma_dev *udma_dev, + uint32_t cfg_id) +{ + if (!CFGID_CHECK(cfg_id, udma_dev->caps.user_ctrl_normal_jetty)) { + dev_err(udma_dev->dev, + "user id %u error, user ctrl normal st idx %u cnt %u.\n", + cfg_id, + udma_dev->caps.user_ctrl_normal_jetty.start_idx, + udma_dev->caps.user_ctrl_normal_jetty.max_cnt); + return -EINVAL; + } + + return 0; +} + +static int udma_verify_jetty_type_urma_normal(struct udma_dev *udma_dev, + uint32_t cfg_id) +{ + if (!(CFGID_CHECK(cfg_id, udma_dev->caps.public_jetty) || + CFGID_CHECK(cfg_id, udma_dev->caps.hdc_jetty) || + CFGID_CHECK(cfg_id, udma_dev->caps.jetty))) { + dev_err(udma_dev->dev, + "user id %u error, ccu st idx %u cnt %u, stars st idx %u, normal st idx %u cnt %u.\n", + cfg_id, udma_dev->caps.ccu_jetty.start_idx, + udma_dev->caps.ccu_jetty.max_cnt, + udma_dev->caps.stars_jetty.start_idx, + udma_dev->caps.jetty.start_idx, + udma_dev->caps.jetty.max_cnt); + return -EINVAL; + } + + if (well_known_jetty_pgsz_check && PAGE_SIZE != UDMA_HW_PAGE_SIZE) { + dev_err(udma_dev->dev, "Does not support specifying Jetty ID on non-4KB page systems.\n"); + return -EINVAL; + } + + return 0; +} + +static int udma_verify_jetty_type(struct udma_dev *udma_dev, + enum udma_jetty_type jetty_type, uint32_t cfg_id) +{ + int (*udma_cfg_id_check[UDMA_JETTY_TYPE_MAX])(struct udma_dev *udma_dev, + uint32_t cfg_id) = { + udma_verify_jetty_type_dwqe, + udma_verify_jetty_type_ccu, + udma_verify_jetty_type_normal, + udma_verify_jetty_type_urma_normal + }; + + if (jetty_type < UDMA_JETTY_TYPE_MAX) { + if (!cfg_id) + return 0; + + return udma_cfg_id_check[jetty_type](udma_dev, cfg_id); + } + + dev_err(udma_dev->dev, "invalid jetty type 0x%x.\n", jetty_type); + return -EINVAL; +} + +static int udma_alloc_jetty_id_own(struct udma_dev *udma_dev, uint32_t *id, + enum udma_jetty_type jetty_type) +{ + int ret; + + switch (jetty_type) { + case UDMA_CACHE_LOCK_DWQE_JETTY_TYPE: + ret = udma_alloc_jetty_id(udma_dev, id, + &udma_dev->caps.stars_jetty); + break; + case UDMA_NORMAL_JETTY_TYPE: + ret = udma_alloc_jetty_id(udma_dev, id, + &udma_dev->caps.user_ctrl_normal_jetty); + break; + case UDMA_CCU_JETTY_TYPE: + ret = udma_alloc_jetty_id(udma_dev, id, &udma_dev->caps.ccu_jetty); + break; + default: + ret = udma_alloc_normal_jetty_id(udma_dev, id); + break; + } + + if (ret) + dev_err(udma_dev->dev, + "udma alloc jetty id own failed, type = %d, ret = %d.\n", + jetty_type, ret); + + return ret; +} + +int alloc_jetty_id(struct udma_dev *udma_dev, struct udma_jetty_queue *sq, + uint32_t cfg_id, struct ubcore_jetty_group *jetty_grp) +{ + int ret; + + if (udma_verify_jetty_type(udma_dev, sq->jetty_type, cfg_id)) + return -EINVAL; + + if (cfg_id > 0 && !jetty_grp) { + ret = udma_user_specify_jetty_id(udma_dev, cfg_id); + if (ret) + return ret; + + sq->id = cfg_id; + } else { + ret = udma_alloc_jetty_id_own(udma_dev, &sq->id, sq->jetty_type); + } + + return ret; +} + +void udma_set_query_flush_time(struct udma_jetty_queue *sq, uint8_t err_timeout) +{ +#define UDMA_TA_TIMEOUT_MAX_INDEX 3 + uint32_t time[] = { + UDMA_TA_TIMEOUT_128MS, + UDMA_TA_TIMEOUT_1000MS, + UDMA_TA_TIMEOUT_8000MS, + UDMA_TA_TIMEOUT_64000MS, + }; + uint8_t index; + + index = to_ta_timeout(err_timeout); + if (index > UDMA_TA_TIMEOUT_MAX_INDEX) + index = UDMA_TA_TIMEOUT_MAX_INDEX; + + sq->ta_timeout = time[index]; +} diff --git a/drivers/ub/urma/hw/udma/udma_jetty.h b/drivers/ub/urma/hw/udma/udma_jetty.h index e1c578783a48..fb70231278b7 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.h +++ b/drivers/ub/urma/hw/udma/udma_jetty.h @@ -6,7 +6,24 @@ #include "udma_common.h" +#define SQE_TOKEN_ID_L_MASK GENMASK(11, 0) +#define SQE_TOKEN_ID_H_OFFSET 12U +#define SQE_TOKEN_ID_H_MASK GENMASK(7, 0) +#define SQE_VA_L_OFFSET 12U +#define SQE_VA_L_VALID_BIT GENMASK(19, 0) +#define SQE_VA_H_OFFSET 32U +#define SQE_VA_H_VALID_BIT GENMASK(31, 0) #define JETTY_CTX_JFRN_H_OFFSET 12 +#define AVAIL_SGMT_OST_INIT 512 + +#define SQE_PLD_TOKEN_ID_MASK GENMASK(19, 0) + +#define UDMA_TA_TIMEOUT_128MS 128 +#define UDMA_TA_TIMEOUT_1000MS 1000 +#define UDMA_TA_TIMEOUT_8000MS 8000 +#define UDMA_TA_TIMEOUT_64000MS 64000 + +#define UDMA_MAX_PRIORITY 16 enum jetty_state { JETTY_RESET, @@ -27,6 +44,11 @@ struct udma_jetty { bool ue_rx_closed; }; +enum jfsc_mode { + JFS, + JETTY, +}; + enum jetty_type { JETTY_RAW_OR_NIC, JETTY_UM, @@ -167,6 +189,20 @@ struct udma_jetty_grp_ctx { uint32_t valid; }; +static inline uint32_t to_udma_type(uint32_t trans_mode) +{ + switch (trans_mode) { + case UBCORE_TP_RM: + return JETTY_RM; + case UBCORE_TP_RC: + return JETTY_RC; + case UBCORE_TP_UM: + return JETTY_UM; + default: + return JETTY_TYPE_RESERVED; + } +} + static inline struct udma_jetty *to_udma_jetty(struct ubcore_jetty *jetty) { return container_of(jetty, struct udma_jetty, ubcore_jetty); @@ -182,4 +218,8 @@ static inline struct udma_jetty *to_udma_jetty_from_queue(struct udma_jetty_queu return container_of(queue, struct udma_jetty, sq); } +int alloc_jetty_id(struct udma_dev *udma_dev, struct udma_jetty_queue *sq, + uint32_t cfg_id, struct ubcore_jetty_group *jetty_grp); +void udma_set_query_flush_time(struct udma_jetty_queue *sq, uint8_t err_timeout); + #endif /* __UDMA_JETTY_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_jfs.c b/drivers/ub/urma/hw/udma/udma_jfs.c new file mode 100644 index 000000000000..002636a03c21 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_jfs.c @@ -0,0 +1,357 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt +#define pr_fmt(fmt) "UDMA: " fmt + +#include +#include +#include +#include +#include +#include +#include "udma_common.h" +#include "udma_dev.h" +#include +#include "udma_cmd.h" +#include "udma_jetty.h" +#include "udma_segment.h" +#include "udma_jfs.h" + +int udma_alloc_u_sq_buf(struct udma_dev *dev, struct udma_jetty_queue *sq, + struct udma_create_jetty_ucmd *ucmd) +{ + int ret; + + if (ucmd->sqe_bb_cnt == 0 || ucmd->buf_len == 0) { + dev_err(dev->dev, "invalid param, sqe_bb_cnt=%u, buf_len=%u.\n", + ucmd->sqe_bb_cnt, ucmd->buf_len); + return -EINVAL; + } + + sq->sqe_bb_cnt = ucmd->sqe_bb_cnt; + sq->buf.entry_cnt = ucmd->buf_len >> WQE_BB_SIZE_SHIFT; + if (sq->non_pin) { + sq->buf.addr = ucmd->buf_addr; + } else { + ret = pin_queue_addr(dev, ucmd->buf_addr, ucmd->buf_len, &sq->buf); + if (ret) { + dev_err(dev->dev, + "failed to pin jetty/jfs queue addr, ret = %d.\n", + ret); + return ret; + } + } + + return 0; +} + +int udma_alloc_k_sq_buf(struct udma_dev *dev, struct udma_jetty_queue *sq, + struct ubcore_jfs_cfg *jfs_cfg) +{ + uint32_t wqe_bb_depth; + uint32_t sqe_bb_cnt; + uint32_t size; + int ret; + + if (!jfs_cfg->flag.bs.lock_free) + spin_lock_init(&sq->lock); + + sq->max_inline_size = jfs_cfg->max_inline_data; + sq->max_sge_num = jfs_cfg->max_sge; + sq->tid = dev->tid; + sq->lock_free = jfs_cfg->flag.bs.lock_free; + + sqe_bb_cnt = sq_cal_wqebb_num(SQE_WRITE_NOTIFY_CTL_LEN, jfs_cfg->max_sge); + sq->sqe_bb_cnt = sqe_bb_cnt > (uint32_t)MAX_WQEBB_NUM ? (uint32_t)MAX_WQEBB_NUM : + sqe_bb_cnt; + + wqe_bb_depth = roundup_pow_of_two(sq->sqe_bb_cnt * jfs_cfg->depth); + sq->buf.entry_size = UDMA_JFS_WQEBB_SIZE; + size = ALIGN(wqe_bb_depth * sq->buf.entry_size, UDMA_HW_PAGE_SIZE); + sq->buf.entry_cnt = size >> WQE_BB_SIZE_SHIFT; + + ret = udma_k_alloc_buf(dev, size, &sq->buf); + if (ret) { + dev_err(dev->dev, + "failed to alloc jetty (%u) sq buf when size = %u.\n", sq->id, size); + return ret; + } + + sq->wrid = kcalloc(1, sq->buf.entry_cnt * sizeof(uint64_t), GFP_KERNEL); + if (!sq->wrid) { + udma_k_free_buf(dev, size, &sq->buf); + dev_err(dev->dev, + "failed to alloc wrid for jfs id = %u when entry cnt = %u.\n", + sq->id, sq->buf.entry_cnt); + return -ENOMEM; + } + + udma_alloc_kernel_db(dev, sq); + sq->kva_curr = sq->buf.kva; + + return 0; +} + +void udma_free_sq_buf(struct udma_dev *dev, struct udma_jetty_queue *sq) +{ + uint32_t size; + + if (sq->buf.kva) { + size = sq->buf.entry_cnt * sq->buf.entry_size; + udma_k_free_buf(dev, size, &sq->buf); + kfree(sq->wrid); + return; + } + if (sq->non_pin) + return; + + unpin_queue_addr(sq->buf.umem); +} + +void udma_init_jfsc(struct udma_dev *dev, struct ubcore_jfs_cfg *cfg, + struct udma_jfs *jfs, void *mb_buf) +{ + struct udma_jetty_ctx *ctx = (struct udma_jetty_ctx *)mb_buf; + uint8_t i; + + ctx->state = JETTY_READY; + ctx->jfs_mode = JFS; + ctx->type = to_udma_type(cfg->trans_mode); + ctx->sl = dev->udma_sl[UDMA_DEFAULT_SL_NUM]; + if (ctx->type == JETTY_RM || ctx->type == JETTY_RC) { + for (i = 0; i < dev->udma_total_sl_num; i++) + if (cfg->priority == dev->udma_sl[i]) + ctx->sl = cfg->priority; + } else if (ctx->type == JETTY_UM) { + ctx->sl = dev->unic_sl[UDMA_DEFAULT_SL_NUM]; + for (i = 0; i < dev->unic_sl_num; i++) + if (cfg->priority == dev->unic_sl[i]) + ctx->sl = cfg->priority; + } + ctx->sqe_base_addr_l = (jfs->sq.buf.addr >> SQE_VA_L_OFFSET) & + (uint32_t)SQE_VA_L_VALID_BIT; + ctx->sqe_base_addr_h = (jfs->sq.buf.addr >> SQE_VA_H_OFFSET) & + (uint32_t)SQE_VA_H_VALID_BIT; + ctx->sqe_token_id_l = jfs->sq.tid & (uint32_t)SQE_TOKEN_ID_L_MASK; + ctx->sqe_token_id_h = (jfs->sq.tid >> SQE_TOKEN_ID_H_OFFSET) & + (uint32_t)SQE_TOKEN_ID_H_MASK; + ctx->sqe_bb_shift = ilog2(roundup_pow_of_two(jfs->sq.buf.entry_cnt)); + ctx->tx_jfcn = cfg->jfc->id; + ctx->ta_timeout = to_ta_timeout(cfg->err_timeout); + + if (!!(dev->caps.feature & UDMA_CAP_FEATURE_RNR_RETRY)) + ctx->rnr_retry_num = cfg->rnr_retry; + + ctx->user_data_l = jfs->jfs_addr; + ctx->user_data_h = jfs->jfs_addr >> UDMA_USER_DATA_H_OFFSET; + ctx->seid_idx = cfg->eid_index; + ctx->err_mode = cfg->flag.bs.error_suspend; + ctx->cmp_odr = cfg->flag.bs.outorder_comp; + ctx->avail_sgmt_ost = AVAIL_SGMT_OST_INIT; + ctx->pi_type = jfs->pi_type; + ctx->sqe_pld_tokenid = jfs->sq.tid & (uint32_t)SQE_PLD_TOKEN_ID_MASK; + ctx->next_send_ssn = get_random_u16(); + ctx->next_rcv_ssn = ctx->next_send_ssn; +} + +void udma_dfx_store_jfs_id(struct udma_dev *udma_dev, struct udma_jfs *udma_jfs) +{ + struct udma_dfx_jfs *jfs; + int ret; + + jfs = (struct udma_dfx_jfs *)xa_load(&udma_dev->dfx_info->jfs.table, + udma_jfs->sq.id); + if (jfs) { + dev_warn(udma_dev->dev, "jfs_id(%u) already exists in DFX.\n", + udma_jfs->sq.id); + return; + } + + jfs = kzalloc(sizeof(*jfs), GFP_KERNEL); + if (!jfs) + return; + + jfs->id = udma_jfs->sq.id; + jfs->depth = udma_jfs->sq.buf.entry_cnt / udma_jfs->sq.sqe_bb_cnt; + + write_lock(&udma_dev->dfx_info->jfs.rwlock); + ret = xa_err(xa_store(&udma_dev->dfx_info->jfs.table, udma_jfs->sq.id, + jfs, GFP_KERNEL)); + if (ret) { + write_unlock(&udma_dev->dfx_info->jfs.rwlock); + dev_err(udma_dev->dev, "store jfs_id(%u) to table failed in DFX.\n", + udma_jfs->sq.id); + kfree(jfs); + return; + } + + ++udma_dev->dfx_info->jfs.cnt; + write_unlock(&udma_dev->dfx_info->jfs.rwlock); +} + +static int udma_create_hw_jfs_ctx(struct udma_dev *dev, struct udma_jfs *jfs, + struct ubcore_jfs_cfg *cfg) +{ + struct ubase_mbx_attr attr = {}; + struct udma_jetty_ctx ctx = {}; + int ret; + + if (cfg->priority >= UDMA_MAX_PRIORITY) { + dev_err(dev->dev, "kernel mode jfs priority is out of range, priority is %u.\n", + cfg->priority); + return -EINVAL; + } + + udma_init_jfsc(dev, cfg, jfs, &ctx); + attr.tag = jfs->sq.id; + attr.op = UDMA_CMD_CREATE_JFS_CONTEXT; + ret = post_mailbox_update_ctx(dev, &ctx, sizeof(ctx), &attr); + if (ret) { + dev_err(dev->dev, "failed to upgrade JFSC, ret = %d.\n", ret); + return ret; + } + + return 0; +} + +static int udma_get_user_jfs_cmd(struct udma_dev *dev, struct udma_jfs *jfs, + struct ubcore_udata *udata, + struct udma_create_jetty_ucmd *ucmd) +{ + struct udma_context *uctx; + unsigned long byte; + + if (udata) { + if (!udata->udrv_data) { + dev_err(dev->dev, "udrv_data is null.\n"); + return -EINVAL; + } + + if (!udata->udrv_data->in_addr || udata->udrv_data->in_len < sizeof(*ucmd)) { + dev_err(dev->dev, "jfs in_len %u or addr is invalid.\n", + udata->udrv_data->in_len); + return -EINVAL; + } + + byte = copy_from_user(ucmd, (void *)(uintptr_t)udata->udrv_data->in_addr, + sizeof(*ucmd)); + if (byte) { + dev_err(dev->dev, + "failed to copy jfs udata, ret = %lu.\n", byte); + return -EFAULT; + } + + uctx = to_udma_context(udata->uctx); + jfs->sq.tid = uctx->tid; + jfs->jfs_addr = ucmd->jetty_addr; + jfs->pi_type = ucmd->pi_type; + jfs->sq.non_pin = ucmd->non_pin; + jfs->sq.jetty_type = (enum udma_jetty_type)ucmd->jetty_type; + jfs->sq.id = ucmd->jfs_id; + } else { + jfs->jfs_addr = (uintptr_t)&jfs->sq; + jfs->sq.jetty_type = (enum udma_jetty_type)UDMA_URMA_NORMAL_JETTY_TYPE; + } + + return 0; +} + +static int udma_alloc_jfs_sq(struct udma_dev *dev, struct ubcore_jfs_cfg *cfg, + struct udma_jfs *jfs, struct ubcore_udata *udata) +{ + struct udma_create_jetty_ucmd ucmd = {}; + int ret; + + ret = udma_get_user_jfs_cmd(dev, jfs, udata, &ucmd); + if (ret) + goto err_get_user_cmd; + + ret = alloc_jetty_id(dev, &jfs->sq, jfs->sq.id, NULL); + if (ret) { + dev_err(dev->dev, "failed to alloc_id.\n"); + goto err_alloc_id; + } + jfs->ubcore_jfs.jfs_id.id = jfs->sq.id; + jfs->ubcore_jfs.jfs_cfg = *cfg; + udma_set_query_flush_time(&jfs->sq, cfg->err_timeout); + + ret = xa_err(xa_store(&dev->jetty_table.xa, jfs->sq.id, &jfs->sq, GFP_KERNEL)); + if (ret) { + dev_err(dev->dev, "failed to store_sq(%u), ret=%d.", jfs->sq.id, ret); + goto err_store_sq; + } + + ret = udata ? udma_alloc_u_sq_buf(dev, &jfs->sq, &ucmd) : + udma_alloc_k_sq_buf(dev, &jfs->sq, cfg); + if (ret) + goto err_alloc_sq_buf; + + jfs->sq.trans_mode = cfg->trans_mode; + + return ret; + +err_alloc_sq_buf: + xa_erase(&dev->jetty_table.xa, jfs->sq.id); +err_store_sq: + if (jfs->sq.id < dev->caps.jetty.start_idx) + udma_id_free(&dev->rsvd_jetty_ida_table, jfs->sq.id); + else + udma_adv_id_free(&dev->jetty_table.bitmap_table, + jfs->sq.id, false); +err_alloc_id: +err_get_user_cmd: + return ret; +} + +struct ubcore_jfs *udma_create_jfs(struct ubcore_device *ub_dev, + struct ubcore_jfs_cfg *cfg, + struct ubcore_udata *udata) +{ + struct udma_dev *dev = to_udma_dev(ub_dev); + struct udma_jfs *jfs; + int ret; + + if (cfg->trans_mode == UBCORE_TP_RC) { + dev_err(dev->dev, "jfs not support RC transmode.\n"); + return NULL; + } + + jfs = kcalloc(1, sizeof(*jfs), GFP_KERNEL); + if (!jfs) + return NULL; + + ret = udma_alloc_jfs_sq(dev, cfg, jfs, udata); + if (ret) { + dev_err(dev->dev, "failed to alloc_jfs_sq, ret = %d.\n", ret); + goto err_alloc_sq; + } + + ret = udma_create_hw_jfs_ctx(dev, jfs, cfg); + if (ret) { + dev_err(dev->dev, + "post mailbox create jfs ctx failed, ret = %d.\n", ret); + goto err_create_hw_jfs; + } + + jfs->mode = UDMA_NORMAL_JFS_TYPE; + jfs->sq.state = UBCORE_JETTY_STATE_READY; + refcount_set(&jfs->ae_refcount, 1); + init_completion(&jfs->ae_comp); + if (dfx_switch) + udma_dfx_store_jfs_id(dev, jfs); + + return &jfs->ubcore_jfs; + +err_create_hw_jfs: + udma_free_sq_buf(dev, &jfs->sq); + xa_erase(&dev->jetty_table.xa, jfs->sq.id); + if (jfs->sq.id < dev->caps.jetty.start_idx) + udma_id_free(&dev->rsvd_jetty_ida_table, jfs->sq.id); + else + udma_adv_id_free(&dev->jetty_table.bitmap_table, + jfs->sq.id, false); +err_alloc_sq: + kfree(jfs); + return NULL; +} diff --git a/drivers/ub/urma/hw/udma/udma_jfs.h b/drivers/ub/urma/hw/udma/udma_jfs.h index 39a7b5d1bfc4..425c87400fec 100644 --- a/drivers/ub/urma/hw/udma/udma_jfs.h +++ b/drivers/ub/urma/hw/udma/udma_jfs.h @@ -6,6 +6,17 @@ #include "udma_common.h" +#define MAX_WQEBB_NUM 4 +#define UDMA_JFS_WQEBB_SIZE 64 +#define UDMA_JFS_SGE_SIZE 16 + +#define SQE_WRITE_NOTIFY_CTL_LEN 80 + +enum udma_jfs_type { + UDMA_NORMAL_JFS_TYPE, + UDMA_KERNEL_STARS_JFS_TYPE, +}; + struct udma_jfs { struct ubcore_jfs ubcore_jfs; struct udma_jetty_queue sq; @@ -27,4 +38,19 @@ static inline struct udma_jfs *to_udma_jfs_from_queue(struct udma_jetty_queue *q return container_of(queue, struct udma_jfs, sq); } +static inline uint32_t sq_cal_wqebb_num(uint32_t sqe_ctl_len, uint32_t sge_num) +{ + return (sqe_ctl_len + (sge_num - 1) * UDMA_JFS_SGE_SIZE) / + UDMA_JFS_WQEBB_SIZE + 1; +} + +struct ubcore_jfs *udma_create_jfs(struct ubcore_device *ub_dev, + struct ubcore_jfs_cfg *cfg, + struct ubcore_udata *udata); +int udma_alloc_u_sq_buf(struct udma_dev *dev, struct udma_jetty_queue *sq, + struct udma_create_jetty_ucmd *ucmd); +int udma_alloc_k_sq_buf(struct udma_dev *dev, struct udma_jetty_queue *sq, + struct ubcore_jfs_cfg *jfs_cfg); +void udma_free_sq_buf(struct udma_dev *dev, struct udma_jetty_queue *sq); + #endif /* __UDMA_JFS_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index dcf0ae79d583..bf1ffe10367f 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -19,6 +19,7 @@ #include "udma_dev.h" #include "udma_eq.h" #include "udma_segment.h" +#include "udma_jfs.h" #include "udma_cmd.h" #include "udma_ctx.h" #include "udma_rct.h" @@ -173,6 +174,7 @@ static struct ubcore_ops g_dev_ops = { .unregister_seg = udma_unregister_seg, .import_seg = udma_import_seg, .unimport_seg = udma_unimport_seg, + .create_jfs = udma_create_jfs, .query_jfs = udma_query_jfs, .query_jfr = udma_query_jfr, .query_jetty = udma_query_jetty, -- Gitee From 8e04bdcb04811aa854cf64c1fc2d46a16c55859e Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 10:18:46 +0800 Subject: [PATCH 069/103] ub: udma: Support destroy jfs. commit 717d2a2e8d2b4539b400f0f4f04833cab2fdc4e3 openEuler This patch adds the ability to destroy jfs, During the destruction process, driver will destroy jfs context and send it to the hardware. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_dev.h | 2 + drivers/ub/urma/hw/udma/udma_jetty.c | 200 +++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jetty.h | 4 + drivers/ub/urma/hw/udma/udma_jfs.c | 54 ++++++++ drivers/ub/urma/hw/udma/udma_jfs.h | 1 + drivers/ub/urma/hw/udma/udma_main.c | 1 + 6 files changed, 262 insertions(+) diff --git a/drivers/ub/urma/hw/udma/udma_dev.h b/drivers/ub/urma/hw/udma/udma_dev.h index 469e55e93d7a..bc6ad5c509fd 100644 --- a/drivers/ub/urma/hw/udma/udma_dev.h +++ b/drivers/ub/urma/hw/udma/udma_dev.h @@ -37,6 +37,8 @@ extern bool dump_aux_info; #define UDMA_MAX_SL_NUM 16 #define UDMA_DEFAULT_SL_NUM 0 +#define UDMA_RCV_SEND_MAX_DIFF 512U + #define UDMA_CQE_SIZE 64 #define UDMA_MAX_GRANT_SIZE 0xFFFFFFFFF000 diff --git a/drivers/ub/urma/hw/udma/udma_jetty.c b/drivers/ub/urma/hw/udma/udma_jetty.c index a92fbc7d5d11..b012010c0e74 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.c +++ b/drivers/ub/urma/hw/udma/udma_jetty.c @@ -261,3 +261,203 @@ void udma_set_query_flush_time(struct udma_jetty_queue *sq, uint8_t err_timeout) sq->ta_timeout = time[index]; } + +int udma_destroy_hw_jetty_ctx(struct udma_dev *dev, uint32_t jetty_id) +{ + struct ubase_mbx_attr attr = {}; + int ret; + + attr.tag = jetty_id; + attr.op = UDMA_CMD_DESTROY_JFS_CONTEXT; + ret = post_mailbox_update_ctx(dev, NULL, 0, &attr); + if (ret) + dev_err(dev->dev, + "post mailbox destroy jetty ctx failed, ret = %d.\n", ret); + + return ret; +} + +int udma_set_jetty_state(struct udma_dev *dev, uint32_t jetty_id, + enum jetty_state state) +{ + struct udma_jetty_ctx *ctx, *ctx_mask; + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + int ret; + + mailbox = udma_alloc_cmd_mailbox(dev); + if (!mailbox) { + dev_err(dev->dev, "failed to alloc mailbox for jettyc.\n"); + return -EINVAL; + } + + ctx = (struct udma_jetty_ctx *)mailbox->buf; + + /* Optimize chip access performance. */ + ctx_mask = (struct udma_jetty_ctx *)((char *)ctx + UDMA_JFS_MASK_OFFSET); + memset(ctx_mask, 0xff, sizeof(struct udma_jetty_ctx)); + ctx->state = state; + ctx_mask->state = 0; + + mbox_attr.tag = jetty_id; + mbox_attr.op = UDMA_CMD_MODIFY_JFS_CONTEXT; + ret = udma_post_mbox(dev, mailbox, &mbox_attr); + if (ret) + dev_err(dev->dev, + "failed to upgrade jettyc, ret = %d.\n", ret); + udma_free_cmd_mailbox(dev, mailbox); + + return ret; +} + +static int udma_query_jetty_ctx(struct udma_dev *dev, + struct udma_jetty_ctx *jfs_ctx, + uint32_t jetty_id) +{ + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + + mbox_attr.tag = jetty_id; + mbox_attr.op = UDMA_CMD_QUERY_JFS_CONTEXT; + mailbox = udma_mailbox_query_ctx(dev, &mbox_attr); + if (!mailbox) + return -ENOMEM; + memcpy((void *)jfs_ctx, mailbox->buf, sizeof(*jfs_ctx)); + + udma_free_cmd_mailbox(dev, mailbox); + + return 0; +} + +static bool udma_wait_timeout(uint32_t *sum_times, uint32_t times, uint32_t ta_timeout) +{ + uint32_t wait_time; + + if (*sum_times > ta_timeout) + return true; + + wait_time = 1 << times; + msleep(wait_time); + *sum_times += wait_time; + + return false; +} + +static bool udma_query_jetty_fd(struct udma_dev *dev, struct udma_jetty_queue *sq) +{ + struct udma_jetty_ctx ctx = {}; + uint16_t rcv_send_diff = 0; + uint32_t sum_times = 0; + uint32_t times = 0; + + while (true) { + if (udma_query_jetty_ctx(dev, &ctx, sq->id)) + return false; + + if (ctx.flush_cqe_done) + return true; + + if (udma_wait_timeout(&sum_times, times, UDMA_TA_TIMEOUT_64000MS)) + break; + + times++; + } + + /* In the flip scenario, ctx.next_rcv_ssn - ctx.next_send_ssn value is less than 512. */ + rcv_send_diff = ctx.next_rcv_ssn - ctx.next_send_ssn; + if (ctx.flush_ssn_vld && rcv_send_diff < UDMA_RCV_SEND_MAX_DIFF) + return true; + + udma_dfx_ctx_print(dev, "Flush Failed Jetty", sq->id, sizeof(ctx) / sizeof(uint32_t), + (uint32_t *)&ctx); + + return false; +} + +int udma_modify_jetty_precondition(struct udma_dev *dev, struct udma_jetty_queue *sq) +{ + struct udma_jetty_ctx ctx = {}; + uint16_t rcv_send_diff = 0; + uint32_t sum_times = 0; + uint32_t times = 0; + int ret; + + while (true) { + ret = udma_query_jetty_ctx(dev, &ctx, sq->id); + if (ret) { + dev_err(dev->dev, "query jetty ctx failed, id = %u, ret = %d.\n", + sq->id, ret); + return ret; + } + + rcv_send_diff = ctx.next_rcv_ssn - ctx.next_send_ssn; + if (ctx.PI == ctx.CI && rcv_send_diff < UDMA_RCV_SEND_MAX_DIFF && + ctx.state == JETTY_READY) + break; + + if (rcv_send_diff < UDMA_RCV_SEND_MAX_DIFF && + ctx.state == JETTY_ERROR) + break; + + if (udma_wait_timeout(&sum_times, times, sq->ta_timeout)) { + dev_warn(dev->dev, "TA timeout, id = %u. PI = %d, CI = %d, nxt_send_ssn = %d nxt_rcv_ssn = %d state = %d.\n", + sq->id, ctx.PI, ctx.CI, ctx.next_send_ssn, + ctx.next_rcv_ssn, ctx.state); + break; + } + times++; + } + + return 0; +} + +static bool udma_destroy_jetty_precondition(struct udma_dev *dev, struct udma_jetty_queue *sq) +{ +#define UDMA_DESTROY_JETTY_DELAY_TIME 100U + + if (sq->state != UBCORE_JETTY_STATE_READY && sq->state != UBCORE_JETTY_STATE_SUSPENDED) + goto query_jetty_fd; + + if (dev->caps.feature & UDMA_CAP_FEATURE_UE_RX_CLOSE) + goto modify_to_err; + + if (udma_modify_jetty_precondition(dev, sq)) + return false; + +modify_to_err: + if (udma_set_jetty_state(dev, sq->id, JETTY_ERROR)) { + dev_err(dev->dev, "modify jetty to error failed, id: %u.\n", + sq->id); + return false; + } + + sq->state = UBCORE_JETTY_STATE_ERROR; + +query_jetty_fd: + if (!udma_query_jetty_fd(dev, sq)) + return false; + + udelay(UDMA_DESTROY_JETTY_DELAY_TIME); + + return true; +} + +int udma_modify_and_destroy_jetty(struct udma_dev *dev, + struct udma_jetty_queue *sq) +{ + int ret; + + if (!udma_destroy_jetty_precondition(dev, sq)) + return -EFAULT; + + if (sq->state != UBCORE_JETTY_STATE_RESET) { + ret = udma_destroy_hw_jetty_ctx(dev, sq->id); + if (ret) { + dev_err(dev->dev, "jetty destroyed failed, id: %u.\n", + sq->id); + return ret; + } + } + + return 0; +} diff --git a/drivers/ub/urma/hw/udma/udma_jetty.h b/drivers/ub/urma/hw/udma/udma_jetty.h index fb70231278b7..63d7073b8631 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.h +++ b/drivers/ub/urma/hw/udma/udma_jetty.h @@ -15,6 +15,7 @@ #define SQE_VA_H_VALID_BIT GENMASK(31, 0) #define JETTY_CTX_JFRN_H_OFFSET 12 #define AVAIL_SGMT_OST_INIT 512 +#define UDMA_JFS_MASK_OFFSET 128 #define SQE_PLD_TOKEN_ID_MASK GENMASK(19, 0) @@ -220,6 +221,9 @@ static inline struct udma_jetty *to_udma_jetty_from_queue(struct udma_jetty_queu int alloc_jetty_id(struct udma_dev *udma_dev, struct udma_jetty_queue *sq, uint32_t cfg_id, struct ubcore_jetty_group *jetty_grp); +int udma_destroy_hw_jetty_ctx(struct udma_dev *dev, uint32_t jetty_id); void udma_set_query_flush_time(struct udma_jetty_queue *sq, uint8_t err_timeout); +int udma_modify_and_destroy_jetty(struct udma_dev *dev, + struct udma_jetty_queue *sq); #endif /* __UDMA_JETTY_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_jfs.c b/drivers/ub/urma/hw/udma/udma_jfs.c index 002636a03c21..cb00cec5ccfd 100644 --- a/drivers/ub/urma/hw/udma/udma_jfs.c +++ b/drivers/ub/urma/hw/udma/udma_jfs.c @@ -355,3 +355,57 @@ struct ubcore_jfs *udma_create_jfs(struct ubcore_device *ub_dev, kfree(jfs); return NULL; } + +static void udma_free_jfs(struct ubcore_jfs *jfs) +{ + struct udma_dev *dev = to_udma_dev(jfs->ub_dev); + struct udma_jfs *ujfs = to_udma_jfs(jfs); + + xa_erase(&dev->jetty_table.xa, ujfs->sq.id); + + if (refcount_dec_and_test(&ujfs->ae_refcount)) + complete(&ujfs->ae_comp); + wait_for_completion(&ujfs->ae_comp); + + if (dfx_switch) + udma_dfx_delete_id(dev, &dev->dfx_info->jfs, jfs->jfs_id.id); + + if (ujfs->mode == UDMA_NORMAL_JFS_TYPE) + udma_free_sq_buf(dev, &ujfs->sq); + else + kfree(ujfs->sq.wrid); + + if (ujfs->sq.id < dev->caps.jetty.start_idx) + udma_id_free(&dev->rsvd_jetty_ida_table, ujfs->sq.id); + else + udma_adv_id_free(&dev->jetty_table.bitmap_table, + ujfs->sq.id, false); + + kfree(ujfs); +} + +int udma_destroy_jfs(struct ubcore_jfs *jfs) +{ + struct udma_dev *dev = to_udma_dev(jfs->ub_dev); + struct udma_jfs *ujfs = to_udma_jfs(jfs); + int ret; + + if (!ujfs->ue_rx_closed && udma_close_ue_rx(dev, true, true, false, 0)) { + dev_err(dev->dev, "close ue rx failed when destroying jfs.\n"); + return -EINVAL; + } + + ret = udma_modify_and_destroy_jetty(dev, &ujfs->sq); + if (ret) { + dev_info(dev->dev, "udma modify error and destroy jfs failed, id: %u.\n", + jfs->jfs_id.id); + if (!ujfs->ue_rx_closed) + udma_open_ue_rx(dev, true, true, false, 0); + return ret; + } + + udma_free_jfs(jfs); + udma_open_ue_rx(dev, true, true, false, 0); + + return 0; +} diff --git a/drivers/ub/urma/hw/udma/udma_jfs.h b/drivers/ub/urma/hw/udma/udma_jfs.h index 425c87400fec..ed1ff16e4573 100644 --- a/drivers/ub/urma/hw/udma/udma_jfs.h +++ b/drivers/ub/urma/hw/udma/udma_jfs.h @@ -47,6 +47,7 @@ static inline uint32_t sq_cal_wqebb_num(uint32_t sqe_ctl_len, uint32_t sge_num) struct ubcore_jfs *udma_create_jfs(struct ubcore_device *ub_dev, struct ubcore_jfs_cfg *cfg, struct ubcore_udata *udata); +int udma_destroy_jfs(struct ubcore_jfs *jfs); int udma_alloc_u_sq_buf(struct udma_dev *dev, struct udma_jetty_queue *sq, struct udma_create_jetty_ucmd *ucmd); int udma_alloc_k_sq_buf(struct udma_dev *dev, struct udma_jetty_queue *sq, diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index bf1ffe10367f..2d0b1b0f7332 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -176,6 +176,7 @@ static struct ubcore_ops g_dev_ops = { .unimport_seg = udma_unimport_seg, .create_jfs = udma_create_jfs, .query_jfs = udma_query_jfs, + .destroy_jfs = udma_destroy_jfs, .query_jfr = udma_query_jfr, .query_jetty = udma_query_jetty, }; -- Gitee From d06a4bcf95bb26d20ad18e286bd5ba42c63d3fbb Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 14:49:06 +0800 Subject: [PATCH 070/103] ub: udma: Support create jfr. commit 4d99b1a2909140212152b956ae8969405ba3bb30 openEuler This patch adds the ability to create jfr, During the creation process, driver will create jfr context and send it to the hardware. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/Makefile | 2 +- drivers/ub/urma/hw/udma/udma_dev.h | 2 + drivers/ub/urma/hw/udma/udma_jfr.c | 447 ++++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jfr.h | 63 ++++ drivers/ub/urma/hw/udma/udma_main.c | 2 + 5 files changed, 515 insertions(+), 1 deletion(-) create mode 100644 drivers/ub/urma/hw/udma/udma_jfr.c diff --git a/drivers/ub/urma/hw/udma/Makefile b/drivers/ub/urma/hw/udma/Makefile index 7b1c82ab51dd..8eddc0984ac7 100644 --- a/drivers/ub/urma/hw/udma/Makefile +++ b/drivers/ub/urma/hw/udma/Makefile @@ -3,6 +3,6 @@ udma-$(CONFIG_UB_UDMA) := udma_main.o udma_cmd.o udma_common.o udma_ctx.o udma_db.o \ udma_rct.o udma_tid.o udma_debugfs.o udma_eq.o udma_jfc.o \ udma_ctrlq_tp.o udma_eid.o udma_ctl.o udma_segment.o \ - udma_dfx.o udma_jfs.o udma_jetty.o + udma_dfx.o udma_jfs.o udma_jetty.o udma_jfr.o obj-m := udma.o diff --git a/drivers/ub/urma/hw/udma/udma_dev.h b/drivers/ub/urma/hw/udma/udma_dev.h index bc6ad5c509fd..7656124f875a 100644 --- a/drivers/ub/urma/hw/udma/udma_dev.h +++ b/drivers/ub/urma/hw/udma/udma_dev.h @@ -19,6 +19,8 @@ extern bool dump_aux_info; #define WQE_BB_SIZE_SHIFT 6 +#define UDMA_CTX_NUM 2 + #define MAX_JETTY_IN_JETTY_GRP 32 #define UDMA_USER_DATA_H_OFFSET 32U diff --git a/drivers/ub/urma/hw/udma/udma_jfr.c b/drivers/ub/urma/hw/udma/udma_jfr.c new file mode 100644 index 000000000000..9783907f4602 --- /dev/null +++ b/drivers/ub/urma/hw/udma/udma_jfr.c @@ -0,0 +1,447 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright(c) 2025 HiSilicon Technologies CO., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "UDMA: " fmt + +#include +#include "udma_cmd.h" +#include +#include "udma_jetty.h" +#include "udma_common.h" +#include "udma_db.h" +#include "udma_jfc.h" +#include "udma_jfr.h" + +const char *state_str[] = { + "RESET", + "READY", + "ERROR", + "INVALID" +}; + +static int udma_verify_jfr_param(struct udma_dev *dev, + struct ubcore_jfr_cfg *cfg) +{ + if (!cfg->max_sge || !cfg->depth || cfg->depth > dev->caps.jfr.depth || + cfg->max_sge > dev->caps.jfr_sge) { + dev_err(dev->dev, "Invalid jfr param, depth = %u, max_sge = %u.\n", + cfg->depth, cfg->max_sge); + return -EINVAL; + } + + if (cfg->flag.bs.token_policy > UBCORE_TOKEN_PLAIN_TEXT) { + dev_err(dev->dev, "jfr key policy = %d is not supported now.\n", + cfg->flag.bs.token_policy); + return -EINVAL; + } + + return 0; +} + +static int udma_get_k_jfr_buf(struct udma_dev *dev, struct udma_jfr *jfr) +{ + uint32_t rqe_buf_size; + uint32_t idx_buf_size; + uint32_t sge_per_wqe; + int ret; + + sge_per_wqe = min(jfr->max_sge, dev->caps.jfr_sge); + jfr->rq.buf.entry_size = UDMA_SGE_SIZE * sge_per_wqe; + jfr->rq.buf.entry_cnt = jfr->wqe_cnt; + rqe_buf_size = jfr->rq.buf.entry_size * jfr->rq.buf.entry_cnt; + + ret = udma_k_alloc_buf(dev, rqe_buf_size, &jfr->rq.buf); + if (ret) { + dev_err(dev->dev, + "failed to alloc rq buffer for jfr when buffer size = %u.\n", + rqe_buf_size); + return ret; + } + + jfr->idx_que.buf.entry_size = UDMA_IDX_QUE_ENTRY_SZ; + jfr->idx_que.buf.entry_cnt = jfr->wqe_cnt; + idx_buf_size = jfr->idx_que.buf.entry_size * jfr->idx_que.buf.entry_cnt; + + ret = udma_k_alloc_buf(dev, idx_buf_size, &jfr->idx_que.buf); + if (ret) { + dev_err(dev->dev, + "failed to alloc idx que buffer for jfr when buffer size = %u.\n", + idx_buf_size); + goto err_idx_que; + } + + jfr->rq.wrid = kcalloc(1, jfr->rq.buf.entry_cnt * sizeof(uint64_t), GFP_KERNEL); + if (!jfr->rq.wrid) + goto err_wrid; + + jfr->jetty_addr = (uintptr_t)&jfr->rq; + + if (udma_alloc_sw_db(dev, &jfr->sw_db, UDMA_JFR_TYPE_DB)) { + dev_err(dev->dev, "failed to alloc sw db for jfr(%u).\n", jfr->rq.id); + goto err_alloc_db; + } + + udma_init_udma_table(&jfr->idx_que.jfr_idx_table, jfr->idx_que.buf.entry_cnt - 1, 0); + + jfr->rq.tid = dev->tid; + + return 0; + +err_alloc_db: + kfree(jfr->rq.wrid); +err_wrid: + udma_k_free_buf(dev, idx_buf_size, &jfr->idx_que.buf); +err_idx_que: + udma_k_free_buf(dev, rqe_buf_size, &jfr->rq.buf); + + return -ENOMEM; +} + +static int udma_get_u_jfr_buf(struct udma_dev *dev, struct udma_jfr *jfr, + struct ubcore_udata *udata, + struct udma_create_jetty_ucmd *ucmd) +{ + unsigned long byte; + int ret; + + if (!udata->udrv_data) { + dev_err(dev->dev, "jfr udata udrv_data is null.\n"); + return -EINVAL; + } + + if (!udata->udrv_data->in_addr || udata->udrv_data->in_len < sizeof(*ucmd)) { + dev_err(dev->dev, "jfr in_len %u or addr is invalid.\n", + udata->udrv_data->in_len); + return -EINVAL; + } + + byte = copy_from_user(ucmd, (void *)(uintptr_t)udata->udrv_data->in_addr, + sizeof(*ucmd)); + if (byte) { + dev_err(dev->dev, + "failed to copy jfr udata, byte = %lu.\n", byte); + return -EFAULT; + } + + if (!ucmd->non_pin) { + ret = pin_queue_addr(dev, ucmd->buf_addr, ucmd->buf_len, &jfr->rq.buf); + if (ret) { + dev_err(dev->dev, + "failed to pin jfr rqe buf addr, ret = %d.\n", ret); + return ret; + } + + ret = pin_queue_addr(dev, ucmd->idx_addr, ucmd->idx_len, + &jfr->idx_que.buf); + if (ret) { + dev_err(dev->dev, + "failed to pin jfr idx que addr, ret = %d.\n", ret); + goto err_pin_idx_buf; + } + } else { + jfr->rq.buf.addr = ucmd->buf_addr; + jfr->idx_que.buf.addr = ucmd->idx_addr; + } + + jfr->udma_ctx = to_udma_context(udata->uctx); + jfr->sw_db.db_addr = ucmd->db_addr; + jfr->jfr_sleep_buf.db_addr = ucmd->jfr_sleep_buf; + + if (!ucmd->non_pin) { + ret = udma_pin_sw_db(jfr->udma_ctx, &jfr->sw_db); + if (ret) { + dev_err(dev->dev, + "failed to pin jfr sw db addr, ret = %d.\n", ret); + goto err_pin_sw_db; + } + + ret = udma_pin_sw_db(jfr->udma_ctx, &jfr->jfr_sleep_buf); + if (ret) { + dev_err(dev->dev, + "failed to pin jfr sleep time buf, ret = %d.\n", ret); + goto err_pin_jfr_sleep_buf; + } + } + + jfr->jetty_addr = ucmd->jetty_addr; + jfr->rq.tid = jfr->udma_ctx->tid; + + return ret; + +err_pin_jfr_sleep_buf: + udma_unpin_sw_db(jfr->udma_ctx, &jfr->sw_db); +err_pin_sw_db: + unpin_queue_addr(jfr->idx_que.buf.umem); +err_pin_idx_buf: + unpin_queue_addr(jfr->rq.buf.umem); + return ret; +} + +static int udma_get_jfr_buf(struct udma_dev *dev, struct udma_jfr *jfr, + struct ubcore_udata *udata) +{ + struct udma_create_jetty_ucmd ucmd = {}; + + if (udata == NULL) + return udma_get_k_jfr_buf(dev, jfr); + else + return udma_get_u_jfr_buf(dev, jfr, udata, &ucmd); +} + +static void udma_put_jfr_buf(struct udma_dev *dev, struct udma_jfr *jfr) +{ + uint32_t size; + + if (!jfr->rq.buf.kva && !jfr->idx_que.buf.kva && + jfr->sw_db.page && jfr->jfr_sleep_buf.page) { + udma_unpin_sw_db(jfr->udma_ctx, &jfr->jfr_sleep_buf); + udma_unpin_sw_db(jfr->udma_ctx, &jfr->sw_db); + unpin_queue_addr(jfr->idx_que.buf.umem); + unpin_queue_addr(jfr->rq.buf.umem); + return; + } + + if (jfr->rq.buf.kva) { + size = jfr->rq.buf.entry_cnt * jfr->rq.buf.entry_size; + udma_k_free_buf(dev, size, &jfr->rq.buf); + udma_free_sw_db(dev, &jfr->sw_db); + } + + if (jfr->idx_que.buf.kva) { + size = jfr->idx_que.buf.entry_cnt * jfr->idx_que.buf.entry_size; + udma_k_free_buf(dev, size, &jfr->idx_que.buf); + udma_destroy_udma_table(dev, &jfr->idx_que.jfr_idx_table, "JFR_IDX"); + } + + kfree(jfr->rq.wrid); +} + +static enum udma_rx_limit_wl to_udma_limit_wl(uint32_t rx_threshold) +{ + if (rx_threshold >= LIMIT_WL_4096_V) + return UDMA_RX_LIMIT_WL_4096; + if (rx_threshold >= LIMIT_WL_512_V) + return UDMA_RX_LIMIT_WL_512; + if (rx_threshold >= LIMIT_WL_64_V) + return UDMA_RX_LIMIT_WL_64; + + return UDMA_RX_LIMIT_WL_0; +} + +static void udma_init_jfrc(struct udma_dev *dev, struct ubcore_jfr_cfg *cfg, + struct udma_jfr *jfr, void *mb_buf, + uint32_t rx_threshold) +{ + struct udma_jfr_ctx *ctx = (struct udma_jfr_ctx *)mb_buf; + struct udma_jfc *jfc = to_udma_jfc(cfg->jfc); + uint32_t tid = jfr->rq.tid; + uint64_t db_addr; + + db_addr = jfr->sw_db.db_addr; + + memset(ctx, 0, sizeof(struct udma_jfr_ctx) * UDMA_CTX_NUM); + ctx->state = UDMA_JFR_STATE_READY; + ctx->record_db_en = 1; + ctx->rqe_base_addr_l = (jfr->rq.buf.addr >> RQE_VA_L_PAGE_4K_OFFSET) & + (uint32_t)RQE_VA_L_VALID_BIT; + ctx->rqe_base_addr_h = (jfr->rq.buf.addr >> (uint32_t)RQE_VA_H_PAGE_4K_OFFSET) & + (uint32_t)RQE_VA_H_VALID_BIT; + ctx->idx_que_addr_l = (jfr->idx_que.buf.addr >> JFR_IDX_VA_L_PAGE_4K_OFFSET) & + (uint32_t)JFR_IDX_VA_L_VALID_BIT; + ctx->idx_que_addr_h = (jfr->idx_que.buf.addr >> (uint32_t)JFR_IDX_VA_H_PAGE_4K_OFFSET) & + (uint32_t)JFR_IDX_VA_H_VALID_BIT; + ctx->record_db_addr_l = (db_addr >> JFR_DB_VA_L_PAGE_64_OFFSET) & + (uint32_t)JFR_DB_VA_L_VALID_BIT; + ctx->record_db_addr_m = (db_addr >> (uint32_t)JFR_DB_VA_M_PAGE_64_OFFSET) & + (uint32_t)JFR_DB_VA_M_VALID_BIT; + ctx->record_db_addr_h = (db_addr >> (uint32_t)JFR_DB_VA_H_PAGE_64_OFFSET) & + (uint32_t)JFR_DB_VA_H_VALID_BIT; + ctx->rqe_token_id_l = tid & (uint32_t)RQE_TOKEN_ID_L_MASK; + ctx->rqe_token_id_h = (tid >> RQE_TOKEN_ID_H_OFFSET) & (uint32_t)RQE_TOKEN_ID_H_MASK; + ctx->jfcn_l = cfg->jfc->id & (uint32_t)JFR_JFCN_L_VALID_BIT; + ctx->jfcn_h = (cfg->jfc->id >> JFR_JFCN_H_OFFSET) & (uint32_t)JFR_JFCN_H_VALID_BIT; + if (cfg->min_rnr_timer > UDMA_RNR_MAX) { + dev_warn(dev->dev, + "min_rnr_timer is out of range, max_value(%d) is applied.\n", + UDMA_RNR_MAX); + ctx->rnr_timer = UDMA_RNR_MAX; + } else { + ctx->rnr_timer = cfg->min_rnr_timer; + } + if (cfg->flag.bs.token_policy != UBCORE_TOKEN_NONE) + ctx->token_en = 1; + ctx->type = to_udma_type(cfg->trans_mode); + ctx->token_value = cfg->token_value.token; + ctx->user_data_l = jfr->jetty_addr; + ctx->user_data_h = jfr->jetty_addr >> UDMA_USER_DATA_H_OFFSET; + ctx->rqe_size_shift = ilog2(jfr->max_sge); + ctx->rqe_shift = ilog2(jfr->wqe_cnt); + if (!!(dev->caps.feature & UDMA_CAP_FEATURE_JFC_INLINE)) + ctx->cqeie = jfc->inline_en; + + ctx->limit_wl = (uint32_t)to_udma_limit_wl(rx_threshold); + ctx->pld_token_id = tid & (uint32_t)JFR_PLD_TOKEN_ID_MASK; +} + +static void udma_reset_sw_k_jfr_queue(struct udma_jfr *jfr) +{ + ida_destroy(&jfr->idx_que.jfr_idx_table.ida_table.ida); + ida_init(&jfr->idx_que.jfr_idx_table.ida_table.ida); + jfr->rq.pi = 0; + jfr->rq.ci = 0; + *jfr->sw_db.db_record = 0; +} + +static int udma_hw_init_jfrc(struct udma_dev *dev, struct ubcore_jfr_cfg *cfg, + struct udma_jfr *jfr, uint32_t rx_threshold) +{ + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + struct udma_jfr_ctx *ctx = NULL; + int ret; + + mailbox = udma_alloc_cmd_mailbox(dev); + if (!mailbox) { + dev_err(dev->dev, "failed to alloc mailbox for JFRC.\n"); + return -ENOMEM; + } + + udma_init_jfrc(dev, cfg, jfr, mailbox->buf, rx_threshold); + + mbox_attr.tag = jfr->rq.id; + mbox_attr.op = UDMA_CMD_CREATE_JFR_CONTEXT; + ret = udma_post_mbox(dev, mailbox, &mbox_attr); + if (ret) + dev_err(dev->dev, + "failed to post mbox cmd of create JFRC, ret = %d.\n", + ret); + + if (jfr->rq.buf.kva) + udma_reset_sw_k_jfr_queue(jfr); + + ctx = (struct udma_jfr_ctx *)mailbox->buf; + ctx->token_value = 0; + udma_free_cmd_mailbox(dev, mailbox); + + return ret; +} + +static void set_jfr_param(struct udma_jfr *jfr, struct ubcore_jfr_cfg *cfg) +{ + if (cfg->depth < UDMA_MIN_JFR_DEPTH) + jfr->wqe_cnt = UDMA_MIN_JFR_DEPTH; + else + jfr->wqe_cnt = roundup_pow_of_two(cfg->depth); + + jfr->ubcore_jfr.jfr_id.id = jfr->rq.id; + jfr->ubcore_jfr.jfr_cfg = *cfg; + jfr->max_sge = roundup_pow_of_two(cfg->max_sge); + jfr->ubcore_jfr.jfr_cfg.max_sge = jfr->max_sge; + jfr->ubcore_jfr.jfr_cfg.depth = jfr->wqe_cnt; + jfr->state = UBCORE_JFR_STATE_READY; + + if (!cfg->flag.bs.lock_free) + spin_lock_init(&jfr->lock); +} + +static int udma_alloc_jfr_id(struct udma_dev *udma_dev, uint32_t cfg_id, uint32_t *idx) +{ + struct udma_ida *ida_table = &udma_dev->jfr_table.ida_table; + uint32_t min; + uint32_t max; + int id; + + if (cfg_id && (cfg_id < ida_table->min || cfg_id > ida_table->max)) { + dev_err(udma_dev->dev, + "user specify id %u error, min %u max %u.\n", + cfg_id, ida_table->min, ida_table->max); + return -EINVAL; + } + + spin_lock(&ida_table->lock); + min = cfg_id ? cfg_id : ida_table->next; + max = cfg_id ? cfg_id : ida_table->max; + id = ida_alloc_range(&ida_table->ida, min, max, GFP_ATOMIC); + if (id < 0) { + if (!cfg_id) + id = ida_alloc_range(&ida_table->ida, min = ida_table->min, + max, GFP_ATOMIC); + if (id < 0) { + dev_err(udma_dev->dev, + "alloc jfr id range (%u - %u) failed, ret = %d.\n", + min, max, id); + spin_unlock(&ida_table->lock); + + return id; + } + } + + *idx = (uint32_t)id; + + if (!cfg_id) + ida_table->next = (uint32_t)id + 1 > ida_table->max ? + ida_table->min : (uint32_t)id + 1; + spin_unlock(&ida_table->lock); + + return 0; +} + +struct ubcore_jfr *udma_create_jfr(struct ubcore_device *dev, + struct ubcore_jfr_cfg *cfg, + struct ubcore_udata *udata) +{ + struct udma_dev *udma_dev = to_udma_dev(dev); + struct udma_jfr *udma_jfr; + int ret; + + ret = udma_verify_jfr_param(udma_dev, cfg); + if (ret) { + dev_err(udma_dev->dev, "verify jfr param failed.\n"); + return NULL; + } + + udma_jfr = kzalloc(sizeof(*udma_jfr), GFP_KERNEL); + if (!udma_jfr) + return NULL; + + ret = udma_alloc_jfr_id(udma_dev, cfg->id, &udma_jfr->rq.id); + if (ret) + goto err_alloc_jfr_id; + + set_jfr_param(udma_jfr, cfg); + + ret = udma_get_jfr_buf(udma_dev, udma_jfr, udata); + if (ret) + goto err_get_jfr_buf; + + ret = xa_err(xa_store(&udma_dev->jfr_table.xa, udma_jfr->rq.id, + udma_jfr, GFP_KERNEL)); + if (ret) { + dev_err(udma_dev->dev, "store jfr to jfr_table failed.\n"); + goto err_xa_store; + } + + ret = udma_hw_init_jfrc(udma_dev, cfg, udma_jfr, 0); + if (ret) { + dev_err(udma_dev->dev, "failed to init JFRC, ret = %d.\n", ret); + goto err_hw_init_jfrc; + } + + refcount_set(&udma_jfr->ae_refcount, 1); + init_completion(&udma_jfr->ae_comp); + + if (dfx_switch) + udma_dfx_store_id(udma_dev, &udma_dev->dfx_info->jfr, udma_jfr->rq.id, "jfr"); + + return &udma_jfr->ubcore_jfr; + +err_hw_init_jfrc: + xa_erase(&udma_dev->jfr_table.xa, udma_jfr->rq.id); +err_xa_store: + udma_put_jfr_buf(udma_dev, udma_jfr); +err_get_jfr_buf: + udma_id_free(&udma_dev->jfr_table.ida_table, udma_jfr->rq.id); +err_alloc_jfr_id: + kfree(udma_jfr); + return NULL; +} diff --git a/drivers/ub/urma/hw/udma/udma_jfr.h b/drivers/ub/urma/hw/udma/udma_jfr.h index bffb68b3cdbd..bd29f9c4a526 100644 --- a/drivers/ub/urma/hw/udma/udma_jfr.h +++ b/drivers/ub/urma/hw/udma/udma_jfr.h @@ -8,7 +8,67 @@ #include "udma_ctx.h" #include "udma_common.h" +#define RQE_VA_L_PAGE_4K_OFFSET 12U +#define RQE_VA_L_VALID_BIT GENMASK(19, 0) +#define RQE_VA_H_OFFSET 20 +#define RQE_VA_H_PAGE_4K_OFFSET (RQE_VA_H_OFFSET + RQE_VA_L_PAGE_4K_OFFSET) +#define RQE_VA_H_VALID_BIT GENMASK(31, 0) + +#define RQE_TOKEN_ID_L_MASK GENMASK(13, 0) +#define RQE_TOKEN_ID_H_OFFSET 14U +#define RQE_TOKEN_ID_H_MASK GENMASK(5, 0) + +#define JFR_IDX_VA_L_PAGE_4K_OFFSET 12U +#define JFR_IDX_VA_L_VALID_BIT GENMASK(31, 0) +#define JFR_IDX_VA_H_OFFSET 32 +#define JFR_IDX_VA_H_PAGE_4K_OFFSET \ + (JFR_IDX_VA_H_OFFSET + JFR_IDX_VA_L_PAGE_4K_OFFSET) +#define JFR_IDX_VA_H_VALID_BIT GENMASK(19, 0) + +#define JFR_DB_VA_L_PAGE_64_OFFSET 6U +#define JFR_DB_VA_L_VALID_BIT GENMASK(23, 0) +#define JFR_DB_VA_M_OFFSET 24 +#define JFR_DB_VA_M_PAGE_64_OFFSET \ + (JFR_DB_VA_M_OFFSET + JFR_DB_VA_L_PAGE_64_OFFSET) +#define JFR_DB_VA_M_VALID_BIT GENMASK(31, 0) +#define JFR_DB_VA_H_OFFSET 32 +#define JFR_DB_VA_H_PAGE_64_OFFSET \ + (JFR_DB_VA_H_OFFSET + JFR_DB_VA_M_PAGE_64_OFFSET) +#define JFR_DB_VA_H_VALID_BIT GENMASK(1, 0) + +#define JFR_JFCN_L_VALID_BIT GENMASK(11, 0) #define JFR_JFCN_H_OFFSET 12U +#define JFR_JFCN_H_VALID_BIT GENMASK(7, 0) + +#define UDMA_JFR_DB_PI_M GENMASK(15, 0) + +#define JFR_PLD_TOKEN_ID_MASK GENMASK(19, 0) + +#define UDMA_MIN_JFR_DEPTH 64 +#define UDMA_SGE_SIZE 16U +#define UDMA_IDX_QUE_ENTRY_SZ 4 +#define UDMA_RNR_MAX 19 + +enum jfr_state { + UDMA_JFR_STATE_RESET = 0, + UDMA_JFR_STATE_READY, + UDMA_JFR_STATE_ERROR, + JFR_STATE_NUM, +}; + +enum udma_rx_limit_wl { + UDMA_RX_LIMIT_WL_0 = 0, + UDMA_RX_LIMIT_WL_64, + UDMA_RX_LIMIT_WL_512, + UDMA_RX_LIMIT_WL_4096 +}; + +enum { + LIMIT_WL_0_V = 0, + LIMIT_WL_64_V = 64, + LIMIT_WL_512_V = 512, + LIMIT_WL_4096_V = 4096 +}; struct udma_jfr_idx_que { struct udma_buf buf; @@ -92,4 +152,7 @@ static inline struct udma_jfr *to_udma_jfr_from_queue(struct udma_jetty_queue *q return container_of(queue, struct udma_jfr, rq); } +struct ubcore_jfr *udma_create_jfr(struct ubcore_device *dev, struct ubcore_jfr_cfg *cfg, + struct ubcore_udata *udata); + #endif /* __UDMA_JFR_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 2d0b1b0f7332..2b6cbcb0bd20 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -20,6 +20,7 @@ #include "udma_eq.h" #include "udma_segment.h" #include "udma_jfs.h" +#include "udma_jfr.h" #include "udma_cmd.h" #include "udma_ctx.h" #include "udma_rct.h" @@ -177,6 +178,7 @@ static struct ubcore_ops g_dev_ops = { .create_jfs = udma_create_jfs, .query_jfs = udma_query_jfs, .destroy_jfs = udma_destroy_jfs, + .create_jfr = udma_create_jfr, .query_jfr = udma_query_jfr, .query_jetty = udma_query_jetty, }; -- Gitee From d57de0ac9721a69f6540f75400e407aeb7fe03c1 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 15:22:55 +0800 Subject: [PATCH 071/103] ub: udma: Support destroy jfr. commit c9ab1d26bebe7b020b7b0f938cd76b8157133f92 openEuler This patch adds the ability to destroy jfr, During the destruction process, driver will destroy jfr context and send it to the hardware. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_dev.h | 1 + drivers/ub/urma/hw/udma/udma_jfr.c | 205 ++++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jfr.h | 5 + drivers/ub/urma/hw/udma/udma_main.c | 6 + 4 files changed, 217 insertions(+) diff --git a/drivers/ub/urma/hw/udma/udma_dev.h b/drivers/ub/urma/hw/udma/udma_dev.h index 7656124f875a..9f2a20eea557 100644 --- a/drivers/ub/urma/hw/udma/udma_dev.h +++ b/drivers/ub/urma/hw/udma/udma_dev.h @@ -12,6 +12,7 @@ #include extern bool dfx_switch; +extern uint32_t jfr_sleep_time; extern uint32_t jfc_arm_mode; extern bool dump_aux_info; diff --git a/drivers/ub/urma/hw/udma/udma_jfr.c b/drivers/ub/urma/hw/udma/udma_jfr.c index 9783907f4602..f15ca6b26d42 100644 --- a/drivers/ub/urma/hw/udma/udma_jfr.c +++ b/drivers/ub/urma/hw/udma/udma_jfr.c @@ -445,3 +445,208 @@ struct ubcore_jfr *udma_create_jfr(struct ubcore_device *dev, kfree(udma_jfr); return NULL; } + +static int modify_jfr_context(struct udma_dev *dev, uint32_t jfrn, + bool state_flag, bool rx_threshold_flag, + struct ubcore_jfr_attr *attr) +{ + struct ubase_mbx_attr mbox_attr = {}; + struct udma_jfr_ctx *ctx, *ctx_mask; + struct ubase_cmd_mailbox *mailbox; + int ret; + + mailbox = udma_alloc_cmd_mailbox(dev); + if (!mailbox) { + dev_err(dev->dev, "failed to alloc mailbox for JFRC.\n"); + return -EINVAL; + } + + ctx = (struct udma_jfr_ctx *)mailbox->buf; + ctx_mask = ctx + 1; + memset(ctx_mask, 0xff, sizeof(struct udma_jfr_ctx)); + if (state_flag) { + ctx->state = attr->state; + ctx_mask->state = 0; + } + + if (rx_threshold_flag) { + ctx->limit_wl = (uint32_t)to_udma_limit_wl(attr->rx_threshold); + ctx_mask->limit_wl = 0; + } + + mbox_attr.tag = jfrn; + mbox_attr.op = UDMA_CMD_MODIFY_JFR_CONTEXT; + + ret = udma_post_mbox(dev, mailbox, &mbox_attr); + if (ret) + dev_err(dev->dev, + "failed to post mbox cmd of modify JFRC, ret = %d.\n", ret); + + udma_free_cmd_mailbox(dev, mailbox); + + return ret; +} + +static int udma_modify_jfr_to_error(struct ubcore_jfr *jfr, bool *need_sleep) +{ + struct udma_dev *udma_dev = to_udma_dev(jfr->ub_dev); + struct udma_jfr *udma_jfr = to_udma_jfr(jfr); + struct ubcore_jfr_attr attr; + int ret = 0; + + if (udma_jfr->state == UBCORE_JFR_STATE_READY) { + attr.state = UBCORE_JFR_STATE_ERROR; + attr.mask = UBCORE_JFR_STATE; + ret = modify_jfr_context(udma_dev, udma_jfr->rq.id, true, false, &attr); + if (ret) { + dev_err(udma_dev->dev, "failed to modify jfr state to error, id: %u.\n", + udma_jfr->rq.id); + return ret; + } + + udma_jfr->state = UBCORE_JFR_STATE_ERROR; + + *need_sleep = true; + } + + return ret; +} + +static int udma_modify_jfr_to_reset(struct ubcore_jfr *jfr) +{ + struct udma_dev *udma_dev = to_udma_dev(jfr->ub_dev); + struct udma_jfr *udma_jfr = to_udma_jfr(jfr); + struct ubase_mbx_attr mbox_attr = {}; + int ret = 0; + + if (udma_jfr->state != UBCORE_JFR_STATE_RESET) { + mbox_attr.tag = udma_jfr->rq.id; + mbox_attr.op = UDMA_CMD_DESTROY_JFR_CONTEXT; + ret = post_mailbox_update_ctx(udma_dev, NULL, 0, &mbox_attr); + if (ret) { + dev_err(udma_dev->dev, "failed to post jfr destroy cmd, id: %u.\n", + udma_jfr->rq.id); + return ret; + } + + udma_jfr->state = UBCORE_JFR_STATE_RESET; + } + + return ret; +} + +static int udma_modify_and_del_jfr(struct udma_dev *udma_dev, struct udma_jfr *udma_jfr) +{ + bool large_payload = false; + bool need_sleep = false; + uint32_t sleep_time = 0; + int ret = 0; + + ret = udma_modify_jfr_to_error(&udma_jfr->ubcore_jfr, &need_sleep); + if (ret) + return ret; + if (!udma_jfr->rq.buf.kva && udma_jfr->jfr_sleep_buf.page) + large_payload = !!(*(bool *)udma_jfr->jfr_sleep_buf.virt_addr); + if (need_sleep) { + sleep_time = large_payload ? jfr_sleep_time : UDMA_DEF_JFR_SLEEP_TIME; + dev_info_ratelimited(udma_dev->dev, "jfr sleep time = %u us.\n", sleep_time); + usleep_range(sleep_time, sleep_time + UDMA_SLEEP_DELAY_TIME); + } + + return udma_modify_jfr_to_reset(&udma_jfr->ubcore_jfr); +} + +static void udma_free_jfr(struct ubcore_jfr *jfr) +{ + struct udma_dev *udma_dev = to_udma_dev(jfr->ub_dev); + struct udma_jfr *udma_jfr = to_udma_jfr(jfr); + + if (dfx_switch) + udma_dfx_delete_id(udma_dev, &udma_dev->dfx_info->jfr, udma_jfr->rq.id); + + xa_erase(&udma_dev->jfr_table.xa, udma_jfr->rq.id); + + if (refcount_dec_and_test(&udma_jfr->ae_refcount)) + complete(&udma_jfr->ae_comp); + wait_for_completion(&udma_jfr->ae_comp); + + udma_put_jfr_buf(udma_dev, udma_jfr); + udma_id_free(&udma_dev->jfr_table.ida_table, udma_jfr->rq.id); + jfr->jfr_cfg.token_value.token = 0; + kfree(udma_jfr); +} + +int udma_destroy_jfr(struct ubcore_jfr *jfr) +{ + struct udma_dev *udma_dev = to_udma_dev(jfr->ub_dev); + struct udma_jfr *udma_jfr = to_udma_jfr(jfr); + int ret; + + ret = udma_modify_and_del_jfr(udma_dev, udma_jfr); + if (ret) { + dev_err(udma_dev->dev, + "failed to modify and delete jfr, id: %u, ret = %d.\n", + udma_jfr->rq.id, ret); + return ret; + } + + udma_free_jfr(jfr); + + return 0; +} + +int udma_destroy_jfr_batch(struct ubcore_jfr **jfr, int jfr_cnt, int *bad_jfr_index) +{ + bool large_payload = false; + struct udma_dev *udma_dev; + struct udma_jfr *udma_jfr; + bool need_sleep = false; + uint32_t sleep_time = 0; + uint32_t i; + int ret; + + if (!jfr) { + pr_info("jfr array is null.\n"); + return -EINVAL; + } + + if (!jfr_cnt) { + pr_info("jfr cnt is 0.\n"); + return -EINVAL; + } + + udma_dev = to_udma_dev(jfr[0]->ub_dev); + + for (i = 0; i < jfr_cnt; i++) { + ret = udma_modify_jfr_to_error(jfr[i], &need_sleep); + if (ret) { + *bad_jfr_index = 0; + return ret; + } + + if (unlikely(large_payload)) + continue; + udma_jfr = to_udma_jfr(jfr[i]); + if (!udma_jfr->rq.buf.kva && udma_jfr->jfr_sleep_buf.page) + large_payload = !!(*(bool *)udma_jfr->jfr_sleep_buf.virt_addr); + } + + if (need_sleep) { + sleep_time = large_payload ? jfr_sleep_time : UDMA_DEF_JFR_SLEEP_TIME; + dev_info(udma_dev->dev, "jfr sleep time = %u us.\n", sleep_time); + usleep_range(sleep_time, sleep_time + UDMA_SLEEP_DELAY_TIME); + } + + for (i = 0; i < jfr_cnt; i++) { + ret = udma_modify_jfr_to_reset(jfr[i]); + if (ret) { + *bad_jfr_index = 0; + return ret; + } + } + + for (i = 0; i < jfr_cnt; i++) + udma_free_jfr(jfr[i]); + + return 0; +} diff --git a/drivers/ub/urma/hw/udma/udma_jfr.h b/drivers/ub/urma/hw/udma/udma_jfr.h index bd29f9c4a526..43ee96cea746 100644 --- a/drivers/ub/urma/hw/udma/udma_jfr.h +++ b/drivers/ub/urma/hw/udma/udma_jfr.h @@ -49,6 +49,9 @@ #define UDMA_IDX_QUE_ENTRY_SZ 4 #define UDMA_RNR_MAX 19 +#define UDMA_DEF_JFR_SLEEP_TIME 1000 +#define UDMA_SLEEP_DELAY_TIME 10 + enum jfr_state { UDMA_JFR_STATE_RESET = 0, UDMA_JFR_STATE_READY, @@ -154,5 +157,7 @@ static inline struct udma_jfr *to_udma_jfr_from_queue(struct udma_jetty_queue *q struct ubcore_jfr *udma_create_jfr(struct ubcore_device *dev, struct ubcore_jfr_cfg *cfg, struct ubcore_udata *udata); +int udma_destroy_jfr(struct ubcore_jfr *jfr); +int udma_destroy_jfr_batch(struct ubcore_jfr **jfr_arr, int jfr_num, int *bad_jfr_index); #endif /* __UDMA_JFR_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 2b6cbcb0bd20..c5911b027ba6 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -33,6 +33,7 @@ bool is_rmmod; static DEFINE_MUTEX(udma_reset_mutex); +uint32_t jfr_sleep_time = 1000; uint32_t jfc_arm_mode; bool dump_aux_info; @@ -179,6 +180,8 @@ static struct ubcore_ops g_dev_ops = { .query_jfs = udma_query_jfs, .destroy_jfs = udma_destroy_jfs, .create_jfr = udma_create_jfr, + .destroy_jfr = udma_destroy_jfr, + .destroy_jfr_batch = udma_destroy_jfr_batch, .query_jfr = udma_query_jfr, .query_jetty = udma_query_jetty, }; @@ -1092,6 +1095,9 @@ module_init(udma_init); module_exit(udma_exit); MODULE_LICENSE("GPL"); +module_param(jfr_sleep_time, uint, 0444); +MODULE_PARM_DESC(jfr_sleep_time, "Set the destroy jfr sleep time, default: 1000 us.\n"); + module_param(jfc_arm_mode, uint, 0444); MODULE_PARM_DESC(jfc_arm_mode, "Set the ARM mode of the JFC, default: 0(0:Always ARM, other: NO ARM."); -- Gitee From 8ea6b97064206a1bbc64376946405f76e54f6723 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 15:51:47 +0800 Subject: [PATCH 072/103] ub: udma: Support create jfc. commit 14ca6ade755ce2333f8f9c1524bdd24ff5577c8b openEuler This patch adds the ability to create jfc. During the creation process, driver will create jfc context and send it to the hardware. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_dev.h | 7 + drivers/ub/urma/hw/udma/udma_jfc.c | 381 ++++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jfc.h | 36 +++ drivers/ub/urma/hw/udma/udma_main.c | 6 + 4 files changed, 430 insertions(+) diff --git a/drivers/ub/urma/hw/udma/udma_dev.h b/drivers/ub/urma/hw/udma/udma_dev.h index 9f2a20eea557..d9b10ab28028 100644 --- a/drivers/ub/urma/hw/udma/udma_dev.h +++ b/drivers/ub/urma/hw/udma/udma_dev.h @@ -12,6 +12,7 @@ #include extern bool dfx_switch; +extern bool cqe_mode; extern uint32_t jfr_sleep_time; extern uint32_t jfc_arm_mode; extern bool dump_aux_info; @@ -85,6 +86,11 @@ struct udma_mailbox_cmd { struct rw_semaphore udma_mb_rwsem; }; +struct udma_ex_jfc_addr { + uint64_t cq_addr; + uint32_t cq_len; +}; + struct udma_dev { struct ubase_adev_com comdev; struct ubcore_device ub_dev; @@ -124,6 +130,7 @@ struct udma_dev { uint32_t status; struct udma_dev_debugfs *dbgfs; uint32_t ue_num; + struct udma_ex_jfc_addr cq_addr_array[UDMA_JFC_TYPE_NUM]; uint32_t ue_id; struct page *db_page; u8 udma_tp_sl_num; diff --git a/drivers/ub/urma/hw/udma/udma_jfc.c b/drivers/ub/urma/hw/udma/udma_jfc.c index ee223bb923f6..9d86d9003593 100644 --- a/drivers/ub/urma/hw/udma/udma_jfc.c +++ b/drivers/ub/urma/hw/udma/udma_jfc.c @@ -18,6 +18,387 @@ #include #include "udma_jfc.h" +static void udma_construct_jfc_ctx(struct udma_dev *dev, + struct udma_jfc *jfc, + struct udma_jfc_ctx *ctx) +{ + memset(ctx, 0, sizeof(struct udma_jfc_ctx)); + + ctx->state = UDMA_JFC_STATE_VALID; + if (jfc_arm_mode) + ctx->arm_st = UDMA_CTX_NO_ARMED; + else + ctx->arm_st = UDMA_CTX_ALWAYS_ARMED; + ctx->shift = jfc->cq_shift - UDMA_JFC_DEPTH_SHIFT_BASE; + ctx->jfc_type = UDMA_NORMAL_JFC_TYPE; + if (!!(dev->caps.feature & UDMA_CAP_FEATURE_JFC_INLINE)) + ctx->inline_en = jfc->inline_en; + ctx->cqe_va_l = jfc->buf.addr >> CQE_VA_L_OFFSET; + ctx->cqe_va_h = jfc->buf.addr >> CQE_VA_H_OFFSET; + ctx->cqe_token_id = jfc->tid; + + if (cqe_mode) + ctx->cq_cnt_mode = UDMA_CQE_CNT_MODE_BY_CI_PI_GAP; + else + ctx->cq_cnt_mode = UDMA_CQE_CNT_MODE_BY_COUNT; + + ctx->ceqn = jfc->ceqn; + if (jfc->stars_en) { + ctx->stars_en = UDMA_STARS_SWITCH; + ctx->record_db_en = UDMA_NO_RECORD_EN; + } else { + ctx->record_db_en = UDMA_RECORD_EN; + ctx->record_db_addr_l = jfc->db.db_addr >> UDMA_DB_L_OFFSET; + ctx->record_db_addr_h = jfc->db.db_addr >> UDMA_DB_H_OFFSET; + } +} + +void udma_init_jfc_param(struct ubcore_jfc_cfg *cfg, + struct udma_jfc *jfc) +{ + jfc->base.id = jfc->jfcn; + jfc->base.jfc_cfg = *cfg; + jfc->ceqn = cfg->ceqn; + jfc->lock_free = cfg->flag.bs.lock_free; + jfc->inline_en = cfg->flag.bs.jfc_inline; + jfc->cq_shift = ilog2(jfc->buf.entry_cnt); +} + +int udma_check_jfc_cfg(struct udma_dev *dev, struct udma_jfc *jfc, + struct ubcore_jfc_cfg *cfg) +{ + if (!jfc->buf.entry_cnt || jfc->buf.entry_cnt > dev->caps.jfc.depth) { + dev_err(dev->dev, "invalid jfc depth = %u, cap depth = %u.\n", + jfc->buf.entry_cnt, dev->caps.jfc.depth); + return -EINVAL; + } + + if (jfc->buf.entry_cnt < UDMA_JFC_DEPTH_MIN) + jfc->buf.entry_cnt = UDMA_JFC_DEPTH_MIN; + + if (cfg->ceqn >= dev->caps.comp_vector_cnt) { + dev_err(dev->dev, "invalid ceqn = %u, cap ceq cnt = %u.\n", + cfg->ceqn, dev->caps.comp_vector_cnt); + return -EINVAL; + } + + return 0; +} + +static int udma_get_cmd_from_user(struct udma_create_jfc_ucmd *ucmd, + struct udma_dev *dev, + struct ubcore_udata *udata, + struct udma_jfc *jfc) +{ +#define UDMA_JFC_CQE_SHIFT 6 + unsigned long byte; + + if (!udata->udrv_data || !udata->udrv_data->in_addr) { + dev_err(dev->dev, "jfc udrv_data or in_addr is null.\n"); + return -EINVAL; + } + + byte = copy_from_user(ucmd, (void *)(uintptr_t)udata->udrv_data->in_addr, + min(udata->udrv_data->in_len, + (uint32_t)sizeof(*ucmd))); + if (byte) { + dev_err(dev->dev, + "failed to copy udata from user, byte = %lu.\n", byte); + return -EFAULT; + } + + jfc->mode = ucmd->mode; + jfc->ctx = to_udma_context(udata->uctx); + if (jfc->mode > UDMA_NORMAL_JFC_TYPE && jfc->mode < UDMA_KERNEL_STARS_JFC_TYPE) { + jfc->buf.entry_cnt = ucmd->buf_len; + return 0; + } + + jfc->db.db_addr = ucmd->db_addr; + jfc->buf.entry_cnt = ucmd->buf_len >> UDMA_JFC_CQE_SHIFT; + + return 0; +} + +static int udma_get_jfc_buf(struct udma_dev *dev, struct udma_create_jfc_ucmd *ucmd, + struct ubcore_udata *udata, struct udma_jfc *jfc) +{ + struct udma_context *uctx; + uint32_t size; + int ret = 0; + + if (udata) { + ret = pin_queue_addr(dev, ucmd->buf_addr, ucmd->buf_len, &jfc->buf); + if (ret) { + dev_err(dev->dev, "failed to pin queue for jfc, ret = %d.\n", ret); + return ret; + } + uctx = to_udma_context(udata->uctx); + jfc->tid = uctx->tid; + ret = udma_pin_sw_db(uctx, &jfc->db); + if (ret) { + dev_err(dev->dev, "failed to pin sw db for jfc, ret = %d.\n", ret); + unpin_queue_addr(jfc->buf.umem); + } + + return ret; + } + + if (!jfc->lock_free) + spin_lock_init(&jfc->lock); + jfc->buf.entry_size = dev->caps.cqe_size; + jfc->tid = dev->tid; + size = jfc->buf.entry_size * jfc->buf.entry_cnt; + + ret = udma_k_alloc_buf(dev, size, &jfc->buf); + if (ret) { + dev_err(dev->dev, "failed to alloc buffer for jfc.\n"); + return ret; + } + + ret = udma_alloc_sw_db(dev, &jfc->db, UDMA_JFC_TYPE_DB); + if (ret) { + dev_err(dev->dev, "failed to alloc sw db for jfc(%u).\n", jfc->jfcn); + udma_k_free_buf(dev, size, &jfc->buf); + return -ENOMEM; + } + + return ret; +} + +static void udma_free_jfc_buf(struct udma_dev *dev, struct udma_jfc *jfc) +{ + struct udma_context *uctx; + uint32_t size; + + if (jfc->buf.kva) { + size = jfc->buf.entry_size * jfc->buf.entry_cnt; + udma_k_free_buf(dev, size, &jfc->buf); + } else if (jfc->buf.umem) { + uctx = to_udma_context(jfc->base.uctx); + unpin_queue_addr(jfc->buf.umem); + } + + if (jfc->db.page) { + uctx = to_udma_context(jfc->base.uctx); + udma_unpin_sw_db(uctx, &jfc->db); + } else if (jfc->db.kpage) { + udma_free_sw_db(dev, &jfc->db); + } +} + +int udma_post_create_jfc_mbox(struct udma_dev *dev, struct udma_jfc *jfc) +{ + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + int ret; + + mailbox = udma_alloc_cmd_mailbox(dev); + if (!mailbox) { + dev_err(dev->dev, "failed to alloc mailbox for JFCC.\n"); + return -ENOMEM; + } + + if (jfc->mode == UDMA_STARS_JFC_TYPE || jfc->mode == UDMA_CCU_JFC_TYPE || + jfc->mode == UDMA_KERNEL_STARS_JFC_TYPE) + jfc->stars_en = true; + udma_construct_jfc_ctx(dev, jfc, (struct udma_jfc_ctx *)mailbox->buf); + + mbox_attr.tag = jfc->jfcn; + mbox_attr.op = UDMA_CMD_CREATE_JFC_CONTEXT; + ret = udma_post_mbox(dev, mailbox, &mbox_attr); + if (ret) + dev_err(dev->dev, + "failed to post create JFC mailbox, ret = %d.\n", ret); + + udma_free_cmd_mailbox(dev, mailbox); + + return ret; +} + +static int udma_verify_stars_jfc_param(struct udma_dev *dev, + struct udma_ex_jfc_addr *jfc_addr, + struct udma_jfc *jfc) +{ + uint32_t size; + + if (!jfc_addr->cq_addr) { + dev_err(dev->dev, "CQE addr is wrong.\n"); + return -ENOMEM; + } + if (!jfc_addr->cq_len) { + dev_err(dev->dev, "CQE len is wrong.\n"); + return -EINVAL; + } + + size = jfc->buf.entry_cnt * dev->caps.cqe_size; + + if (size != jfc_addr->cq_len) { + dev_err(dev->dev, "cqe buff size is wrong, buf size = %u.\n", size); + return -EINVAL; + } + + return 0; +} + +static int udma_get_stars_jfc_buf(struct udma_dev *dev, struct udma_jfc *jfc) +{ + struct udma_ex_jfc_addr *jfc_addr = &dev->cq_addr_array[jfc->mode]; + int ret; + + jfc->tid = dev->tid; + + ret = udma_verify_stars_jfc_param(dev, jfc_addr, jfc); + if (ret) + return ret; + + jfc->buf.addr = (dma_addr_t)(uintptr_t)jfc_addr->cq_addr; + + ret = udma_alloc_sw_db(dev, &jfc->db, UDMA_JFC_TYPE_DB); + if (ret) { + dev_err(dev->dev, "failed to alloc sw db for jfc(%u).\n", jfc->jfcn); + return -ENOMEM; + } + + return ret; +} + +static int udma_create_stars_jfc(struct udma_dev *dev, + struct udma_jfc *jfc, + struct ubcore_jfc_cfg *cfg, + struct ubcore_udata *udata, + struct udma_create_jfc_ucmd *ucmd) +{ + unsigned long flags_store; + unsigned long flags_erase; + int ret; + + ret = udma_id_alloc_auto_grow(dev, &dev->jfc_table.ida_table, &jfc->jfcn); + if (ret) { + dev_err(dev->dev, "failed to alloc id for stars JFC.\n"); + return -ENOMEM; + } + + udma_init_jfc_param(cfg, jfc); + xa_lock_irqsave(&dev->jfc_table.xa, flags_store); + ret = xa_err(__xa_store(&dev->jfc_table.xa, jfc->jfcn, jfc, GFP_ATOMIC)); + xa_unlock_irqrestore(&dev->jfc_table.xa, flags_store); + if (ret) { + dev_err(dev->dev, + "failed to stored stars jfc id to jfc_table, jfcn: %u.\n", + jfc->jfcn); + goto err_store_jfcn; + } + + ret = udma_get_stars_jfc_buf(dev, jfc); + if (ret) + goto err_alloc_cqc; + + ret = udma_post_create_jfc_mbox(dev, jfc); + if (ret) + goto err_get_jfc_buf; + + refcount_set(&jfc->event_refcount, 1); + init_completion(&jfc->event_comp); + + if (dfx_switch) + udma_dfx_store_id(dev, &dev->dfx_info->jfc, jfc->jfcn, "jfc"); + + return 0; + +err_get_jfc_buf: + udma_free_sw_db(dev, &jfc->db); +err_alloc_cqc: + xa_lock_irqsave(&dev->jfc_table.xa, flags_erase); + __xa_erase(&dev->jfc_table.xa, jfc->jfcn); + xa_unlock_irqrestore(&dev->jfc_table.xa, flags_erase); +err_store_jfcn: + udma_id_free(&dev->jfc_table.ida_table, jfc->jfcn); + + return -ENOMEM; +} + +struct ubcore_jfc *udma_create_jfc(struct ubcore_device *ubcore_dev, + struct ubcore_jfc_cfg *cfg, + struct ubcore_udata *udata) +{ + struct udma_dev *dev = to_udma_dev(ubcore_dev); + struct udma_create_jfc_ucmd ucmd = {}; + unsigned long flags_store; + unsigned long flags_erase; + struct udma_jfc *jfc; + int ret; + + jfc = kzalloc(sizeof(struct udma_jfc), GFP_KERNEL); + if (!jfc) + return NULL; + + if (udata) { + ret = udma_get_cmd_from_user(&ucmd, dev, udata, jfc); + if (ret) + goto err_get_cmd; + } else { + jfc->arm_sn = 1; + jfc->buf.entry_cnt = cfg->depth ? roundup_pow_of_two(cfg->depth) : cfg->depth; + } + + ret = udma_check_jfc_cfg(dev, jfc, cfg); + if (ret) + goto err_get_cmd; + + if (jfc->mode == UDMA_STARS_JFC_TYPE || jfc->mode == UDMA_CCU_JFC_TYPE) { + if (udma_create_stars_jfc(dev, jfc, cfg, udata, &ucmd)) + goto err_get_cmd; + return &jfc->base; + } + + ret = udma_id_alloc_auto_grow(dev, &dev->jfc_table.ida_table, + &jfc->jfcn); + if (ret) + goto err_get_cmd; + + udma_init_jfc_param(cfg, jfc); + + xa_lock_irqsave(&dev->jfc_table.xa, flags_store); + ret = xa_err(__xa_store(&dev->jfc_table.xa, jfc->jfcn, jfc, GFP_ATOMIC)); + xa_unlock_irqrestore(&dev->jfc_table.xa, flags_store); + if (ret) { + dev_err(dev->dev, + "failed to stored jfc id to jfc_table, jfcn: %u.\n", + jfc->jfcn); + goto err_store_jfcn; + } + + ret = udma_get_jfc_buf(dev, &ucmd, udata, jfc); + if (ret) + goto err_get_jfc_buf; + + ret = udma_post_create_jfc_mbox(dev, jfc); + if (ret) + goto err_alloc_cqc; + + refcount_set(&jfc->event_refcount, 1); + init_completion(&jfc->event_comp); + + if (dfx_switch) + udma_dfx_store_id(dev, &dev->dfx_info->jfc, jfc->jfcn, "jfc"); + + return &jfc->base; + +err_alloc_cqc: + jfc->base.uctx = (udata == NULL ? NULL : udata->uctx); + udma_free_jfc_buf(dev, jfc); +err_get_jfc_buf: + xa_lock_irqsave(&dev->jfc_table.xa, flags_erase); + __xa_erase(&dev->jfc_table.xa, jfc->jfcn); + xa_unlock_irqrestore(&dev->jfc_table.xa, flags_erase); +err_store_jfcn: + udma_id_free(&dev->jfc_table.ida_table, jfc->jfcn); +err_get_cmd: + kfree(jfc); + return NULL; +} + int udma_jfc_completion(struct notifier_block *nb, unsigned long jfcn, void *data) { diff --git a/drivers/ub/urma/hw/udma/udma_jfc.h b/drivers/ub/urma/hw/udma/udma_jfc.h index 8cb7271739d7..eba31242050c 100644 --- a/drivers/ub/urma/hw/udma/udma_jfc.h +++ b/drivers/ub/urma/hw/udma/udma_jfc.h @@ -7,10 +7,43 @@ #include "udma_dev.h" #include "udma_ctx.h" +#define UDMA_JFC_DEPTH_MIN 64 #define UDMA_JFC_DEPTH_SHIFT_BASE 6 +#define CQE_VA_L_OFFSET 12 +#define CQE_VA_H_OFFSET 32 + +#define UDMA_DB_L_OFFSET 6 +#define UDMA_DB_H_OFFSET 38 + +#define UDMA_STARS_SWITCH 1 + +enum udma_jfc_state { + UDMA_JFC_STATE_INVALID, + UDMA_JFC_STATE_VALID, + UDMA_JFC_STATE_ERROR, +}; + +enum udma_armed_jfc { + UDMA_CTX_NO_ARMED, + UDMA_CTX_ALWAYS_ARMED, + UDMA_CTX_REG_NEXT_CEQE, + UDMA_CTX_REG_NEXT_SOLICITED_CEQE, +}; + +enum udma_record_db { + UDMA_NO_RECORD_EN, + UDMA_RECORD_EN, +}; + +enum udma_cq_cnt_mode { + UDMA_CQE_CNT_MODE_BY_COUNT, + UDMA_CQE_CNT_MODE_BY_CI_PI_GAP, +}; + struct udma_jfc { struct ubcore_jfc base; + struct udma_context *ctx; uint32_t jfcn; uint32_t ceqn; uint32_t tid; @@ -103,6 +136,9 @@ static inline struct udma_jfc *to_udma_jfc(struct ubcore_jfc *jfc) return container_of(jfc, struct udma_jfc, base); } +struct ubcore_jfc *udma_create_jfc(struct ubcore_device *ubcore_dev, + struct ubcore_jfc_cfg *cfg, + struct ubcore_udata *udata); int udma_jfc_completion(struct notifier_block *nb, unsigned long jfcn, void *data); diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index c5911b027ba6..72457ae13878 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -20,6 +20,7 @@ #include "udma_eq.h" #include "udma_segment.h" #include "udma_jfs.h" +#include "udma_jfc.h" #include "udma_jfr.h" #include "udma_cmd.h" #include "udma_ctx.h" @@ -31,6 +32,7 @@ #include "udma_common.h" #include "udma_ctrlq_tp.h" +bool cqe_mode = true; bool is_rmmod; static DEFINE_MUTEX(udma_reset_mutex); uint32_t jfr_sleep_time = 1000; @@ -176,6 +178,7 @@ static struct ubcore_ops g_dev_ops = { .unregister_seg = udma_unregister_seg, .import_seg = udma_import_seg, .unimport_seg = udma_unimport_seg, + .create_jfc = udma_create_jfc, .create_jfs = udma_create_jfs, .query_jfs = udma_query_jfs, .destroy_jfs = udma_destroy_jfs, @@ -1095,6 +1098,9 @@ module_init(udma_init); module_exit(udma_exit); MODULE_LICENSE("GPL"); +module_param(cqe_mode, bool, 0444); +MODULE_PARM_DESC(cqe_mode, "Set cqe reporting mode, default: 1 (0:BY_COUNT, 1:BY_CI_PI_GAP)"); + module_param(jfr_sleep_time, uint, 0444); MODULE_PARM_DESC(jfr_sleep_time, "Set the destroy jfr sleep time, default: 1000 us.\n"); -- Gitee From 91945efc8531def97a3f9f6fa511841b6e6f10b4 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 16:06:10 +0800 Subject: [PATCH 073/103] ub: udma: Support destroy jfc. commit 10408c91c73de7803de5f335804d8c85c6b6ddcf openEuler This patch adds the ability to destroy jfc, During the destruction process, driver will destroy jfc context and send it to the hardware. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_jfc.c | 105 ++++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jfc.h | 1 + drivers/ub/urma/hw/udma/udma_main.c | 1 + 3 files changed, 107 insertions(+) diff --git a/drivers/ub/urma/hw/udma/udma_jfc.c b/drivers/ub/urma/hw/udma/udma_jfc.c index 9d86d9003593..bfbf479ec06f 100644 --- a/drivers/ub/urma/hw/udma/udma_jfc.c +++ b/drivers/ub/urma/hw/udma/udma_jfc.c @@ -399,6 +399,111 @@ struct ubcore_jfc *udma_create_jfc(struct ubcore_device *ubcore_dev, return NULL; } +static int udma_post_destroy_jfc_mbox(struct udma_dev *dev, uint32_t jfcn) +{ + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + struct udma_jfc_ctx *ctx; + int ret; + + mailbox = udma_alloc_cmd_mailbox(dev); + if (!mailbox) { + dev_err(dev->dev, "failed to alloc mailbox for JFCC.\n"); + return -ENOMEM; + } + + ctx = (struct udma_jfc_ctx *)mailbox->buf; + + mbox_attr.tag = jfcn; + mbox_attr.op = UDMA_CMD_DESTROY_JFC_CONTEXT; + ret = udma_post_mbox(dev, mailbox, &mbox_attr); + if (ret) + dev_err(dev->dev, + "failed to post destroy JFC mailbox, ret = %d.\n", + ret); + + udma_free_cmd_mailbox(dev, mailbox); + + return ret; +} + +static int udma_query_jfc_destroy_done(struct udma_dev *dev, uint32_t jfcn) +{ + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + struct udma_jfc_ctx *jfc_ctx; + int ret; + + mbox_attr.tag = jfcn; + mbox_attr.op = UDMA_CMD_QUERY_JFC_CONTEXT; + mailbox = udma_mailbox_query_ctx(dev, &mbox_attr); + if (!mailbox) + return -ENOMEM; + + jfc_ctx = (struct udma_jfc_ctx *)mailbox->buf; + ret = jfc_ctx->pi == jfc_ctx->wr_cqe_idx ? 0 : -EAGAIN; + + jfc_ctx->cqe_token_value = 0; + jfc_ctx->remote_token_value = 0; + udma_free_cmd_mailbox(dev, mailbox); + + return ret; +} + +static int udma_destroy_and_flush_jfc(struct udma_dev *dev, uint32_t jfcn) +{ +#define QUERY_MAX_TIMES 5 + uint32_t wait_times = 0; + int ret; + + ret = udma_post_destroy_jfc_mbox(dev, jfcn); + if (ret) { + dev_err(dev->dev, "failed to post mbox to destroy jfc, id: %u.\n", jfcn); + return ret; + } + + while (true) { + if (udma_query_jfc_destroy_done(dev, jfcn) == 0) + return 0; + if (wait_times > QUERY_MAX_TIMES) + break; + msleep(1 << wait_times); + wait_times++; + } + dev_err(dev->dev, "jfc flush timed out, id: %u.\n", jfcn); + + return -EFAULT; +} + +int udma_destroy_jfc(struct ubcore_jfc *jfc) +{ + struct udma_dev *dev = to_udma_dev(jfc->ub_dev); + struct udma_jfc *ujfc = to_udma_jfc(jfc); + unsigned long flags; + int ret; + + ret = udma_destroy_and_flush_jfc(dev, ujfc->jfcn); + if (ret) + return ret; + + xa_lock_irqsave(&dev->jfc_table.xa, flags); + __xa_erase(&dev->jfc_table.xa, ujfc->jfcn); + xa_unlock_irqrestore(&dev->jfc_table.xa, flags); + + if (refcount_dec_and_test(&ujfc->event_refcount)) + complete(&ujfc->event_comp); + wait_for_completion(&ujfc->event_comp); + + if (dfx_switch) + udma_dfx_delete_id(dev, &dev->dfx_info->jfc, jfc->id); + + udma_free_jfc_buf(dev, ujfc); + udma_id_free(&dev->jfc_table.ida_table, ujfc->jfcn); + kfree(ujfc); + + return 0; +} + int udma_jfc_completion(struct notifier_block *nb, unsigned long jfcn, void *data) { diff --git a/drivers/ub/urma/hw/udma/udma_jfc.h b/drivers/ub/urma/hw/udma/udma_jfc.h index eba31242050c..21f4016a42cd 100644 --- a/drivers/ub/urma/hw/udma/udma_jfc.h +++ b/drivers/ub/urma/hw/udma/udma_jfc.h @@ -139,6 +139,7 @@ static inline struct udma_jfc *to_udma_jfc(struct ubcore_jfc *jfc) struct ubcore_jfc *udma_create_jfc(struct ubcore_device *ubcore_dev, struct ubcore_jfc_cfg *cfg, struct ubcore_udata *udata); +int udma_destroy_jfc(struct ubcore_jfc *jfc); int udma_jfc_completion(struct notifier_block *nb, unsigned long jfcn, void *data); diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 72457ae13878..d1d45200b585 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -179,6 +179,7 @@ static struct ubcore_ops g_dev_ops = { .import_seg = udma_import_seg, .unimport_seg = udma_unimport_seg, .create_jfc = udma_create_jfc, + .destroy_jfc = udma_destroy_jfc, .create_jfs = udma_create_jfs, .query_jfs = udma_query_jfs, .destroy_jfs = udma_destroy_jfs, -- Gitee From 64f89f3883ec6c7bb34e21ce8f2ac897d380f188 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 16:35:29 +0800 Subject: [PATCH 074/103] ub: udma: Support create jetty. commit 4d0a86f5836c68cb1303313cd3b7eed1876864b2 openEuler This patch adds the ability to create jetty. During the creation process, driver will create jetty context and send it to the hardware. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_jetty.c | 300 +++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jetty.h | 3 + drivers/ub/urma/hw/udma/udma_main.c | 1 + 3 files changed, 304 insertions(+) diff --git a/drivers/ub/urma/hw/udma/udma_jetty.c b/drivers/ub/urma/hw/udma/udma_jetty.c index b012010c0e74..63e5eae5f7b7 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.c +++ b/drivers/ub/urma/hw/udma/udma_jetty.c @@ -18,6 +18,144 @@ bool well_known_jetty_pgsz_check = true; +static int udma_get_user_jetty_cmd(struct udma_dev *dev, struct udma_jetty *jetty, + struct ubcore_udata *udata, + struct udma_create_jetty_ucmd *ucmd) +{ + struct udma_context *uctx; + unsigned long byte; + + if (!udata) { + jetty->sq.jetty_type = (enum udma_jetty_type)UDMA_URMA_NORMAL_JETTY_TYPE; + return 0; + } + + if (!udata->udrv_data) { + dev_err(dev->dev, "jetty udata udrv_data is null.\n"); + return -EINVAL; + } + + if (!udata->udrv_data->in_addr || udata->udrv_data->in_len < sizeof(*ucmd)) { + dev_err(dev->dev, "jetty in_len (%u) or addr is invalid.\n", + udata->udrv_data->in_len); + return -EINVAL; + } + + byte = copy_from_user(ucmd, (void *)(uintptr_t)udata->udrv_data->in_addr, + sizeof(*ucmd)); + if (byte) { + dev_err(dev->dev, + "failed to copy jetty udata, byte = %lu.\n", byte); + return -EFAULT; + } + + uctx = to_udma_context(udata->uctx); + jetty->sq.tid = uctx->tid; + jetty->jetty_addr = ucmd->jetty_addr; + jetty->pi_type = ucmd->pi_type; + jetty->sq.jetty_type = (enum udma_jetty_type)ucmd->jetty_type; + jetty->sq.non_pin = ucmd->non_pin; + + return 0; +} + +static int udma_get_jetty_buf(struct udma_dev *dev, struct udma_jetty *jetty, + struct ubcore_udata *udata, + struct ubcore_jetty_cfg *cfg, + struct udma_create_jetty_ucmd *ucmd) +{ + struct ubcore_jfs_cfg jfs_cfg = { + .depth = cfg->jfs_depth, + .trans_mode = cfg->trans_mode, + .priority = cfg->priority, + .max_sge = cfg->max_send_sge, + .max_rsge = cfg->max_send_rsge, + .max_inline_data = cfg->max_inline_data, + .rnr_retry = cfg->rnr_retry, + .err_timeout = cfg->err_timeout, + .jfs_context = cfg->jetty_context, + .jfc = cfg->send_jfc, + }; + int ret; + + jfs_cfg.flag.bs.lock_free = cfg->flag.bs.lock_free; + if (!udata) + jetty->jetty_addr = (uintptr_t)&jetty->sq; + + jetty->jfr = to_udma_jfr(cfg->jfr); + + ret = udata ? udma_alloc_u_sq_buf(dev, &jetty->sq, ucmd) : + udma_alloc_k_sq_buf(dev, &jetty->sq, &jfs_cfg); + if (ret) { + dev_err(dev->dev, "failed to get sq buf, ret = %d.\n", ret); + return ret; + } + jetty->sq.trans_mode = jfs_cfg.trans_mode; + jetty->sq.is_jetty = true; + + return ret; +} + +static void udma_init_jettyc(struct udma_dev *dev, struct ubcore_jetty_cfg *cfg, + struct udma_jetty *jetty, void *mb_buf) +{ + struct udma_jetty_ctx *ctx = (struct udma_jetty_ctx *)mb_buf; + struct udma_jfc *receive_jfc = to_udma_jfc(cfg->recv_jfc); + uint8_t i; + + ctx->state = JETTY_READY; + ctx->jfs_mode = JETTY; + ctx->type = to_udma_type(cfg->trans_mode); + ctx->sl = dev->udma_sl[UDMA_DEFAULT_SL_NUM]; + if (ctx->type == JETTY_RM || ctx->type == JETTY_RC) { + for (i = 0; i < dev->udma_total_sl_num; i++) { + if (cfg->priority == dev->udma_sl[i]) { + ctx->sl = cfg->priority; + break; + } + } + } else if (ctx->type == JETTY_UM) { + ctx->sl = dev->unic_sl[UDMA_DEFAULT_SL_NUM]; + for (i = 0; i < dev->unic_sl_num; i++) { + if (cfg->priority == dev->unic_sl[i]) { + ctx->sl = cfg->priority; + break; + } + } + } + ctx->sqe_base_addr_l = (jetty->sq.buf.addr >> SQE_VA_L_OFFSET) & + (uint32_t)SQE_VA_L_VALID_BIT; + ctx->sqe_base_addr_h = (jetty->sq.buf.addr >> SQE_VA_H_OFFSET) & + (uint32_t)SQE_VA_H_VALID_BIT; + ctx->sqe_token_id_l = jetty->sq.tid & (uint32_t)SQE_TOKEN_ID_L_MASK; + ctx->sqe_token_id_h = (jetty->sq.tid >> SQE_TOKEN_ID_H_OFFSET) & + (uint32_t)SQE_TOKEN_ID_H_MASK; + ctx->sqe_bb_shift = ilog2(roundup_pow_of_two(jetty->sq.buf.entry_cnt)); + ctx->tx_jfcn = cfg->send_jfc->id; + ctx->ta_timeout = to_ta_timeout(cfg->err_timeout); + + if (!!(dev->caps.feature & UDMA_CAP_FEATURE_RNR_RETRY)) + ctx->rnr_retry_num = cfg->rnr_retry; + + ctx->jfrn_l = jetty->jfr->rq.id; + ctx->jfrn_h = jetty->jfr->rq.id >> JETTY_CTX_JFRN_H_OFFSET; + ctx->rx_jfcn = cfg->recv_jfc->id; + ctx->user_data_l = jetty->jetty_addr; + ctx->user_data_h = jetty->jetty_addr >> UDMA_USER_DATA_H_OFFSET; + ctx->seid_idx = cfg->eid_index; + ctx->pi_type = jetty->pi_type ? 1 : 0; + + if (!!(dev->caps.feature & UDMA_CAP_FEATURE_JFC_INLINE)) + ctx->cqe_ie = receive_jfc->inline_en; + + ctx->err_mode = cfg->flag.bs.error_suspend; + ctx->cmp_odr = cfg->flag.bs.outorder_comp; + ctx->avail_sgmt_ost = AVAIL_SGMT_OST_INIT; + ctx->sqe_pld_tokenid = jetty->sq.tid & (uint32_t)SQE_PLD_TOKEN_ID_MASK; + ctx->next_send_ssn = get_random_u16(); + ctx->next_rcv_ssn = ctx->next_send_ssn; +} + static int udma_specify_rsvd_jetty_id(struct udma_dev *udma_dev, uint32_t cfg_id) { struct udma_ida *ida_table = &udma_dev->rsvd_jetty_ida_table; @@ -244,6 +382,114 @@ int alloc_jetty_id(struct udma_dev *udma_dev, struct udma_jetty_queue *sq, return ret; } +static void free_jetty_id(struct udma_dev *udma_dev, + struct udma_jetty *udma_jetty, bool is_grp) +{ + if (udma_jetty->sq.id < udma_dev->caps.jetty.start_idx) + udma_id_free(&udma_dev->rsvd_jetty_ida_table, udma_jetty->sq.id); + else + udma_adv_id_free(&udma_dev->jetty_table.bitmap_table, + udma_jetty->sq.id, false); +} + +static void udma_dfx_store_jetty_id(struct udma_dev *udma_dev, + struct udma_jetty *udma_jetty) +{ + struct udma_dfx_jetty *jetty; + int ret; + + jetty = (struct udma_dfx_jetty *)xa_load(&udma_dev->dfx_info->jetty.table, + udma_jetty->sq.id); + if (jetty) { + dev_warn(udma_dev->dev, "jetty_id(%u) already exists in dfx.\n", + udma_jetty->sq.id); + return; + } + + jetty = kzalloc(sizeof(*jetty), GFP_KERNEL); + if (!jetty) + return; + + jetty->id = udma_jetty->sq.id; + jetty->jfs_depth = udma_jetty->sq.buf.entry_cnt / udma_jetty->sq.sqe_bb_cnt; + + write_lock(&udma_dev->dfx_info->jetty.rwlock); + ret = xa_err(xa_store(&udma_dev->dfx_info->jetty.table, udma_jetty->sq.id, + jetty, GFP_KERNEL)); + if (ret) { + write_unlock(&udma_dev->dfx_info->jetty.rwlock); + dev_err(udma_dev->dev, "store jetty_id(%u) to jetty_table failed in dfx.\n", + udma_jetty->sq.id); + kfree(jetty); + return; + } + + ++udma_dev->dfx_info->jetty.cnt; + write_unlock(&udma_dev->dfx_info->jetty.rwlock); +} + +static int +udma_alloc_jetty_sq(struct udma_dev *udma_dev, struct udma_jetty *jetty, + struct ubcore_jetty_cfg *cfg, struct ubcore_udata *udata) +{ + struct udma_create_jetty_ucmd ucmd = {}; + int ret; + + ret = udma_get_user_jetty_cmd(udma_dev, jetty, udata, &ucmd); + if (ret) { + dev_err(udma_dev->dev, + "udma get user jetty ucmd failed, ret = %d.\n", ret); + return ret; + } + + ret = alloc_jetty_id(udma_dev, &jetty->sq, cfg->id, cfg->jetty_grp); + if (ret) { + dev_err(udma_dev->dev, "alloc jetty id failed, ret = %d.\n", ret); + return ret; + } + jetty->ubcore_jetty.jetty_id.id = jetty->sq.id; + jetty->ubcore_jetty.jetty_cfg = *cfg; + + ret = udma_get_jetty_buf(udma_dev, jetty, udata, cfg, &ucmd); + if (ret) + free_jetty_id(udma_dev, jetty, !!cfg->jetty_grp); + + return ret; +} + +static void udma_free_jetty_id_buf(struct udma_dev *udma_dev, + struct udma_jetty *udma_jetty, + struct ubcore_jetty_cfg *cfg) +{ + udma_free_sq_buf(udma_dev, &udma_jetty->sq); + free_jetty_id(udma_dev, udma_jetty, !!cfg->jetty_grp); +} + +static int udma_create_hw_jetty_ctx(struct udma_dev *dev, struct udma_jetty *udma_jetty, + struct ubcore_jetty_cfg *cfg) +{ + struct ubase_mbx_attr attr = {}; + struct udma_jetty_ctx ctx = {}; + int ret; + + if (cfg->priority >= UDMA_MAX_PRIORITY) { + dev_err(dev->dev, "kernel mode jetty priority is out of range, priority is %u.\n", + cfg->priority); + return -EINVAL; + } + + udma_init_jettyc(dev, cfg, udma_jetty, &ctx); + + attr.tag = udma_jetty->sq.id; + attr.op = UDMA_CMD_CREATE_JFS_CONTEXT; + ret = post_mailbox_update_ctx(dev, &ctx, sizeof(ctx), &attr); + if (ret) + dev_err(dev->dev, + "post mailbox create jetty ctx failed, ret = %d.\n", ret); + + return ret; +} + void udma_set_query_flush_time(struct udma_jetty_queue *sq, uint8_t err_timeout) { #define UDMA_TA_TIMEOUT_MAX_INDEX 3 @@ -262,6 +508,60 @@ void udma_set_query_flush_time(struct udma_jetty_queue *sq, uint8_t err_timeout) sq->ta_timeout = time[index]; } +struct ubcore_jetty *udma_create_jetty(struct ubcore_device *ub_dev, + struct ubcore_jetty_cfg *cfg, + struct ubcore_udata *udata) +{ + struct udma_dev *udma_dev = to_udma_dev(ub_dev); + struct udma_jetty *udma_jetty; + int ret; + + udma_jetty = kzalloc(sizeof(*udma_jetty), GFP_KERNEL); + if (!udma_jetty) + return NULL; + + ret = udma_alloc_jetty_sq(udma_dev, udma_jetty, cfg, udata); + if (ret) { + dev_err(udma_dev->dev, + "udma alloc jetty id buf failed, ret = %d.\n", ret); + goto err_alloc_jetty; + } + + ret = xa_err(xa_store(&udma_dev->jetty_table.xa, udma_jetty->sq.id, + &udma_jetty->sq, GFP_KERNEL)); + if (ret) { + dev_err(udma_dev->dev, + "store jetty sq(%u) to sq table failed, ret = %d.\n", + udma_jetty->sq.id, ret); + goto err_store_jetty_sq; + } + + ret = udma_create_hw_jetty_ctx(udma_dev, udma_jetty, cfg); + if (ret) { + dev_err(udma_dev->dev, + "post mailbox create jetty ctx failed, ret = %d.\n", ret); + goto err_create_hw_jetty; + } + + udma_set_query_flush_time(&udma_jetty->sq, cfg->err_timeout); + udma_jetty->sq.state = UBCORE_JETTY_STATE_READY; + refcount_set(&udma_jetty->ae_refcount, 1); + init_completion(&udma_jetty->ae_comp); + + if (dfx_switch) + udma_dfx_store_jetty_id(udma_dev, udma_jetty); + + return &udma_jetty->ubcore_jetty; +err_create_hw_jetty: + xa_erase(&udma_dev->jetty_table.xa, udma_jetty->sq.id); +err_store_jetty_sq: + udma_free_jetty_id_buf(udma_dev, udma_jetty, cfg); +err_alloc_jetty: + kfree(udma_jetty); + + return NULL; +} + int udma_destroy_hw_jetty_ctx(struct udma_dev *dev, uint32_t jetty_id) { struct ubase_mbx_attr attr = {}; diff --git a/drivers/ub/urma/hw/udma/udma_jetty.h b/drivers/ub/urma/hw/udma/udma_jetty.h index 63d7073b8631..0c6d409520eb 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.h +++ b/drivers/ub/urma/hw/udma/udma_jetty.h @@ -221,6 +221,9 @@ static inline struct udma_jetty *to_udma_jetty_from_queue(struct udma_jetty_queu int alloc_jetty_id(struct udma_dev *udma_dev, struct udma_jetty_queue *sq, uint32_t cfg_id, struct ubcore_jetty_group *jetty_grp); +struct ubcore_jetty *udma_create_jetty(struct ubcore_device *ub_dev, + struct ubcore_jetty_cfg *cfg, + struct ubcore_udata *udata); int udma_destroy_hw_jetty_ctx(struct udma_dev *dev, uint32_t jetty_id); void udma_set_query_flush_time(struct udma_jetty_queue *sq, uint8_t err_timeout); int udma_modify_and_destroy_jetty(struct udma_dev *dev, diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index d1d45200b585..6d2832081630 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -187,6 +187,7 @@ static struct ubcore_ops g_dev_ops = { .destroy_jfr = udma_destroy_jfr, .destroy_jfr_batch = udma_destroy_jfr_batch, .query_jfr = udma_query_jfr, + .create_jetty = udma_create_jetty, .query_jetty = udma_query_jetty, }; -- Gitee From 02643e0417634cbf5a490e62783216ac53ea12a7 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 16:50:18 +0800 Subject: [PATCH 075/103] ub: udma: Support destroy jetty. commit 70df47775eb5fec27c8b0fccfadeb97d9f0e210a openEuler This patch adds the ability to destroy jetty, During the destruction process, driver will destroy jetty context and send it to the hardware. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_jetty.c | 46 ++++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jetty.h | 1 + drivers/ub/urma/hw/udma/udma_main.c | 1 + 3 files changed, 48 insertions(+) diff --git a/drivers/ub/urma/hw/udma/udma_jetty.c b/drivers/ub/urma/hw/udma/udma_jetty.c index 63e5eae5f7b7..bc35512c57b6 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.c +++ b/drivers/ub/urma/hw/udma/udma_jetty.c @@ -761,3 +761,49 @@ int udma_modify_and_destroy_jetty(struct udma_dev *dev, return 0; } + +static void udma_free_jetty(struct ubcore_jetty *jetty) +{ + struct udma_dev *udma_dev = to_udma_dev(jetty->ub_dev); + struct udma_jetty *udma_jetty = to_udma_jetty(jetty); + + if (dfx_switch) + udma_dfx_delete_id(udma_dev, &udma_dev->dfx_info->jetty, + udma_jetty->sq.id); + + xa_erase(&udma_dev->jetty_table.xa, udma_jetty->sq.id); + + if (refcount_dec_and_test(&udma_jetty->ae_refcount)) + complete(&udma_jetty->ae_comp); + wait_for_completion(&udma_jetty->ae_comp); + + udma_free_sq_buf(udma_dev, &udma_jetty->sq); + free_jetty_id(udma_dev, udma_jetty, !!udma_jetty->sq.jetty_grp); + kfree(udma_jetty); +} + +int udma_destroy_jetty(struct ubcore_jetty *jetty) +{ + struct udma_dev *udma_dev = to_udma_dev(jetty->ub_dev); + struct udma_jetty *udma_jetty = to_udma_jetty(jetty); + int ret; + + if (!udma_jetty->ue_rx_closed && udma_close_ue_rx(udma_dev, true, true, false, 0)) { + dev_err(udma_dev->dev, "close ue rx failed when destroying jetty.\n"); + return -EINVAL; + } + + ret = udma_modify_and_destroy_jetty(udma_dev, &udma_jetty->sq); + if (ret) { + dev_err(udma_dev->dev, "udma modify error and destroy jetty failed, id: %u.\n", + jetty->jetty_id.id); + if (!udma_jetty->ue_rx_closed) + udma_open_ue_rx(udma_dev, true, true, false, 0); + return ret; + } + + udma_free_jetty(jetty); + udma_open_ue_rx(udma_dev, true, true, false, 0); + + return 0; +} diff --git a/drivers/ub/urma/hw/udma/udma_jetty.h b/drivers/ub/urma/hw/udma/udma_jetty.h index 0c6d409520eb..a37c9a9ff54f 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.h +++ b/drivers/ub/urma/hw/udma/udma_jetty.h @@ -224,6 +224,7 @@ int alloc_jetty_id(struct udma_dev *udma_dev, struct udma_jetty_queue *sq, struct ubcore_jetty *udma_create_jetty(struct ubcore_device *ub_dev, struct ubcore_jetty_cfg *cfg, struct ubcore_udata *udata); +int udma_destroy_jetty(struct ubcore_jetty *jetty); int udma_destroy_hw_jetty_ctx(struct udma_dev *dev, uint32_t jetty_id); void udma_set_query_flush_time(struct udma_jetty_queue *sq, uint8_t err_timeout); int udma_modify_and_destroy_jetty(struct udma_dev *dev, diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 6d2832081630..a1f3bcb5dde3 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -189,6 +189,7 @@ static struct ubcore_ops g_dev_ops = { .query_jfr = udma_query_jfr, .create_jetty = udma_create_jetty, .query_jetty = udma_query_jetty, + .destroy_jetty = udma_destroy_jetty, }; static void udma_uninit_group_table(struct udma_dev *dev, struct udma_group_table *table) -- Gitee From 215b0c5601c20de9b1914b9410b8a945ff61a3fb Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 17:05:48 +0800 Subject: [PATCH 076/103] ub: udma: Support create jetty group. commit fdebd311c4b97415cdc307c322944dbc691f32d0 openEuler This patch adds the ability to create jetty group. During The creation process, driver will create jetty group context and send it to the hardware. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_jetty.c | 112 +++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jetty.h | 3 + drivers/ub/urma/hw/udma/udma_main.c | 1 + 3 files changed, 116 insertions(+) diff --git a/drivers/ub/urma/hw/udma/udma_jetty.c b/drivers/ub/urma/hw/udma/udma_jetty.c index bc35512c57b6..7cbffa81bf1d 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.c +++ b/drivers/ub/urma/hw/udma/udma_jetty.c @@ -807,3 +807,115 @@ int udma_destroy_jetty(struct ubcore_jetty *jetty) return 0; } + +static int udma_alloc_group_start_id(struct udma_dev *udma_dev, + struct udma_group_bitmap *bitmap_table, + uint32_t *start_jetty_id) +{ + int ret; + + ret = udma_adv_id_alloc(udma_dev, bitmap_table, start_jetty_id, true, + bitmap_table->grp_next); + if (ret) { + ret = udma_adv_id_alloc(udma_dev, bitmap_table, start_jetty_id, + true, bitmap_table->min); + if (ret) + return ret; + } + + bitmap_table->grp_next = (*start_jetty_id + NUM_JETTY_PER_GROUP) > + bitmap_table->max ? bitmap_table->min : + (*start_jetty_id + NUM_JETTY_PER_GROUP); + + return 0; +} + +static int udma_alloc_jetty_grp_id(struct udma_dev *udma_dev, + struct udma_jetty_grp *jetty_grp) +{ + int ret; + + ret = udma_alloc_group_start_id(udma_dev, &udma_dev->jetty_table.bitmap_table, + &jetty_grp->start_jetty_id); + if (ret) { + dev_err(udma_dev->dev, + "alloc jetty id for grp failed, ret = %d.\n", ret); + return ret; + } + + ret = udma_id_alloc_auto_grow(udma_dev, &udma_dev->jetty_grp_table.ida_table, + &jetty_grp->jetty_grp_id); + if (ret) { + dev_err(udma_dev->dev, + "alloc jetty grp id failed, ret = %d.\n", ret); + udma_adv_id_free(&udma_dev->jetty_table.bitmap_table, + jetty_grp->start_jetty_id, true); + return ret; + } + + jetty_grp->ubcore_jetty_grp.jetty_grp_id.id = jetty_grp->jetty_grp_id; + + return 0; +} + +struct ubcore_jetty_group *udma_create_jetty_grp(struct ubcore_device *dev, + struct ubcore_jetty_grp_cfg *cfg, + struct ubcore_udata *udata) +{ + struct udma_dev *udma_dev = to_udma_dev(dev); + struct ubase_mbx_attr mbox_attr = {}; + struct udma_jetty_grp_ctx ctx = {}; + struct udma_jetty_grp *jetty_grp; + int ret; + + if (cfg->policy != UBCORE_JETTY_GRP_POLICY_HASH_HINT) { + dev_err(udma_dev->dev, "policy %u not support.\n", cfg->policy); + return NULL; + } + + jetty_grp = kzalloc(sizeof(*jetty_grp), GFP_KERNEL); + if (!jetty_grp) + return NULL; + + ret = udma_alloc_jetty_grp_id(udma_dev, jetty_grp); + if (ret) + goto err_alloc_jetty_grp_id; + + ctx.start_jetty_id = jetty_grp->start_jetty_id; + + ret = xa_err(xa_store(&udma_dev->jetty_grp_table.xa, jetty_grp->jetty_grp_id, + jetty_grp, GFP_KERNEL)); + if (ret) { + dev_err(udma_dev->dev, "store jetty group(%u) failed, ret = %d.\n", + jetty_grp->jetty_grp_id, ret); + goto err_store_jetty_grp; + } + + mbox_attr.tag = jetty_grp->jetty_grp_id; + mbox_attr.op = UDMA_CMD_CREATE_JETTY_GROUP_CONTEXT; + ret = post_mailbox_update_ctx(udma_dev, &ctx, sizeof(ctx), &mbox_attr); + if (ret) { + dev_err(udma_dev->dev, + "post mailbox update jetty ctx failed, ret = %d.\n", ret); + goto err_post_mailbox; + } + + mutex_init(&jetty_grp->valid_lock); + refcount_set(&jetty_grp->ae_refcount, 1); + init_completion(&jetty_grp->ae_comp); + + if (dfx_switch) + udma_dfx_store_id(udma_dev, &udma_dev->dfx_info->jetty_grp, + jetty_grp->jetty_grp_id, "jetty_grp"); + + return &jetty_grp->ubcore_jetty_grp; +err_post_mailbox: + xa_erase(&udma_dev->jetty_grp_table.xa, jetty_grp->jetty_grp_id); +err_store_jetty_grp: + udma_id_free(&udma_dev->jetty_grp_table.ida_table, + jetty_grp->jetty_grp_id); +err_alloc_jetty_grp_id: + kfree(jetty_grp); + + return NULL; +} diff --git a/drivers/ub/urma/hw/udma/udma_jetty.h b/drivers/ub/urma/hw/udma/udma_jetty.h index a37c9a9ff54f..b2e65a8c8f86 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.h +++ b/drivers/ub/urma/hw/udma/udma_jetty.h @@ -225,6 +225,9 @@ struct ubcore_jetty *udma_create_jetty(struct ubcore_device *ub_dev, struct ubcore_jetty_cfg *cfg, struct ubcore_udata *udata); int udma_destroy_jetty(struct ubcore_jetty *jetty); +struct ubcore_jetty_group *udma_create_jetty_grp(struct ubcore_device *dev, + struct ubcore_jetty_grp_cfg *cfg, + struct ubcore_udata *udata); int udma_destroy_hw_jetty_ctx(struct udma_dev *dev, uint32_t jetty_id); void udma_set_query_flush_time(struct udma_jetty_queue *sq, uint8_t err_timeout); int udma_modify_and_destroy_jetty(struct udma_dev *dev, diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index a1f3bcb5dde3..baf9a970fed8 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -190,6 +190,7 @@ static struct ubcore_ops g_dev_ops = { .create_jetty = udma_create_jetty, .query_jetty = udma_query_jetty, .destroy_jetty = udma_destroy_jetty, + .create_jetty_grp = udma_create_jetty_grp, }; static void udma_uninit_group_table(struct udma_dev *dev, struct udma_group_table *table) -- Gitee From 4d71e837bee787b60da0631be33c7ee86349d881 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 17:24:30 +0800 Subject: [PATCH 077/103] ub: udma: Support destroy jetty group. commit a9fe853ef4163a534f78f2b380bdf51f845b0242 openEuler This patch adds the ability to destroy jetty group. During the destruction process, driver will destroy jetty group context and send it to the hardware. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_jetty.c | 41 ++++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jetty.h | 3 +- drivers/ub/urma/hw/udma/udma_main.c | 1 + 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/ub/urma/hw/udma/udma_jetty.c b/drivers/ub/urma/hw/udma/udma_jetty.c index 7cbffa81bf1d..67534599f23d 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.c +++ b/drivers/ub/urma/hw/udma/udma_jetty.c @@ -919,3 +919,44 @@ struct ubcore_jetty_group *udma_create_jetty_grp(struct ubcore_device *dev, return NULL; } + +int udma_delete_jetty_grp(struct ubcore_jetty_group *jetty_grp) +{ + struct udma_jetty_grp *udma_jetty_grp = to_udma_jetty_grp(jetty_grp); + struct udma_dev *udma_dev = to_udma_dev(jetty_grp->ub_dev); + struct ubase_mbx_attr mbox_attr = {}; + int ret; + + mbox_attr.tag = udma_jetty_grp->jetty_grp_id; + mbox_attr.op = UDMA_CMD_DESTROY_JETTY_GROUP_CONTEXT; + ret = post_mailbox_update_ctx(udma_dev, NULL, 0, &mbox_attr); + if (ret) { + dev_err(udma_dev->dev, + "post mailbox destroy jetty group failed, ret = %d.\n", ret); + return ret; + } + + xa_erase(&udma_dev->jetty_grp_table.xa, udma_jetty_grp->jetty_grp_id); + + if (refcount_dec_and_test(&udma_jetty_grp->ae_refcount)) + complete(&udma_jetty_grp->ae_comp); + wait_for_completion(&udma_jetty_grp->ae_comp); + + if (dfx_switch) + udma_dfx_delete_id(udma_dev, &udma_dev->dfx_info->jetty_grp, + udma_jetty_grp->jetty_grp_id); + + if (udma_jetty_grp->valid != 0) + dev_err(udma_dev->dev, + "jetty group been used, jetty valid is 0x%x.\n", + udma_jetty_grp->valid); + + mutex_destroy(&udma_jetty_grp->valid_lock); + udma_id_free(&udma_dev->jetty_grp_table.ida_table, + udma_jetty_grp->jetty_grp_id); + udma_adv_id_free(&udma_dev->jetty_table.bitmap_table, + udma_jetty_grp->start_jetty_id, true); + kfree(udma_jetty_grp); + + return ret; +} diff --git a/drivers/ub/urma/hw/udma/udma_jetty.h b/drivers/ub/urma/hw/udma/udma_jetty.h index b2e65a8c8f86..8f23621a58f6 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.h +++ b/drivers/ub/urma/hw/udma/udma_jetty.h @@ -228,8 +228,9 @@ int udma_destroy_jetty(struct ubcore_jetty *jetty); struct ubcore_jetty_group *udma_create_jetty_grp(struct ubcore_device *dev, struct ubcore_jetty_grp_cfg *cfg, struct ubcore_udata *udata); -int udma_destroy_hw_jetty_ctx(struct udma_dev *dev, uint32_t jetty_id); +int udma_delete_jetty_grp(struct ubcore_jetty_group *jetty_grp); void udma_set_query_flush_time(struct udma_jetty_queue *sq, uint8_t err_timeout); +int udma_destroy_hw_jetty_ctx(struct udma_dev *dev, uint32_t jetty_id); int udma_modify_and_destroy_jetty(struct udma_dev *dev, struct udma_jetty_queue *sq); diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index baf9a970fed8..2491aea7f9e2 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -191,6 +191,7 @@ static struct ubcore_ops g_dev_ops = { .query_jetty = udma_query_jetty, .destroy_jetty = udma_destroy_jetty, .create_jetty_grp = udma_create_jetty_grp, + .delete_jetty_grp = udma_delete_jetty_grp, }; static void udma_uninit_group_table(struct udma_dev *dev, struct udma_group_table *table) -- Gitee From bff0bca39679b03da12dc710ee71799051ff242c Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 19:52:57 +0800 Subject: [PATCH 078/103] ub: udma: Support modify jfs. commit 0ea69661e7ac19a85dcad8c250275d7f9582731b openEuler This patch adds the ability to modify jfs. During the modify jfs process, the driver will post mailbox to notify the hardware to modify. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_jetty.c | 58 +++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jetty.h | 11 +++- drivers/ub/urma/hw/udma/udma_jfs.c | 77 ++++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jfs.h | 2 + drivers/ub/urma/hw/udma/udma_main.c | 1 + 5 files changed, 148 insertions(+), 1 deletion(-) diff --git a/drivers/ub/urma/hw/udma/udma_jetty.c b/drivers/ub/urma/hw/udma/udma_jetty.c index 67534599f23d..74f9a30e2be3 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.c +++ b/drivers/ub/urma/hw/udma/udma_jetty.c @@ -18,6 +18,22 @@ bool well_known_jetty_pgsz_check = true; +const char *state_name[] = { + "RESET", + "READY", + "SUSPENDED", + "ERROR", + "INVALID" +}; + +const char *to_state_name(enum ubcore_jetty_state state) +{ + if ((int)state >= (int)STATE_NUM) + return state_name[STATE_NUM]; + + return state_name[state]; +} + static int udma_get_user_jetty_cmd(struct udma_dev *dev, struct udma_jetty *jetty, struct ubcore_udata *udata, struct udma_create_jetty_ucmd *ucmd) @@ -465,6 +481,14 @@ static void udma_free_jetty_id_buf(struct udma_dev *udma_dev, free_jetty_id(udma_dev, udma_jetty, !!cfg->jetty_grp); } +void udma_reset_sw_k_jetty_queue(struct udma_jetty_queue *sq) +{ + sq->kva_curr = sq->buf.kva; + sq->pi = 0; + sq->ci = 0; + sq->flush_flag = false; +} + static int udma_create_hw_jetty_ctx(struct udma_dev *dev, struct udma_jetty *udma_jetty, struct ubcore_jetty_cfg *cfg) { @@ -808,6 +832,40 @@ int udma_destroy_jetty(struct ubcore_jetty *jetty) return 0; } +bool verify_modify_jetty(enum ubcore_jetty_state jetty_state, + enum ubcore_jetty_state attr_state) +{ + switch (jetty_state) { + case UBCORE_JETTY_STATE_RESET: + return attr_state == UBCORE_JETTY_STATE_READY; + case UBCORE_JETTY_STATE_READY: + return attr_state == UBCORE_JETTY_STATE_ERROR || + attr_state == UBCORE_JETTY_STATE_SUSPENDED; + case UBCORE_JETTY_STATE_SUSPENDED: + return attr_state == UBCORE_JETTY_STATE_ERROR; + case UBCORE_JETTY_STATE_ERROR: + return attr_state == UBCORE_JETTY_STATE_RESET; + default: + break; + } + + return false; +} + +enum jetty_state to_jetty_state(enum ubcore_jetty_state state) +{ + switch (state) { + case UBCORE_JETTY_STATE_ERROR: + return JETTY_ERROR; + case UBCORE_JETTY_STATE_SUSPENDED: + return JETTY_SUSPEND; + default: + break; + } + + return STATE_NUM; +} + static int udma_alloc_group_start_id(struct udma_dev *udma_dev, struct udma_group_bitmap *bitmap_table, uint32_t *start_jetty_id) diff --git a/drivers/ub/urma/hw/udma/udma_jetty.h b/drivers/ub/urma/hw/udma/udma_jetty.h index 8f23621a58f6..013fb8ddd17f 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.h +++ b/drivers/ub/urma/hw/udma/udma_jetty.h @@ -219,6 +219,10 @@ static inline struct udma_jetty *to_udma_jetty_from_queue(struct udma_jetty_queu return container_of(queue, struct udma_jetty, sq); } +enum jetty_state to_jetty_state(enum ubcore_jetty_state state); +const char *to_state_name(enum ubcore_jetty_state state); +bool verify_modify_jetty(enum ubcore_jetty_state jetty_state, + enum ubcore_jetty_state attr_state); int alloc_jetty_id(struct udma_dev *udma_dev, struct udma_jetty_queue *sq, uint32_t cfg_id, struct ubcore_jetty_group *jetty_grp); struct ubcore_jetty *udma_create_jetty(struct ubcore_device *ub_dev, @@ -229,9 +233,14 @@ struct ubcore_jetty_group *udma_create_jetty_grp(struct ubcore_device *dev, struct ubcore_jetty_grp_cfg *cfg, struct ubcore_udata *udata); int udma_delete_jetty_grp(struct ubcore_jetty_group *jetty_grp); -void udma_set_query_flush_time(struct udma_jetty_queue *sq, uint8_t err_timeout); +int udma_set_jetty_state(struct udma_dev *dev, uint32_t jetty_id, + enum jetty_state state); + +void udma_reset_sw_k_jetty_queue(struct udma_jetty_queue *sq); int udma_destroy_hw_jetty_ctx(struct udma_dev *dev, uint32_t jetty_id); +void udma_set_query_flush_time(struct udma_jetty_queue *sq, uint8_t err_timeout); int udma_modify_and_destroy_jetty(struct udma_dev *dev, struct udma_jetty_queue *sq); +int udma_modify_jetty_precondition(struct udma_dev *dev, struct udma_jetty_queue *sq); #endif /* __UDMA_JETTY_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_jfs.c b/drivers/ub/urma/hw/udma/udma_jfs.c index cb00cec5ccfd..e770bc5f6a2f 100644 --- a/drivers/ub/urma/hw/udma/udma_jfs.c +++ b/drivers/ub/urma/hw/udma/udma_jfs.c @@ -409,3 +409,80 @@ int udma_destroy_jfs(struct ubcore_jfs *jfs) return 0; } + +static int udma_modify_jfs_state(struct udma_dev *udma_dev, struct udma_jfs *udma_jfs, + struct ubcore_jfs_attr *attr) +{ + int ret; + + switch (attr->state) { + case UBCORE_JETTY_STATE_RESET: + ret = udma_destroy_hw_jetty_ctx(udma_dev, udma_jfs->sq.id); + break; + case UBCORE_JETTY_STATE_READY: + ret = udma_create_hw_jfs_ctx(udma_dev, udma_jfs, &udma_jfs->ubcore_jfs.jfs_cfg); + if (ret) + break; + + udma_reset_sw_k_jetty_queue(&udma_jfs->sq); + break; + default: + ret = udma_close_ue_rx(udma_dev, true, true, false, 0); + if (ret) + break; + + if (!(udma_dev->caps.feature & UDMA_CAP_FEATURE_UE_RX_CLOSE)) { + if (udma_modify_jetty_precondition(udma_dev, &udma_jfs->sq)) { + ret = -ENOMEM; + udma_open_ue_rx(udma_dev, true, true, false, 0); + break; + } + } + + ret = udma_set_jetty_state(udma_dev, udma_jfs->sq.id, to_jetty_state(attr->state)); + if (ret) + udma_open_ue_rx(udma_dev, true, true, false, 0); + else + udma_jfs->ue_rx_closed = true; + break; + } + + return ret; +} + +int udma_modify_jfs(struct ubcore_jfs *jfs, struct ubcore_jfs_attr *attr, + struct ubcore_udata *udata) +{ + struct udma_dev *udma_dev = to_udma_dev(jfs->ub_dev); + struct udma_jfs *udma_jfs = to_udma_jfs(jfs); + int ret = 0; + + if (!(attr->mask & UBCORE_JFS_STATE)) { + dev_err(udma_dev->dev, "modify jfs mask is error or not set, jfs_id = %u.\n", + udma_jfs->sq.id); + return -EINVAL; + } + + if (udma_jfs->sq.state == attr->state) { + dev_info(udma_dev->dev, "jfs state has been %s.\n", + to_state_name(attr->state)); + return 0; + } + + if (!verify_modify_jetty(udma_jfs->sq.state, attr->state)) { + dev_err(udma_dev->dev, "not support modify jfs state from %s to %s.\n", + to_state_name(udma_jfs->sq.state), to_state_name(attr->state)); + return -EINVAL; + } + + ret = udma_modify_jfs_state(udma_dev, udma_jfs, attr); + if (ret) { + dev_err(udma_dev->dev, "modify jfs %u state to %u failed.\n", + udma_jfs->sq.id, attr->state); + return ret; + } + + udma_jfs->sq.state = attr->state; + + return 0; +} diff --git a/drivers/ub/urma/hw/udma/udma_jfs.h b/drivers/ub/urma/hw/udma/udma_jfs.h index ed1ff16e4573..6cdc281e53c3 100644 --- a/drivers/ub/urma/hw/udma/udma_jfs.h +++ b/drivers/ub/urma/hw/udma/udma_jfs.h @@ -53,5 +53,7 @@ int udma_alloc_u_sq_buf(struct udma_dev *dev, struct udma_jetty_queue *sq, int udma_alloc_k_sq_buf(struct udma_dev *dev, struct udma_jetty_queue *sq, struct ubcore_jfs_cfg *jfs_cfg); void udma_free_sq_buf(struct udma_dev *dev, struct udma_jetty_queue *sq); +int udma_modify_jfs(struct ubcore_jfs *jfs, struct ubcore_jfs_attr *attr, + struct ubcore_udata *udata); #endif /* __UDMA_JFS_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 2491aea7f9e2..c726a231e4f8 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -181,6 +181,7 @@ static struct ubcore_ops g_dev_ops = { .create_jfc = udma_create_jfc, .destroy_jfc = udma_destroy_jfc, .create_jfs = udma_create_jfs, + .modify_jfs = udma_modify_jfs, .query_jfs = udma_query_jfs, .destroy_jfs = udma_destroy_jfs, .create_jfr = udma_create_jfr, -- Gitee From dd8a4cf6316551892d6c37ba2e8966f4d5f6ea95 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Wed, 20 Aug 2025 20:09:44 +0800 Subject: [PATCH 079/103] ub: udma: Support modify jetty. commit f9d5d20b756c9484513f0c0a0493b560f98d9546 openEuler This patch adds the ability to modify jetty. During the modify jetty process, the driver will post mailbox to notify the hardware to modify. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_jetty.c | 77 ++++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jetty.h | 2 + drivers/ub/urma/hw/udma/udma_main.c | 1 + 3 files changed, 80 insertions(+) diff --git a/drivers/ub/urma/hw/udma/udma_jetty.c b/drivers/ub/urma/hw/udma/udma_jetty.c index 74f9a30e2be3..914ef33b81d9 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.c +++ b/drivers/ub/urma/hw/udma/udma_jetty.c @@ -866,6 +866,83 @@ enum jetty_state to_jetty_state(enum ubcore_jetty_state state) return STATE_NUM; } +static int udma_modify_jetty_state(struct udma_dev *udma_dev, struct udma_jetty *udma_jetty, + struct ubcore_jetty_attr *attr) +{ + int ret; + + switch (attr->state) { + case UBCORE_JETTY_STATE_RESET: + ret = udma_destroy_hw_jetty_ctx(udma_dev, udma_jetty->sq.id); + break; + case UBCORE_JETTY_STATE_READY: + ret = udma_create_hw_jetty_ctx(udma_dev, udma_jetty, + &udma_jetty->ubcore_jetty.jetty_cfg); + if (ret) + break; + + udma_reset_sw_k_jetty_queue(&udma_jetty->sq); + break; + default: + ret = udma_close_ue_rx(udma_dev, true, true, false, 0); + if (ret) + break; + + if (!(udma_dev->caps.feature & UDMA_CAP_FEATURE_UE_RX_CLOSE)) { + if (udma_modify_jetty_precondition(udma_dev, &udma_jetty->sq)) { + ret = -ENOMEM; + udma_open_ue_rx(udma_dev, true, true, false, 0); + break; + } + } + + ret = udma_set_jetty_state(udma_dev, udma_jetty->sq.id, + to_jetty_state(attr->state)); + if (ret) + udma_open_ue_rx(udma_dev, true, true, false, 0); + else + udma_jetty->ue_rx_closed = true; + break; + } + + return ret; +} + +int udma_modify_jetty(struct ubcore_jetty *jetty, struct ubcore_jetty_attr *attr, + struct ubcore_udata *udata) +{ + struct udma_dev *udma_dev = to_udma_dev(jetty->ub_dev); + struct udma_jetty *udma_jetty = to_udma_jetty(jetty); + int ret; + + if (!(attr->mask & UBCORE_JETTY_STATE)) { + dev_err(udma_dev->dev, "modify jetty mask is error or not set, jetty_id = %u.\n", + udma_jetty->sq.id); + return -EINVAL; + } + + if (udma_jetty->sq.state == attr->state) { + dev_info(udma_dev->dev, "jetty state has been %s.\n", to_state_name(attr->state)); + return 0; + } + + if (!verify_modify_jetty(udma_jetty->sq.state, attr->state)) { + dev_err(udma_dev->dev, "not support modify jetty state from %s to %s.\n", + to_state_name(udma_jetty->sq.state), to_state_name(attr->state)); + return -EINVAL; + } + + ret = udma_modify_jetty_state(udma_dev, udma_jetty, attr); + if (ret) { + dev_err(udma_dev->dev, "modify jetty %u state to %s failed.\n", + udma_jetty->sq.id, to_state_name(attr->state)); + return ret; + } + udma_jetty->sq.state = attr->state; + + return 0; +} + static int udma_alloc_group_start_id(struct udma_dev *udma_dev, struct udma_group_bitmap *bitmap_table, uint32_t *start_jetty_id) diff --git a/drivers/ub/urma/hw/udma/udma_jetty.h b/drivers/ub/urma/hw/udma/udma_jetty.h index 013fb8ddd17f..5b428e999ff1 100644 --- a/drivers/ub/urma/hw/udma/udma_jetty.h +++ b/drivers/ub/urma/hw/udma/udma_jetty.h @@ -229,6 +229,8 @@ struct ubcore_jetty *udma_create_jetty(struct ubcore_device *ub_dev, struct ubcore_jetty_cfg *cfg, struct ubcore_udata *udata); int udma_destroy_jetty(struct ubcore_jetty *jetty); +int udma_modify_jetty(struct ubcore_jetty *jetty, struct ubcore_jetty_attr *attr, + struct ubcore_udata *udata); struct ubcore_jetty_group *udma_create_jetty_grp(struct ubcore_device *dev, struct ubcore_jetty_grp_cfg *cfg, struct ubcore_udata *udata); diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index c726a231e4f8..93ca98ef248e 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -189,6 +189,7 @@ static struct ubcore_ops g_dev_ops = { .destroy_jfr_batch = udma_destroy_jfr_batch, .query_jfr = udma_query_jfr, .create_jetty = udma_create_jetty, + .modify_jetty = udma_modify_jetty, .query_jetty = udma_query_jetty, .destroy_jetty = udma_destroy_jetty, .create_jetty_grp = udma_create_jetty_grp, -- Gitee From 1d456dda7261c54edfb7540b53c910e4960ed9d8 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Thu, 21 Aug 2025 09:26:22 +0800 Subject: [PATCH 080/103] ub: udma: Support modify jfr. commit d7b858224867b71d55b7ad700bb86da388ec2d91 openEuler This patch adds the ability to modify jfr. During the modify jfr process, the driver will post mailbox to notify the hardware to modify. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_jfr.c | 140 ++++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jfr.h | 2 + drivers/ub/urma/hw/udma/udma_main.c | 3 +- 3 files changed, 144 insertions(+), 1 deletion(-) diff --git a/drivers/ub/urma/hw/udma/udma_jfr.c b/drivers/ub/urma/hw/udma/udma_jfr.c index f15ca6b26d42..953fcffc5001 100644 --- a/drivers/ub/urma/hw/udma/udma_jfr.c +++ b/drivers/ub/urma/hw/udma/udma_jfr.c @@ -19,6 +19,14 @@ const char *state_str[] = { "INVALID" }; +static const char *to_state_str(enum ubcore_jfr_state state) +{ + if ((int)state >= (int)JFR_STATE_NUM) + return state_str[JFR_STATE_NUM]; + + return state_str[state]; +} + static int udma_verify_jfr_param(struct udma_dev *dev, struct ubcore_jfr_cfg *cfg) { @@ -650,3 +658,135 @@ int udma_destroy_jfr_batch(struct ubcore_jfr **jfr, int jfr_cnt, int *bad_jfr_in return 0; } + +static bool verify_modify_jfr_state(enum ubcore_jfr_state jfr_state, + enum ubcore_jfr_state attr_state) +{ + switch (jfr_state) { + case UBCORE_JFR_STATE_RESET: + return attr_state == UBCORE_JFR_STATE_READY; + case UBCORE_JFR_STATE_READY: + return attr_state == UBCORE_JFR_STATE_ERROR; + case UBCORE_JFR_STATE_ERROR: + return attr_state == UBCORE_JFR_STATE_RESET; + default: + break; + } + + return false; +} + +static int verify_modify_jfr(struct udma_dev *udma_dev, struct udma_jfr *udma_jfr, + struct ubcore_jfr_attr *attr, bool *state_flag, + bool *rx_threshold_flag) +{ + *rx_threshold_flag = false; + *state_flag = false; + + if (!(attr->mask & (UBCORE_JFR_RX_THRESHOLD | UBCORE_JFR_STATE))) { + dev_err(udma_dev->dev, + "modify jfr mask is error or not set, jfrn = %u.\n", + udma_jfr->rq.id); + return -EINVAL; + } + + if (attr->mask & UBCORE_JFR_RX_THRESHOLD) { + if (attr->rx_threshold >= udma_jfr->wqe_cnt) { + dev_err(udma_dev->dev, + "JFR rx_threshold(%u) must less than wqe num(%u).\n", + attr->rx_threshold, udma_jfr->wqe_cnt); + return -EINVAL; + } + *rx_threshold_flag = true; + } + + if (attr->mask & UBCORE_JFR_STATE) { + if (udma_jfr->state == attr->state) { + dev_info(udma_dev->dev, + "jfr(%u) state has been %s, keep it unchanged.\n", + udma_jfr->rq.id, to_state_str(attr->state)); + return 0; + } else if (!verify_modify_jfr_state(udma_jfr->state, + attr->state)) { + dev_err(udma_dev->dev, + "jfr(%u) not support modify jfr state from %s to %s.\n", + udma_jfr->rq.id, to_state_str(udma_jfr->state), + to_state_str(attr->state)); + return -EINVAL; + } else if ((attr->state == UBCORE_JFR_STATE_RESET || + attr->state == UBCORE_JFR_STATE_ERROR) && + *rx_threshold_flag) { + dev_err(udma_dev->dev, + "jfr(%u) not support set rx threshold when change state to %s.\n", + udma_jfr->rq.id, to_state_str(attr->state)); + return -EINVAL; + } + *state_flag = true; + } + + return 0; +} + +static int udma_destroy_hw_jfr_ctx(struct udma_dev *dev, uint32_t jfr_id) +{ + struct ubase_mbx_attr attr = {}; + int ret; + + attr.tag = jfr_id; + attr.op = UDMA_CMD_DESTROY_JFR_CONTEXT; + ret = post_mailbox_update_ctx(dev, NULL, 0, &attr); + if (ret) + dev_err(dev->dev, + "post mailbox destroy jfr ctx failed, ret = %d.\n", ret); + + return ret; +} + +int udma_modify_jfr(struct ubcore_jfr *jfr, struct ubcore_jfr_attr *attr, + struct ubcore_udata *udata) +{ + struct udma_dev *udma_dev = to_udma_dev(jfr->ub_dev); + struct udma_jfr *udma_jfr = to_udma_jfr(jfr); + bool rx_threshold_flag = false; + bool state_flag = false; + int ret = 0; + + ret = verify_modify_jfr(udma_dev, udma_jfr, attr, &state_flag, + &rx_threshold_flag); + if (ret) + return ret; + + if (!(rx_threshold_flag || state_flag)) + return 0; + + if (rx_threshold_flag && !state_flag) { + ret = modify_jfr_context(udma_dev, udma_jfr->rq.id, state_flag, + rx_threshold_flag, attr); + } else { + switch (attr->state) { + case UBCORE_JFR_STATE_RESET: + ret = udma_destroy_hw_jfr_ctx(udma_dev, udma_jfr->rq.id); + break; + case UBCORE_JFR_STATE_READY: + ret = udma_hw_init_jfrc(udma_dev, &jfr->jfr_cfg, udma_jfr, + rx_threshold_flag ? + attr->rx_threshold : udma_jfr->rx_threshold); + break; + default: + ret = modify_jfr_context(udma_dev, udma_jfr->rq.id, state_flag, + rx_threshold_flag, attr); + break; + } + } + + if (ret) + return ret; + + if (state_flag) + udma_jfr->state = attr->state; + + if (rx_threshold_flag) + udma_jfr->rx_threshold = attr->rx_threshold; + + return 0; +} diff --git a/drivers/ub/urma/hw/udma/udma_jfr.h b/drivers/ub/urma/hw/udma/udma_jfr.h index 43ee96cea746..ae6d0d97f460 100644 --- a/drivers/ub/urma/hw/udma/udma_jfr.h +++ b/drivers/ub/urma/hw/udma/udma_jfr.h @@ -155,6 +155,8 @@ static inline struct udma_jfr *to_udma_jfr_from_queue(struct udma_jetty_queue *q return container_of(queue, struct udma_jfr, rq); } +int udma_modify_jfr(struct ubcore_jfr *jfr, struct ubcore_jfr_attr *attr, + struct ubcore_udata *udata); struct ubcore_jfr *udma_create_jfr(struct ubcore_device *dev, struct ubcore_jfr_cfg *cfg, struct ubcore_udata *udata); int udma_destroy_jfr(struct ubcore_jfr *jfr); diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 93ca98ef248e..3a478a468c6f 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -185,9 +185,10 @@ static struct ubcore_ops g_dev_ops = { .query_jfs = udma_query_jfs, .destroy_jfs = udma_destroy_jfs, .create_jfr = udma_create_jfr, + .modify_jfr = udma_modify_jfr, + .query_jfr = udma_query_jfr, .destroy_jfr = udma_destroy_jfr, .destroy_jfr_batch = udma_destroy_jfr_batch, - .query_jfr = udma_query_jfr, .create_jetty = udma_create_jetty, .modify_jetty = udma_modify_jetty, .query_jetty = udma_query_jetty, -- Gitee From ee67651bc9724e5829b9d8090e0a15f10652b842 Mon Sep 17 00:00:00 2001 From: Wei Qin Date: Thu, 21 Aug 2025 09:37:37 +0800 Subject: [PATCH 081/103] ub: udma: Support modify jfc. commit ab014f21ec7d348ce728443be3d8af41ab6d8d40 openEuler This patch adds the ability to modify jfc. During the modify jfc process, the driver will post mailbox to notify the hardware to modify. Signed-off-by: Wei Qin Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/urma/hw/udma/udma_jfc.c | 109 ++++++++++++++++++++++++++++ drivers/ub/urma/hw/udma/udma_jfc.h | 2 + drivers/ub/urma/hw/udma/udma_main.c | 1 + 3 files changed, 112 insertions(+) diff --git a/drivers/ub/urma/hw/udma/udma_jfc.c b/drivers/ub/urma/hw/udma/udma_jfc.c index bfbf479ec06f..5067b3c52104 100644 --- a/drivers/ub/urma/hw/udma/udma_jfc.c +++ b/drivers/ub/urma/hw/udma/udma_jfc.c @@ -536,3 +536,112 @@ int udma_jfc_completion(struct notifier_block *nb, unsigned long jfcn, return 0; } + +static int udma_get_cqe_period(uint16_t cqe_period) +{ + uint16_t period[] = { + UDMA_CQE_PERIOD_0, + UDMA_CQE_PERIOD_4, + UDMA_CQE_PERIOD_16, + UDMA_CQE_PERIOD_64, + UDMA_CQE_PERIOD_256, + UDMA_CQE_PERIOD_1024, + UDMA_CQE_PERIOD_4096, + UDMA_CQE_PERIOD_16384 + }; + uint32_t i; + + for (i = 0; i < ARRAY_SIZE(period); ++i) { + if (cqe_period == period[i]) + return i; + } + + return -EINVAL; +} + +static int udma_check_jfc_attr(struct udma_dev *udma_dev, struct ubcore_jfc_attr *attr) +{ + if (!(attr->mask & (UBCORE_JFC_MODERATE_COUNT | UBCORE_JFC_MODERATE_PERIOD))) { + dev_err(udma_dev->dev, + "udma modify jfc mask is not set or invalid.\n"); + return -EINVAL; + } + + if ((attr->mask & UBCORE_JFC_MODERATE_COUNT) && + (attr->moderate_count >= UDMA_CQE_COALESCE_CNT_MAX)) { + dev_err(udma_dev->dev, "udma cqe coalesce cnt %u is invalid.\n", + attr->moderate_count); + return -EINVAL; + } + + if ((attr->mask & UBCORE_JFC_MODERATE_PERIOD) && + (udma_get_cqe_period(attr->moderate_period) == -EINVAL)) { + dev_err(udma_dev->dev, "udma cqe coalesce period %u is invalid.\n", + attr->moderate_period); + return -EINVAL; + } + + return 0; +} + +static int udma_modify_jfc_attr(struct udma_dev *dev, uint32_t jfcn, + struct ubcore_jfc_attr *attr) +{ + struct udma_jfc_ctx *jfc_context, *ctx_mask; + struct ubase_mbx_attr mbox_attr = {}; + struct ubase_cmd_mailbox *mailbox; + int ret; + + mailbox = udma_alloc_cmd_mailbox(dev); + if (!mailbox) { + dev_err(dev->dev, "failed to alloc mailbox for modify jfc.\n"); + return -ENOMEM; + } + + jfc_context = &((struct udma_jfc_ctx *)mailbox->buf)[0]; + ctx_mask = &((struct udma_jfc_ctx *)mailbox->buf)[1]; + memset(ctx_mask, 0xff, sizeof(struct udma_jfc_ctx)); + + if (attr->mask & UBCORE_JFC_MODERATE_COUNT) { + jfc_context->cqe_coalesce_cnt = attr->moderate_count; + ctx_mask->cqe_coalesce_cnt = 0; + } + + if (attr->mask & UBCORE_JFC_MODERATE_PERIOD) { + jfc_context->cqe_coalesce_period = + udma_get_cqe_period(attr->moderate_period); + ctx_mask->cqe_coalesce_period = 0; + } + + mbox_attr.tag = jfcn; + mbox_attr.op = UDMA_CMD_MODIFY_JFC_CONTEXT; + ret = udma_post_mbox(dev, mailbox, &mbox_attr); + if (ret) + dev_err(dev->dev, + "failed to send post mbox in modify JFCC, ret = %d.\n", + ret); + + udma_free_cmd_mailbox(dev, mailbox); + + return ret; +} + +int udma_modify_jfc(struct ubcore_jfc *ubcore_jfc, struct ubcore_jfc_attr *attr, + struct ubcore_udata *udata) +{ + struct udma_dev *udma_device = to_udma_dev(ubcore_jfc->ub_dev); + struct udma_jfc *udma_jfc = to_udma_jfc(ubcore_jfc); + int ret; + + ret = udma_check_jfc_attr(udma_device, attr); + if (ret) + return ret; + + ret = udma_modify_jfc_attr(udma_device, udma_jfc->jfcn, attr); + if (ret) + dev_err(udma_device->dev, + "failed to modify JFC, jfcn = %u, ret = %d.\n", + udma_jfc->jfcn, ret); + + return ret; +} diff --git a/drivers/ub/urma/hw/udma/udma_jfc.h b/drivers/ub/urma/hw/udma/udma_jfc.h index 21f4016a42cd..29db1243623e 100644 --- a/drivers/ub/urma/hw/udma/udma_jfc.h +++ b/drivers/ub/urma/hw/udma/udma_jfc.h @@ -142,5 +142,7 @@ struct ubcore_jfc *udma_create_jfc(struct ubcore_device *ubcore_dev, int udma_destroy_jfc(struct ubcore_jfc *jfc); int udma_jfc_completion(struct notifier_block *nb, unsigned long jfcn, void *data); +int udma_modify_jfc(struct ubcore_jfc *ubcore_jfc, struct ubcore_jfc_attr *attr, + struct ubcore_udata *udata); #endif /* __UDMA_JFC_H__ */ diff --git a/drivers/ub/urma/hw/udma/udma_main.c b/drivers/ub/urma/hw/udma/udma_main.c index 3a478a468c6f..b1fad9e31f38 100644 --- a/drivers/ub/urma/hw/udma/udma_main.c +++ b/drivers/ub/urma/hw/udma/udma_main.c @@ -179,6 +179,7 @@ static struct ubcore_ops g_dev_ops = { .import_seg = udma_import_seg, .unimport_seg = udma_unimport_seg, .create_jfc = udma_create_jfc, + .modify_jfc = udma_modify_jfc, .destroy_jfc = udma_destroy_jfc, .create_jfs = udma_create_jfs, .modify_jfs = udma_modify_jfs, -- Gitee From 5ef1dc11cbf02a46cec3617773c0aa3a08f6345c Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 15:43:50 +0800 Subject: [PATCH 082/103] ub: cdma: support kernel resource reclamation commit 82ffc9d85146f7dbf53de48a04c7d56ee9fce95a openEuler This patch implements kernel resource reclamation functionality within the CDMA driver. The implementation includes reclaiming the corresponding context and the resources under that context, such as queues, jfs, ctp, jfc, and segments, after the user-space process has exited. Signed-off-by: Zhipeng Lu Signed-off-by: Bangwei Zhang Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma_chardev.c | 60 ++++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_chardev.h | 2 ++ drivers/ub/cdma/cdma_context.c | 46 ++++++++++++++++++++++++++ drivers/ub/cdma/cdma_context.h | 1 + drivers/ub/cdma/cdma_event.c | 2 ++ drivers/ub/cdma/cdma_types.h | 6 ++++ 6 files changed, 117 insertions(+) diff --git a/drivers/ub/cdma/cdma_chardev.c b/drivers/ub/cdma/cdma_chardev.c index 124b5701b253..a1a289eb0e91 100644 --- a/drivers/ub/cdma/cdma_chardev.c +++ b/drivers/ub/cdma/cdma_chardev.c @@ -176,11 +176,61 @@ static int cdma_mmap(struct file *file, struct vm_area_struct *vma) return 0; } +static void cdma_mmu_release(struct mmu_notifier *mn, struct mm_struct *mm) +{ + struct cdma_mn *mn_notifier = container_of(mn, struct cdma_mn, mn); + struct cdma_file *cfile = container_of(mn_notifier, struct cdma_file, mn_notifier); + + if (mn_notifier->mm != mm || mn_notifier->mm == NULL) { + pr_info("mm already released.\n"); + return; + } + mn_notifier->mm = NULL; + + mutex_lock(&cfile->ctx_mutex); + cdma_cleanup_context_uobj(cfile); + if (cfile->uctx) + cdma_cleanup_context_res(cfile->uctx); + cfile->uctx = NULL; + mutex_unlock(&cfile->ctx_mutex); +} + +static const struct mmu_notifier_ops cdma_mm_notifier_ops = { + .release = cdma_mmu_release +}; + +static int cdma_register_mmu(struct cdma_file *file) +{ + struct cdma_mn *mn_notifier = &file->mn_notifier; + int ret; + + mn_notifier->mm = current->mm; + mn_notifier->mn.ops = &cdma_mm_notifier_ops; + ret = mmu_notifier_register(&mn_notifier->mn, current->mm); + if (ret) + mn_notifier->mm = NULL; + + return ret; +} + +static void cdma_unregister_mmu(struct cdma_file *cfile) +{ + struct cdma_mn *mn_notifier = &cfile->mn_notifier; + struct mm_struct *mm = mn_notifier->mm; + + if (!mm) + return; + + cfile->mn_notifier.mm = NULL; + mmu_notifier_unregister(&cfile->mn_notifier.mn, mm); +} + static int cdma_open(struct inode *inode, struct file *file) { struct cdma_chardev *chardev; struct cdma_file *cfile; struct cdma_dev *cdev; + int ret; chardev = container_of(inode->i_cdev, struct cdma_chardev, cdev); cdev = container_of(chardev, struct cdma_dev, chardev); @@ -189,6 +239,13 @@ static int cdma_open(struct inode *inode, struct file *file) if (!cfile) return -ENOMEM; + ret = cdma_register_mmu(cfile); + if (ret) { + dev_err(cdev->dev, "register mmu failed, ret = %d.\n", ret); + kfree(cfile); + return ret; + } + cdma_init_uobj_idr(cfile); mutex_lock(&cdev->file_mutex); cfile->cdev = cdev; @@ -216,6 +273,8 @@ static int cdma_close(struct inode *inode, struct file *file) mutex_lock(&cfile->ctx_mutex); cdma_cleanup_context_uobj(cfile); + if (cfile->uctx) + cdma_cleanup_context_res(cfile->uctx); cfile->uctx = NULL; mutex_unlock(&cfile->ctx_mutex); @@ -302,6 +361,7 @@ void cdma_release_file(struct kref *ref) { struct cdma_file *cfile = container_of(ref, struct cdma_file, ref); + cdma_unregister_mmu(cfile); mutex_destroy(&cfile->ctx_mutex); idr_destroy(&cfile->idr); kfree(cfile); diff --git a/drivers/ub/cdma/cdma_chardev.h b/drivers/ub/cdma/cdma_chardev.h index 5366dd77ea54..0bd4fcc654ff 100644 --- a/drivers/ub/cdma/cdma_chardev.h +++ b/drivers/ub/cdma/cdma_chardev.h @@ -4,6 +4,8 @@ #ifndef __CDMA_CHARDEV_H__ #define __CDMA_CHARDEV_H__ +#include + #define CDMA_TEST_NAME "cdma_dev" #define CDMA_MAX_DEVICES 1 #define CDMA_JETTY_DSQE_OFFSET 0x1000 diff --git a/drivers/ub/cdma/cdma_context.c b/drivers/ub/cdma/cdma_context.c index e3b3e13d8a4e..c95ccb0c28b4 100644 --- a/drivers/ub/cdma/cdma_context.c +++ b/drivers/ub/cdma/cdma_context.c @@ -6,6 +6,11 @@ #include #include #include "cdma.h" +#include "cdma_queue.h" +#include "cdma_jfc.h" +#include "cdma_jfs.h" +#include "cdma_tp.h" +#include "cdma_segment.h" #include "cdma_context.h" static void cdma_ctx_handle_free(struct cdma_dev *cdev, @@ -133,3 +138,44 @@ void cdma_free_context(struct cdma_dev *cdev, struct cdma_context *ctx) mutex_destroy(&ctx->pgdir_mutex); kfree(ctx); } + +static void cdma_cleanup_queue_res(struct cdma_dev *cdev, struct cdma_context *ctx) +{ + struct cdma_table *queue_tbl = &cdev->queue_table; + struct cdma_queue *queue, *next_queue; + + list_for_each_entry_safe(queue, next_queue, &ctx->queue_list, list) { + list_del(&queue->list); + + if (queue->jfs) + cdma_delete_jfs(cdev, queue->jfs->id); + + if (queue->tp) + cdma_delete_ctp(cdev, queue->tp->tp_id); + + if (queue->jfc) + cdma_delete_jfc(cdev, queue->jfc->id, NULL); + + spin_lock(&queue_tbl->lock); + idr_remove(&queue_tbl->idr_tbl.idr, queue->id); + spin_unlock(&queue_tbl->lock); + kfree(queue); + } +} + +static void cdma_cleanup_segment_res(struct cdma_dev *cdev, struct cdma_context *ctx) +{ + struct cdma_segment *segment, *next_segment; + + list_for_each_entry_safe(segment, next_segment, &ctx->seg_list, list) { + list_del(&segment->list); + cdma_unregister_seg(cdev, segment); + } +} + +void cdma_cleanup_context_res(struct cdma_context *ctx) +{ + cdma_cleanup_queue_res(ctx->cdev, ctx); + cdma_cleanup_segment_res(ctx->cdev, ctx); + cdma_free_context(ctx->cdev, ctx); +} diff --git a/drivers/ub/cdma/cdma_context.h b/drivers/ub/cdma/cdma_context.h index 590bffb14cce..47736a281257 100644 --- a/drivers/ub/cdma/cdma_context.h +++ b/drivers/ub/cdma/cdma_context.h @@ -35,5 +35,6 @@ struct cdma_ctx_res { struct cdma_context *cdma_find_ctx_by_handle(struct cdma_dev *cdev, int handle); struct cdma_context *cdma_alloc_context(struct cdma_dev *cdev, bool is_kernel); void cdma_free_context(struct cdma_dev *cdev, struct cdma_context *ctx); +void cdma_cleanup_context_res(struct cdma_context *ctx); #endif /* CDMA_CONTEXT_H */ diff --git a/drivers/ub/cdma/cdma_event.c b/drivers/ub/cdma/cdma_event.c index f887c52a0479..f2c51d4833ee 100644 --- a/drivers/ub/cdma/cdma_event.c +++ b/drivers/ub/cdma/cdma_event.c @@ -409,6 +409,7 @@ struct cdma_jfce *cdma_alloc_jfce(struct cdma_file *cfile) jfce->fd = new_fd; jfce->file = file; jfce->cfile = cfile; + kref_get(&cfile->ref); fd_install(new_fd, file); return jfce; @@ -655,6 +656,7 @@ struct cdma_jfae *cdma_alloc_jfae(struct cdma_file *cfile) jfae->fd = fd; jfae->file = file; jfae->cfile = cfile; + kref_get(&cfile->ref); fd_install(fd, file); return jfae; diff --git a/drivers/ub/cdma/cdma_types.h b/drivers/ub/cdma/cdma_types.h index e4c2f3fd7b52..afd59c2c4731 100644 --- a/drivers/ub/cdma/cdma_types.h +++ b/drivers/ub/cdma/cdma_types.h @@ -121,6 +121,11 @@ struct cdma_base_jfc { struct cdma_jfc_event jfc_event; }; +struct cdma_mn { + struct mmu_notifier mn; + struct mm_struct *mm; +}; + struct cdma_file { struct cdma_dev *cdev; struct list_head list; @@ -128,6 +133,7 @@ struct cdma_file { struct cdma_context *uctx; struct idr idr; spinlock_t idr_lock; + struct cdma_mn mn_notifier; struct kref ref; }; -- Gitee From 26cd5ae3aa9450f151828a3b305e9fb750f486f3 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 15:46:33 +0800 Subject: [PATCH 083/103] ub: cdma: support dma write semantic configuration commit 81b92c3f5cf6162d1fda6853750e6b0031390d80 openEuler This patch implements functionality related to DMA write semantic configuration within the CDMA driver. The implementation includes support for the dma_write interface. Signed-off-by: Zhipeng Lu Signed-off-by: Jinjie Cui Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/Makefile | 3 +- drivers/ub/cdma/cdma_api.c | 62 ++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_common.h | 3 ++ drivers/ub/cdma/cdma_handle.c | 72 +++++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_handle.h | 14 +++++++ drivers/ub/cdma/cdma_jfs.h | 70 ++++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_types.h | 9 +++++ include/ub/cdma/cdma_api.h | 8 ++++ 8 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 drivers/ub/cdma/cdma_handle.c create mode 100644 drivers/ub/cdma/cdma_handle.h diff --git a/drivers/ub/cdma/Makefile b/drivers/ub/cdma/Makefile index 714e0542f387..cb3ea219f9e2 100644 --- a/drivers/ub/cdma/Makefile +++ b/drivers/ub/cdma/Makefile @@ -2,6 +2,7 @@ cdma-$(CONFIG_UB_CDMA) := cdma_main.o cdma_dev.o cdma_chardev.o cdma_cmd.o cdma_tid.o cdma_ioctl.o \ cdma_api.o cdma_context.o cdma_queue.o cdma_uobj.o cdma_jfc.o cdma_common.o \ - cdma_db.o cdma_mbox.o cdma_tp.o cdma_jfs.o cdma_eq.o cdma_event.o cdma_segment.o + cdma_db.o cdma_mbox.o cdma_tp.o cdma_jfs.o cdma_eq.o cdma_event.o cdma_segment.o \ + cdma_handle.o obj-m += cdma.o diff --git a/drivers/ub/cdma/cdma_api.c b/drivers/ub/cdma/cdma_api.c index 89d01159f797..c3656793abb2 100644 --- a/drivers/ub/cdma/cdma_api.c +++ b/drivers/ub/cdma/cdma_api.c @@ -11,6 +11,7 @@ #include "cdma_queue.h" #include "cdma_jfc.h" #include "cdma.h" +#include "cdma_handle.h" #include struct dma_device *dma_get_device_list(u32 *num_devices) @@ -437,6 +438,67 @@ void dma_unimport_seg(struct dma_seg *dma_seg) } EXPORT_SYMBOL_GPL(dma_unimport_seg); +static int cdma_param_transfer(struct dma_device *dma_dev, int queue_id, + struct cdma_dev **cdev, + struct cdma_queue **cdma_queue) +{ + struct cdma_queue *tmp_q; + struct cdma_dev *tmp_dev; + u32 eid; + + eid = dma_dev->attr.eid.dw0; + tmp_dev = get_cdma_dev_by_eid(eid); + if (!tmp_dev) { + pr_err("get cdma dev failed, eid = 0x%x.\n", eid); + return -EINVAL; + } + + if (tmp_dev->status == CDMA_SUSPEND) { + pr_warn("cdma device is not prepared, eid = 0x%x.\n", eid); + return -EINVAL; + } + + tmp_q = cdma_find_queue(tmp_dev, queue_id); + if (!tmp_q) { + dev_err(tmp_dev->dev, "get resource failed.\n"); + return -EINVAL; + } + + if (!tmp_q->tp || !tmp_q->jfs || !tmp_q->jfc) { + dev_err(tmp_dev->dev, "get jetty parameters failed.\n"); + return -EFAULT; + } + + *cdev = tmp_dev; + *cdma_queue = tmp_q; + + return 0; +} + +enum dma_status dma_write(struct dma_device *dma_dev, struct dma_seg *rmt_seg, + struct dma_seg *local_seg, int queue_id) +{ + struct cdma_queue *cdma_queue = NULL; + struct cdma_dev *cdev = NULL; + int ret; + + if (!dma_dev || !rmt_seg || !local_seg) { + pr_err("write input parameters error.\n"); + return DMA_STATUS_INVAL; + } + + ret = cdma_param_transfer(dma_dev, queue_id, &cdev, &cdma_queue); + if (ret) + return DMA_STATUS_INVAL; + + ret = cdma_write(cdev, cdma_queue, local_seg, rmt_seg); + if (ret) + return DMA_STATUS_INVAL; + + return DMA_STATUS_OK; +} +EXPORT_SYMBOL_GPL(dma_write); + int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, struct dma_cr *cr) { diff --git a/drivers/ub/cdma/cdma_common.h b/drivers/ub/cdma/cdma_common.h index f0370bea2861..3d45f64f5926 100644 --- a/drivers/ub/cdma/cdma_common.h +++ b/drivers/ub/cdma/cdma_common.h @@ -23,6 +23,9 @@ #define CDMA_RANGE_INDEX_ENTRY_CNT 0x100000 #define CDMA_SEGMENT_ENTRY_CNT 0x10000 +#define CDMA_ENABLE_FLAG 1 +#define CDMA_DISABLE_FLAG 0 + #define CDMA_DB_SIZE 64 #define SQE_PLD_TOKEN_ID_MASK GENMASK(19, 0) diff --git a/drivers/ub/cdma/cdma_handle.c b/drivers/ub/cdma/cdma_handle.c new file mode 100644 index 000000000000..aa4274aac27b --- /dev/null +++ b/drivers/ub/cdma/cdma_handle.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include "cdma_jfs.h" +#include "cdma_common.h" +#include "cdma_handle.h" + +static int cdma_rw_check(struct cdma_dev *cdev, struct dma_seg *rmt_seg, + struct dma_seg *local_seg) +{ + if (!rmt_seg->len || !local_seg->len) { + dev_err(cdev->dev, "invalid len.\n"); + return -EINVAL; + } + + if (!rmt_seg->sva || !local_seg->sva) { + dev_err(cdev->dev, "invalid address.\n"); + return -EINVAL; + } + + return 0; +} + +static inline void cdma_fill_comm_wr(struct cdma_jfs_wr *wr, + struct cdma_queue *queue) +{ + wr->flag.bs.complete_enable = CDMA_ENABLE_FLAG; + wr->flag.bs.inline_flag = CDMA_DISABLE_FLAG; + wr->flag.bs.fence = CDMA_ENABLE_FLAG; + wr->tpn = queue->tp->tpn; + wr->rmt_eid = queue->cfg.rmt_eid.dw0; + wr->next = NULL; +} + +static inline void cdma_fill_sge(struct cdma_sge_info *rmt_sge, + struct cdma_sge_info *local_sge, + struct dma_seg *rmt_seg, + struct dma_seg *local_seg) +{ + local_sge->addr = local_seg->sva; + local_sge->len = local_seg->len; + local_sge->seg = local_seg; + + rmt_sge->addr = rmt_seg->sva; + rmt_sge->len = rmt_seg->len; + rmt_sge->seg = rmt_seg; +} + +int cdma_write(struct cdma_dev *cdev, struct cdma_queue *queue, + struct dma_seg *local_seg, struct dma_seg *rmt_seg) +{ + struct cdma_jfs_wr wr = { .opcode = CDMA_WR_OPC_WRITE }; + struct cdma_sge_info rmt_sge, local_sge; + + if (cdma_rw_check(cdev, rmt_seg, local_seg)) { + dev_err(cdev->dev, "write param check failed.\n"); + return -EINVAL; + } + + cdma_fill_comm_wr(&wr, queue); + + cdma_fill_sge(&rmt_sge, &local_sge, rmt_seg, local_seg); + + wr.rw.src.num_sge = 1; + wr.rw.src.sge = &local_sge; + wr.rw.dst.num_sge = 1; + wr.rw.dst.sge = &rmt_sge; + + return 0; +} diff --git a/drivers/ub/cdma/cdma_handle.h b/drivers/ub/cdma/cdma_handle.h new file mode 100644 index 000000000000..27a3f9495d18 --- /dev/null +++ b/drivers/ub/cdma/cdma_handle.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_HANDLE_H__ +#define __CDMA_HANDLE_H__ + +#include "cdma_segment.h" +#include "cdma_queue.h" +#include "cdma.h" + +int cdma_write(struct cdma_dev *cdev, struct cdma_queue *queue, + struct dma_seg *local_seg, struct dma_seg *rmt_seg); + +#endif /* CDMA_HANDLE_H */ diff --git a/drivers/ub/cdma/cdma_jfs.h b/drivers/ub/cdma/cdma_jfs.h index e4dcaa765a89..b34821701511 100644 --- a/drivers/ub/cdma/cdma_jfs.h +++ b/drivers/ub/cdma/cdma_jfs.h @@ -20,6 +20,74 @@ #define CDMA_RCV_SEND_MAX_DIFF 512U +union cdma_jfs_wr_flag { + struct { + /* 0: There is no order with other WR. + * 1: relax order. + * 2: strong order. + * 3: reserve. + */ + u32 place_order : 2; + /* 0: There is no completion order with other WR + * 1: Completion order with previous WR. + */ + u32 comp_order : 1; + /* 0: There is no fence. + * 1: Fence with previous read and atomic WR + */ + u32 fence : 1; + /* 0: not solicited. + * 1: solicited. It will trigger an event + * on remote side + */ + u32 solicited_enable : 1; + /* 0: Do not notify local process + * after the task is complete. + * 1: Notify local process + * after the task is completed. + */ + u32 complete_enable : 1; + /* 0: No inline. + * 1: Inline data. + */ + u32 inline_flag : 1; + u32 reserved : 25; + } bs; + u32 value; +}; + +struct cdma_sge_info { + u64 addr; + u32 len; + struct dma_seg *seg; +}; + +struct cdma_sg { + struct cdma_sge_info *sge; + u32 num_sge; +}; + +struct cdma_rw_wr { + struct cdma_sg src; + struct cdma_sg dst; + u8 target_hint; /* hint of jetty in a target jetty group */ + u64 notify_data; /* notify data or immeditate data in host byte order */ + u64 notify_addr; + u32 notify_tokenid; + u32 notify_tokenvalue; +}; + +struct cdma_jfs_wr { + enum cdma_wr_opcode opcode; + union cdma_jfs_wr_flag flag; + u32 tpn; + u32 rmt_eid; + union { + struct cdma_rw_wr rw; + }; + struct cdma_jfs_wr *next; +}; + struct cdma_jfs { struct cdma_base_jfs base_jfs; struct cdma_dev *dev; @@ -155,5 +223,7 @@ struct cdma_base_jfs *cdma_create_jfs(struct cdma_dev *cdev, struct cdma_jfs_cfg *cfg, struct cdma_udata *udata); int cdma_delete_jfs(struct cdma_dev *cdev, u32 jfs_id); +int cdma_post_jfs_wr(struct cdma_jfs *jfs, struct cdma_jfs_wr *wr, + struct cdma_jfs_wr **bad_wr); #endif diff --git a/drivers/ub/cdma/cdma_types.h b/drivers/ub/cdma/cdma_types.h index afd59c2c4731..0b861c891558 100644 --- a/drivers/ub/cdma/cdma_types.h +++ b/drivers/ub/cdma/cdma_types.h @@ -121,6 +121,15 @@ struct cdma_base_jfc { struct cdma_jfc_event jfc_event; }; +enum cdma_wr_opcode { + CDMA_WR_OPC_WRITE = 0x00, + CDMA_WR_OPC_WRITE_NOTIFY = 0x02, + CDMA_WR_OPC_READ = 0x10, + CDMA_WR_OPC_CAS = 0x20, + CDMA_WR_OPC_FADD = 0x22, + CDMA_WR_OPC_LAST +}; + struct cdma_mn { struct mmu_notifier mn; struct mm_struct *mm; diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index ff69c268b569..bc30586a5c4f 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -72,6 +72,11 @@ struct dma_context { u32 tid; /* data valid only in bit 0-19 */ }; +enum dma_status { + DMA_STATUS_OK, + DMA_STATUS_INVAL, +}; + struct dma_device *dma_get_device_list(u32 *num_devices); void dma_free_device_list(struct dma_device *dev_list, u32 num_devices); @@ -96,6 +101,9 @@ struct dma_seg *dma_import_seg(struct dma_seg_cfg *cfg); void dma_unimport_seg(struct dma_seg *dma_seg); +enum dma_status dma_write(struct dma_device *dma_dev, struct dma_seg *rmt_seg, + struct dma_seg *local_seg, int queue_id); + int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, struct dma_cr *cr); -- Gitee From ee5d7b631b5ba539d8983254e82000d79a5ea11e Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 15:53:44 +0800 Subject: [PATCH 084/103] ub: cdma: support dma write semantic delivery commit 43aea2fc121a93eb5c3f95992018763b7860b0c9 openEuler This patch implements the functionality of issuing dma write semantics in the CDMA driver. The implementation includes executing the issuance of semantics after the configuration of semantics in the dma_write interface is completed. Signed-off-by: Zhipeng Lu Signed-off-by: Jinjie Cui Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma_common.h | 6 + drivers/ub/cdma/cdma_handle.c | 8 +- drivers/ub/cdma/cdma_jfs.c | 301 ++++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_jfs.h | 49 ++++++ 4 files changed, 363 insertions(+), 1 deletion(-) diff --git a/drivers/ub/cdma/cdma_common.h b/drivers/ub/cdma/cdma_common.h index 3d45f64f5926..a0bb3758ae3a 100644 --- a/drivers/ub/cdma/cdma_common.h +++ b/drivers/ub/cdma/cdma_common.h @@ -30,6 +30,12 @@ #define SQE_PLD_TOKEN_ID_MASK GENMASK(19, 0) +/* thanks to include/rdma/ib_verbs.h */ +enum cdma_sq_opcode { + CDMA_OPC_WRITE = 0x3, + CDMA_OPC_INVALID = 0x12, +}; + enum cdma_jfsc_mode { CDMA_JFS_MODE, CDMA_JETTY_MODE, diff --git a/drivers/ub/cdma/cdma_handle.c b/drivers/ub/cdma/cdma_handle.c index aa4274aac27b..11446f2a8307 100644 --- a/drivers/ub/cdma/cdma_handle.c +++ b/drivers/ub/cdma/cdma_handle.c @@ -53,6 +53,8 @@ int cdma_write(struct cdma_dev *cdev, struct cdma_queue *queue, { struct cdma_jfs_wr wr = { .opcode = CDMA_WR_OPC_WRITE }; struct cdma_sge_info rmt_sge, local_sge; + struct cdma_jfs_wr *bad_wr = NULL; + int ret; if (cdma_rw_check(cdev, rmt_seg, local_seg)) { dev_err(cdev->dev, "write param check failed.\n"); @@ -68,5 +70,9 @@ int cdma_write(struct cdma_dev *cdev, struct cdma_queue *queue, wr.rw.dst.num_sge = 1; wr.rw.dst.sge = &rmt_sge; - return 0; + ret = cdma_post_jfs_wr((struct cdma_jfs *)queue->jfs, &wr, &bad_wr); + if (ret) + dev_err(cdev->dev, "post jfs for write failed, ret = %d.\n", ret); + + return ret; } diff --git a/drivers/ub/cdma/cdma_jfs.c b/drivers/ub/cdma/cdma_jfs.c index abc05c44432b..86bc71851731 100644 --- a/drivers/ub/cdma/cdma_jfs.c +++ b/drivers/ub/cdma/cdma_jfs.c @@ -558,3 +558,304 @@ int cdma_delete_jfs(struct cdma_dev *cdev, u32 jfs_id) return 0; } + +static u8 cdma_get_jfs_opcode(enum cdma_wr_opcode opcode) +{ + switch (opcode) { + case CDMA_WR_OPC_WRITE: + return CDMA_OPC_WRITE; + default: + return CDMA_OPC_INVALID; + } +} + +static inline u32 cdma_get_normal_sge_num(u8 opcode, struct cdma_sqe_ctl *tmp_sq) +{ + return tmp_sq->sge_num; +} + +static bool cdma_k_check_sge_num(u8 opcode, struct cdma_jetty_queue *sq, + struct cdma_jfs_wr *wr) +{ + return wr->rw.src.num_sge > sq->max_sge_num; +} + +static int cdma_fill_sw_sge(struct cdma_sqe_ctl *sqe_ctl, + struct cdma_jfs_wr *wr, + struct cdma_normal_sge *sge) +{ + struct cdma_sge_info *sge_info; + u32 sge_num = 0; + u32 num_sge; + u32 i; + + switch (wr->opcode) { + case CDMA_WR_OPC_WRITE: + sge_info = wr->rw.src.sge; + num_sge = wr->rw.src.num_sge; + break; + default: + return -EINVAL; + } + + for (i = 0; i < num_sge; i++) { + if (sge_info[i].len == 0) + continue; + sge->va = sge_info[i].addr; + sge->length = sge_info[i].len; + sge->token_id = sge_info[i].seg->tid; + sge++; + sge_num++; + } + sqe_ctl->sge_num = sge_num; + + return 0; +} + +static inline u32 cdma_get_ctl_len(u8 opcode) +{ + return SQE_NORMAL_CTL_LEN; +} + +static int cdma_k_fill_write_sqe(struct cdma_dev *cdev, + struct cdma_sqe_ctl *sqe_ctl, + struct cdma_jfs_wr *wr) +{ + struct cdma_sge_info *sge_info; + struct cdma_normal_sge *sge; + u32 ctrl_len; + + ctrl_len = cdma_get_ctl_len(sqe_ctl->opcode); + sge = (struct cdma_normal_sge *)((void *)sqe_ctl + ctrl_len); + + if (cdma_fill_sw_sge(sqe_ctl, wr, sge)) + return -EINVAL; + + sge_info = wr->rw.dst.sge; + + sqe_ctl->toid = sge_info[0].seg->tid; + sqe_ctl->token_en = sge_info[0].seg->token_value_valid; + sqe_ctl->rmt_token_value = sge_info[0].seg->token_value; + sqe_ctl->target_hint = wr->rw.target_hint; + sqe_ctl->rmt_addr_l_or_token_id = + sge_info[0].addr & (u32)SQE_CTL_RMA_ADDR_BIT; + sqe_ctl->rmt_addr_h_or_token_value = + (sge_info[0].addr >> (u32)SQE_CTL_RMA_ADDR_OFFSET) & + (u32)SQE_CTL_RMA_ADDR_BIT; + + return 0; +} + +static int cdma_fill_normal_sge(struct cdma_dev *cdev, + struct cdma_sqe_ctl *sqe_ctl, + struct cdma_jfs_wr *wr) +{ + switch (wr->opcode) { + case CDMA_WR_OPC_WRITE: + return cdma_k_fill_write_sqe(cdev, sqe_ctl, wr); + default: + dev_err(cdev->dev, "cdma wr opcode invalid, opcode = %u.\n", + (u8)wr->opcode); + return -EINVAL; + } +} + +static int cdma_set_sqe(struct cdma_dev *cdev, struct cdma_sqe_ctl *sqe_ctl, + struct cdma_jfs_wr *wr, struct cdma_jetty_queue *sq, + u8 opcode) +{ + int ret; + + sqe_ctl->cqe = wr->flag.bs.complete_enable; + sqe_ctl->owner = (sq->pi & sq->buf.entry_cnt) == 0 ? 1 : 0; + sqe_ctl->opcode = opcode; + sqe_ctl->tpn = wr->tpn; + sqe_ctl->place_odr = wr->flag.bs.place_order; + sqe_ctl->fence = wr->flag.bs.fence; + sqe_ctl->comp_order = wr->flag.bs.comp_order; + sqe_ctl->se = wr->flag.bs.solicited_enable; + sqe_ctl->inline_en = 0; + memcpy(sqe_ctl->rmt_eid, &wr->rmt_eid, sizeof(wr->rmt_eid)); + + ret = cdma_fill_normal_sge(cdev, sqe_ctl, wr); + if (ret) + dev_err(cdev->dev, + "cdma fill normal sge failed, wr opcode = %u.\n", + (u8)wr->opcode); + + return ret; +} + +static u32 cdma_cal_wqebb_num(struct cdma_jfs_wr *wr, u8 opcode, + struct cdma_sqe_ctl *tmp_sq) +{ + u32 normal_sge_num; + u32 sqe_ctl_len; + u32 wqebb_cnt; + + sqe_ctl_len = cdma_get_ctl_len(opcode); + + normal_sge_num = cdma_get_normal_sge_num(opcode, tmp_sq); + wqebb_cnt = cdma_sq_cal_wqebb_num(sqe_ctl_len, normal_sge_num); + + return wqebb_cnt; +} + +static inline bool to_check_sq_overflow(struct cdma_jetty_queue *sq, + u32 wqebb_cnt) +{ + return (sq->pi - sq->ci + wqebb_cnt) > sq->buf.entry_cnt; +} + +static int cdma_copy_to_sq(struct cdma_jetty_queue *sq, u32 wqebb_cnt, + struct cdma_jfs_wqebb *tmp_sq) +{ + u32 remain = sq->buf.entry_cnt - (sq->pi & (sq->buf.entry_cnt - 1)); + u32 tail_cnt; + u32 head_cnt; + + if (to_check_sq_overflow(sq, wqebb_cnt)) + return -ENOMEM; + + tail_cnt = remain > wqebb_cnt ? wqebb_cnt : remain; + head_cnt = wqebb_cnt - tail_cnt; + + memcpy(sq->kva_curr, tmp_sq, tail_cnt * sizeof(*tmp_sq)); + if (head_cnt) + memcpy(sq->buf.kva, tmp_sq + tail_cnt, + head_cnt * sizeof(*tmp_sq)); + + return 0; +} + +static void *cdma_k_update_ptr(u32 total_size, u32 wqebb_size, u8 *base_addr, + u8 *curr_addr) +{ + u8 *end_addr; + + end_addr = base_addr + total_size; + curr_addr = ((curr_addr + wqebb_size) < end_addr) ? + (curr_addr + wqebb_size) : + base_addr + (curr_addr + wqebb_size - end_addr); + + return curr_addr; +} + +static int cdma_post_one_wr(struct cdma_jetty_queue *sq, struct cdma_jfs_wr *wr, + struct cdma_dev *cdev, + struct cdma_sqe_ctl **dwqe_addr, u8 *dwqe_enable) +{ + struct cdma_jfs_wqebb tmp_sq[MAX_WQEBB_NUM] = { 0 }; + u32 wqebb_cnt; + u8 opcode; + int ret; + + opcode = cdma_get_jfs_opcode(wr->opcode); + if (opcode == CDMA_OPC_INVALID) { + dev_err(cdev->dev, "cdma invalid opcode = %u.\n", wr->opcode); + return -EINVAL; + } + + if (cdma_k_check_sge_num(opcode, sq, wr)) { + dev_err(cdev->dev, "cdma sge num invalid, opcode = %u.\n", + opcode); + return -EINVAL; + } + + ret = cdma_set_sqe(cdev, (struct cdma_sqe_ctl *)tmp_sq, wr, sq, opcode); + if (ret) + return ret; + + wqebb_cnt = + cdma_cal_wqebb_num(wr, opcode, (struct cdma_sqe_ctl *)tmp_sq); + if (wqebb_cnt == 1 && + !!(cdev->caps.feature & CDMA_CAP_FEATURE_DIRECT_WQE)) + *dwqe_enable = 1; + + ret = cdma_copy_to_sq(sq, wqebb_cnt, tmp_sq); + if (ret) { + dev_err(cdev->dev, "cdma jfs overflow, wqebb_cnt = %u.\n", + wqebb_cnt); + return ret; + } + + *dwqe_addr = sq->kva_curr; + + sq->kva_curr = cdma_k_update_ptr(sq->buf.entry_cnt * sq->buf.entry_size, + wqebb_cnt * sq->buf.entry_size, + (u8 *)sq->buf.kva, (u8 *)sq->kva_curr); + + sq->pi += wqebb_cnt; + + return 0; +} + +static void cdma_write_dsqe(struct cdma_jetty_queue *sq, + struct cdma_sqe_ctl *ctrl) +{ +#define DWQE_SIZE 8 + int i; + + ctrl->sqe_bb_idx = sq->pi; + for (i = 0; i < DWQE_SIZE; i++) + writeq_relaxed(*((u64 *)ctrl + i), (u64 *)sq->dwqe_addr + i); +} + +static inline void cdma_k_update_sq_db(struct cdma_jetty_queue *sq) +{ + u32 *db_addr = (u32 *)sq->db_addr; + *db_addr = sq->pi; +} + +/* thanks to drivers/infiniband/hw/bnxt_re/ib_verbs.c */ +static int cdma_post_sq_wr(struct cdma_dev *cdev, struct cdma_jetty_queue *sq, + struct cdma_jfs_wr *wr, struct cdma_jfs_wr **bad_wr) +{ + struct cdma_sqe_ctl *dwqe_addr; + struct cdma_jfs_wr *it; + u8 dwqe_enable = 0; + int wr_cnt = 0; + int ret = 0; + + spin_lock(&sq->lock); + + for (it = wr; it != NULL; it = it->next) { + ret = cdma_post_one_wr(sq, it, cdev, &dwqe_addr, &dwqe_enable); + if (ret) { + dev_err(cdev->dev, "cdma post one wr failed.\n"); + *bad_wr = it; + goto post_wr; + } + wr_cnt++; + } + +post_wr: + if (wr_cnt) { + if (cdev->status != CDMA_SUSPEND) { + /* Ensure the order of write memory operations */ + wmb(); + if (wr_cnt == 1 && dwqe_enable && (sq->pi - sq->ci == 1)) + cdma_write_dsqe(sq, dwqe_addr); + else + cdma_k_update_sq_db(sq); + } + } + + spin_unlock(&sq->lock); + + return ret; +} + +int cdma_post_jfs_wr(struct cdma_jfs *jfs, struct cdma_jfs_wr *wr, + struct cdma_jfs_wr **bad_wr) +{ + struct cdma_dev *cdev = jfs->dev; + int ret; + + ret = cdma_post_sq_wr(cdev, &jfs->sq, wr, bad_wr); + if (ret) + dev_err(cdev->dev, + "cdma post jfs wr failed, sq_id = %u.\n", jfs->sq.id); + + return ret; +} diff --git a/drivers/ub/cdma/cdma_jfs.h b/drivers/ub/cdma/cdma_jfs.h index b34821701511..98374b278737 100644 --- a/drivers/ub/cdma/cdma_jfs.h +++ b/drivers/ub/cdma/cdma_jfs.h @@ -9,9 +9,13 @@ #include "cdma_segment.h" #define MAX_WQEBB_NUM 4 +#define CDMA_SQE_RMT_EID_SIZE 4 #define CDMA_JFS_WQEBB_SIZE 64 +#define SQE_NORMAL_CTL_LEN 48 #define CDMA_JFS_SGE_SIZE 16 #define SQE_WRITE_NOTIFY_CTL_LEN 80 +#define SQE_CTL_RMA_ADDR_OFFSET 32 +#define SQE_CTL_RMA_ADDR_BIT GENMASK(31, 0) #define CDMA_TA_TIMEOUT_128MS 128 #define CDMA_TA_TIMEOUT_1000MS 1000 @@ -20,6 +24,45 @@ #define CDMA_RCV_SEND_MAX_DIFF 512U +struct cdma_jfs_wqebb { + u32 value[16]; +}; + +struct cdma_sqe_ctl { + /* DW0 */ + u32 sqe_bb_idx : 16; + u32 place_odr : 2; + u32 comp_order : 1; + u32 fence : 1; + u32 se : 1; + u32 cqe : 1; + u32 inline_en : 1; + u32 rsv : 5; + u32 token_en : 1; + u32 rmt_jetty_type : 2; + u32 owner : 1; + /* DW1 */ + u32 target_hint : 8; + u32 opcode : 8; + u32 rsv1 : 6; + u32 inline_msg_len : 10; + /* DW2 */ + u32 tpn : 24; + u32 sge_num : 8; + /* DW3 */ + u32 toid : 20; + u32 rsv2 : 12; + /* DW4~7 */ + u32 rmt_eid[CDMA_SQE_RMT_EID_SIZE]; + /* DW8 */ + u32 rmt_token_value; + /* DW9~11 */ + u32 rsv3; + u32 rmt_addr_l_or_token_id; + u32 rmt_addr_h_or_token_value; +}; + + union cdma_jfs_wr_flag { struct { /* 0: There is no order with other WR. @@ -62,6 +105,12 @@ struct cdma_sge_info { struct dma_seg *seg; }; +struct cdma_normal_sge { + u32 length; + u32 token_id; + u64 va; +}; + struct cdma_sg { struct cdma_sge_info *sge; u32 num_sge; -- Gitee From bbd0d000f480ee0d9327abac0a95a60884e57004 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 15:56:41 +0800 Subject: [PATCH 085/103] ub: cdma: support dma write with notify semantic commit 26598fa61f1a005665e4dba668fbe5c0844072fa openEuler This patch implements functionality related to the configuration and issuance of DMA write with notify semantics in the CDMA driver. The implementation includes support for the dma_write_with_notify interface and the process of configuring and issuing semantics within this interface. Signed-off-by: Zhipeng Lu Signed-off-by: Jinjie Cui Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma_api.c | 28 +++++++++++++++++++++++++++- drivers/ub/cdma/cdma_common.h | 1 + drivers/ub/cdma/cdma_handle.c | 11 ++++++++++- drivers/ub/cdma/cdma_handle.h | 3 ++- drivers/ub/cdma/cdma_jfs.c | 28 +++++++++++++++++++++++++++- drivers/ub/cdma/cdma_jfs.h | 11 ++++++++++- include/ub/cdma/cdma_api.h | 10 ++++++++++ 7 files changed, 87 insertions(+), 5 deletions(-) diff --git a/drivers/ub/cdma/cdma_api.c b/drivers/ub/cdma/cdma_api.c index c3656793abb2..33f9ce38bb98 100644 --- a/drivers/ub/cdma/cdma_api.c +++ b/drivers/ub/cdma/cdma_api.c @@ -491,7 +491,7 @@ enum dma_status dma_write(struct dma_device *dma_dev, struct dma_seg *rmt_seg, if (ret) return DMA_STATUS_INVAL; - ret = cdma_write(cdev, cdma_queue, local_seg, rmt_seg); + ret = cdma_write(cdev, cdma_queue, local_seg, rmt_seg, NULL); if (ret) return DMA_STATUS_INVAL; @@ -499,6 +499,32 @@ enum dma_status dma_write(struct dma_device *dma_dev, struct dma_seg *rmt_seg, } EXPORT_SYMBOL_GPL(dma_write); +enum dma_status dma_write_with_notify(struct dma_device *dma_dev, + struct dma_seg *rmt_seg, + struct dma_seg *local_seg, int queue_id, + struct dma_notify_data *data) +{ + struct cdma_queue *cdma_queue = NULL; + struct cdma_dev *cdev = NULL; + int ret; + + if (!dma_dev || !rmt_seg || !local_seg || !data || !data->notify_seg) { + pr_err("write with notify input parameters error.\n"); + return DMA_STATUS_INVAL; + } + + ret = cdma_param_transfer(dma_dev, queue_id, &cdev, &cdma_queue); + if (ret) + return DMA_STATUS_INVAL; + + ret = cdma_write(cdev, cdma_queue, local_seg, rmt_seg, data); + if (ret) + return DMA_STATUS_INVAL; + + return DMA_STATUS_OK; +} +EXPORT_SYMBOL_GPL(dma_write_with_notify); + int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, struct dma_cr *cr) { diff --git a/drivers/ub/cdma/cdma_common.h b/drivers/ub/cdma/cdma_common.h index a0bb3758ae3a..cd4f48c2dce4 100644 --- a/drivers/ub/cdma/cdma_common.h +++ b/drivers/ub/cdma/cdma_common.h @@ -33,6 +33,7 @@ /* thanks to include/rdma/ib_verbs.h */ enum cdma_sq_opcode { CDMA_OPC_WRITE = 0x3, + CDMA_OPC_WRITE_WITH_NOTIFY = 0x5, CDMA_OPC_INVALID = 0x12, }; diff --git a/drivers/ub/cdma/cdma_handle.c b/drivers/ub/cdma/cdma_handle.c index 11446f2a8307..ca6daeb03f4c 100644 --- a/drivers/ub/cdma/cdma_handle.c +++ b/drivers/ub/cdma/cdma_handle.c @@ -49,7 +49,8 @@ static inline void cdma_fill_sge(struct cdma_sge_info *rmt_sge, } int cdma_write(struct cdma_dev *cdev, struct cdma_queue *queue, - struct dma_seg *local_seg, struct dma_seg *rmt_seg) + struct dma_seg *local_seg, struct dma_seg *rmt_seg, + struct dma_notify_data *data) { struct cdma_jfs_wr wr = { .opcode = CDMA_WR_OPC_WRITE }; struct cdma_sge_info rmt_sge, local_sge; @@ -61,6 +62,14 @@ int cdma_write(struct cdma_dev *cdev, struct cdma_queue *queue, return -EINVAL; } + if (data) { + wr.opcode = CDMA_WR_OPC_WRITE_NOTIFY; + wr.rw.notify_addr = data->notify_seg->sva; + wr.rw.notify_data = data->notify_data; + wr.rw.notify_tokenid = data->notify_seg->tid; + wr.rw.notify_tokenvalue = data->notify_seg->token_value; + } + cdma_fill_comm_wr(&wr, queue); cdma_fill_sge(&rmt_sge, &local_sge, rmt_seg, local_seg); diff --git a/drivers/ub/cdma/cdma_handle.h b/drivers/ub/cdma/cdma_handle.h index 27a3f9495d18..e9394e2c321a 100644 --- a/drivers/ub/cdma/cdma_handle.h +++ b/drivers/ub/cdma/cdma_handle.h @@ -9,6 +9,7 @@ #include "cdma.h" int cdma_write(struct cdma_dev *cdev, struct cdma_queue *queue, - struct dma_seg *local_seg, struct dma_seg *rmt_seg); + struct dma_seg *local_seg, struct dma_seg *rmt_seg, + struct dma_notify_data *data); #endif /* CDMA_HANDLE_H */ diff --git a/drivers/ub/cdma/cdma_jfs.c b/drivers/ub/cdma/cdma_jfs.c index 86bc71851731..e8a1677a1f2e 100644 --- a/drivers/ub/cdma/cdma_jfs.c +++ b/drivers/ub/cdma/cdma_jfs.c @@ -564,6 +564,8 @@ static u8 cdma_get_jfs_opcode(enum cdma_wr_opcode opcode) switch (opcode) { case CDMA_WR_OPC_WRITE: return CDMA_OPC_WRITE; + case CDMA_WR_OPC_WRITE_NOTIFY: + return CDMA_OPC_WRITE_WITH_NOTIFY; default: return CDMA_OPC_INVALID; } @@ -577,7 +579,13 @@ static inline u32 cdma_get_normal_sge_num(u8 opcode, struct cdma_sqe_ctl *tmp_sq static bool cdma_k_check_sge_num(u8 opcode, struct cdma_jetty_queue *sq, struct cdma_jfs_wr *wr) { - return wr->rw.src.num_sge > sq->max_sge_num; + switch (opcode) { + case CDMA_OPC_WRITE_WITH_NOTIFY: + return wr->rw.src.num_sge > CDMA_JFS_MAX_SGE_NOTIFY || + wr->rw.src.num_sge > sq->max_sge_num; + default: + return wr->rw.src.num_sge > sq->max_sge_num; + } } static int cdma_fill_sw_sge(struct cdma_sqe_ctl *sqe_ctl, @@ -591,6 +599,7 @@ static int cdma_fill_sw_sge(struct cdma_sqe_ctl *sqe_ctl, switch (wr->opcode) { case CDMA_WR_OPC_WRITE: + case CDMA_WR_OPC_WRITE_NOTIFY: sge_info = wr->rw.src.sge; num_sge = wr->rw.src.num_sge; break; @@ -614,6 +623,9 @@ static int cdma_fill_sw_sge(struct cdma_sqe_ctl *sqe_ctl, static inline u32 cdma_get_ctl_len(u8 opcode) { + if (opcode == CDMA_OPC_WRITE_WITH_NOTIFY) + return SQE_WRITE_NOTIFY_CTL_LEN; + return SQE_NORMAL_CTL_LEN; } @@ -621,6 +633,7 @@ static int cdma_k_fill_write_sqe(struct cdma_dev *cdev, struct cdma_sqe_ctl *sqe_ctl, struct cdma_jfs_wr *wr) { + struct cdma_token_info *token_info; struct cdma_sge_info *sge_info; struct cdma_normal_sge *sge; u32 ctrl_len; @@ -643,6 +656,18 @@ static int cdma_k_fill_write_sqe(struct cdma_dev *cdev, (sge_info[0].addr >> (u32)SQE_CTL_RMA_ADDR_OFFSET) & (u32)SQE_CTL_RMA_ADDR_BIT; + if (sqe_ctl->opcode == CDMA_OPC_WRITE_WITH_NOTIFY) { + token_info = (struct cdma_token_info *) + ((void *)sqe_ctl + SQE_NOTIFY_TOKEN_ID_FIELD); + token_info->token_id = wr->rw.notify_tokenid; + token_info->token_value = wr->rw.notify_tokenvalue; + + memcpy((void *)sqe_ctl + SQE_NOTIFY_ADDR_FIELD, + &wr->rw.notify_addr, sizeof(u64)); + memcpy((void *)sqe_ctl + SQE_ATOMIC_DATA_FIELD, + &wr->rw.notify_data, sizeof(u64)); + } + return 0; } @@ -652,6 +677,7 @@ static int cdma_fill_normal_sge(struct cdma_dev *cdev, { switch (wr->opcode) { case CDMA_WR_OPC_WRITE: + case CDMA_WR_OPC_WRITE_NOTIFY: return cdma_k_fill_write_sqe(cdev, sqe_ctl, wr); default: dev_err(cdev->dev, "cdma wr opcode invalid, opcode = %u.\n", diff --git a/drivers/ub/cdma/cdma_jfs.h b/drivers/ub/cdma/cdma_jfs.h index 98374b278737..b94f8aca2d99 100644 --- a/drivers/ub/cdma/cdma_jfs.h +++ b/drivers/ub/cdma/cdma_jfs.h @@ -12,10 +12,14 @@ #define CDMA_SQE_RMT_EID_SIZE 4 #define CDMA_JFS_WQEBB_SIZE 64 #define SQE_NORMAL_CTL_LEN 48 +#define CDMA_JFS_MAX_SGE_NOTIFY 11 #define CDMA_JFS_SGE_SIZE 16 #define SQE_WRITE_NOTIFY_CTL_LEN 80 #define SQE_CTL_RMA_ADDR_OFFSET 32 #define SQE_CTL_RMA_ADDR_BIT GENMASK(31, 0) +#define SQE_NOTIFY_TOKEN_ID_FIELD 48 +#define SQE_NOTIFY_ADDR_FIELD 56 +#define SQE_ATOMIC_DATA_FIELD 64 #define CDMA_TA_TIMEOUT_128MS 128 #define CDMA_TA_TIMEOUT_1000MS 1000 @@ -28,6 +32,12 @@ struct cdma_jfs_wqebb { u32 value[16]; }; +struct cdma_token_info { + u32 token_id : 20; + u32 rsv : 12; + u32 token_value; +}; + struct cdma_sqe_ctl { /* DW0 */ u32 sqe_bb_idx : 16; @@ -62,7 +72,6 @@ struct cdma_sqe_ctl { u32 rmt_addr_h_or_token_value; }; - union cdma_jfs_wr_flag { struct { /* 0: There is no order with other WR. diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index bc30586a5c4f..39dff8f6378f 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -77,6 +77,11 @@ enum dma_status { DMA_STATUS_INVAL, }; +struct dma_notify_data { + struct dma_seg *notify_seg; + u64 notify_data; +}; + struct dma_device *dma_get_device_list(u32 *num_devices); void dma_free_device_list(struct dma_device *dev_list, u32 num_devices); @@ -104,6 +109,11 @@ void dma_unimport_seg(struct dma_seg *dma_seg); enum dma_status dma_write(struct dma_device *dma_dev, struct dma_seg *rmt_seg, struct dma_seg *local_seg, int queue_id); +enum dma_status dma_write_with_notify(struct dma_device *dma_dev, + struct dma_seg *rmt_seg, + struct dma_seg *local_seg, int queue_id, + struct dma_notify_data *data); + int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, struct dma_cr *cr); -- Gitee From 5b913496059560390bf10e561272408a3f67a568 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 29 Aug 2025 15:59:42 +0800 Subject: [PATCH 086/103] ub: cdma: support dma read semantic commit 75367599a7c1a46e8705a01b176762bb8715d233 openEuler This patch implements functionality related to the configuration and issuance of DMA read semantics in the CDMA driver. The implementation includes support for the dma_read interface and the process of configuring and issuing semantics within this interface. Signed-off-by: Zhipeng Lu Signed-off-by: Jinjie Cui Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma_api.c | 24 ++++++++++++++++++++ drivers/ub/cdma/cdma_common.h | 1 + drivers/ub/cdma/cdma_handle.c | 29 ++++++++++++++++++++++++ drivers/ub/cdma/cdma_handle.h | 2 ++ drivers/ub/cdma/cdma_jfs.c | 42 +++++++++++++++++++++++++++++++++++ include/ub/cdma/cdma_api.h | 3 +++ 6 files changed, 101 insertions(+) diff --git a/drivers/ub/cdma/cdma_api.c b/drivers/ub/cdma/cdma_api.c index 33f9ce38bb98..c4038ad740c5 100644 --- a/drivers/ub/cdma/cdma_api.c +++ b/drivers/ub/cdma/cdma_api.c @@ -525,6 +525,30 @@ enum dma_status dma_write_with_notify(struct dma_device *dma_dev, } EXPORT_SYMBOL_GPL(dma_write_with_notify); +enum dma_status dma_read(struct dma_device *dma_dev, struct dma_seg *rmt_seg, + struct dma_seg *local_seg, int queue_id) +{ + struct cdma_queue *cdma_queue = NULL; + struct cdma_dev *cdev = NULL; + int ret; + + if (!dma_dev || !rmt_seg || !local_seg) { + pr_err("read input parameters error.\n"); + return DMA_STATUS_INVAL; + } + + ret = cdma_param_transfer(dma_dev, queue_id, &cdev, &cdma_queue); + if (ret) + return DMA_STATUS_INVAL; + + ret = cdma_read(cdev, cdma_queue, local_seg, rmt_seg); + if (ret) + return DMA_STATUS_INVAL; + + return DMA_STATUS_OK; +} +EXPORT_SYMBOL_GPL(dma_read); + int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, struct dma_cr *cr) { diff --git a/drivers/ub/cdma/cdma_common.h b/drivers/ub/cdma/cdma_common.h index cd4f48c2dce4..3858756a9e5b 100644 --- a/drivers/ub/cdma/cdma_common.h +++ b/drivers/ub/cdma/cdma_common.h @@ -34,6 +34,7 @@ enum cdma_sq_opcode { CDMA_OPC_WRITE = 0x3, CDMA_OPC_WRITE_WITH_NOTIFY = 0x5, + CDMA_OPC_READ = 0x6, CDMA_OPC_INVALID = 0x12, }; diff --git a/drivers/ub/cdma/cdma_handle.c b/drivers/ub/cdma/cdma_handle.c index ca6daeb03f4c..8646e2b08519 100644 --- a/drivers/ub/cdma/cdma_handle.c +++ b/drivers/ub/cdma/cdma_handle.c @@ -85,3 +85,32 @@ int cdma_write(struct cdma_dev *cdev, struct cdma_queue *queue, return ret; } + +int cdma_read(struct cdma_dev *cdev, struct cdma_queue *queue, + struct dma_seg *local_seg, struct dma_seg *rmt_seg) +{ + struct cdma_jfs_wr wr = { .opcode = CDMA_WR_OPC_READ }; + struct cdma_sge_info rmt_sge, local_sge; + struct cdma_jfs_wr *bad_wr = NULL; + int ret; + + if (cdma_rw_check(cdev, rmt_seg, local_seg)) { + dev_err(cdev->dev, "read param check failed.\n"); + return -EINVAL; + } + + cdma_fill_comm_wr(&wr, queue); + + cdma_fill_sge(&rmt_sge, &local_sge, rmt_seg, local_seg); + + wr.rw.src.num_sge = 1; + wr.rw.src.sge = &rmt_sge; + wr.rw.dst.num_sge = 1; + wr.rw.dst.sge = &local_sge; + + ret = cdma_post_jfs_wr((struct cdma_jfs *)queue->jfs, &wr, &bad_wr); + if (ret) + dev_err(cdev->dev, "post jfs for read failed, ret = %d.\n", ret); + + return ret; +} diff --git a/drivers/ub/cdma/cdma_handle.h b/drivers/ub/cdma/cdma_handle.h index e9394e2c321a..aaf7ad61044f 100644 --- a/drivers/ub/cdma/cdma_handle.h +++ b/drivers/ub/cdma/cdma_handle.h @@ -11,5 +11,7 @@ int cdma_write(struct cdma_dev *cdev, struct cdma_queue *queue, struct dma_seg *local_seg, struct dma_seg *rmt_seg, struct dma_notify_data *data); +int cdma_read(struct cdma_dev *cdev, struct cdma_queue *queue, + struct dma_seg *local_seg, struct dma_seg *rmt_seg); #endif /* CDMA_HANDLE_H */ diff --git a/drivers/ub/cdma/cdma_jfs.c b/drivers/ub/cdma/cdma_jfs.c index e8a1677a1f2e..a505a00361cb 100644 --- a/drivers/ub/cdma/cdma_jfs.c +++ b/drivers/ub/cdma/cdma_jfs.c @@ -566,6 +566,8 @@ static u8 cdma_get_jfs_opcode(enum cdma_wr_opcode opcode) return CDMA_OPC_WRITE; case CDMA_WR_OPC_WRITE_NOTIFY: return CDMA_OPC_WRITE_WITH_NOTIFY; + case CDMA_WR_OPC_READ: + return CDMA_OPC_READ; default: return CDMA_OPC_INVALID; } @@ -580,6 +582,8 @@ static bool cdma_k_check_sge_num(u8 opcode, struct cdma_jetty_queue *sq, struct cdma_jfs_wr *wr) { switch (opcode) { + case CDMA_OPC_READ: + return wr->rw.dst.num_sge > sq->max_sge_num; case CDMA_OPC_WRITE_WITH_NOTIFY: return wr->rw.src.num_sge > CDMA_JFS_MAX_SGE_NOTIFY || wr->rw.src.num_sge > sq->max_sge_num; @@ -671,6 +675,42 @@ static int cdma_k_fill_write_sqe(struct cdma_dev *cdev, return 0; } +static int cdma_k_fill_read_sqe(struct cdma_dev *cdev, + struct cdma_sqe_ctl *sqe_ctl, + struct cdma_jfs_wr *wr) +{ + struct cdma_sge_info *sge_info; + struct cdma_normal_sge *sge; + u32 sge_num = 0; + u32 num; + + sge = (struct cdma_normal_sge *)(sqe_ctl + 1); + sge_info = wr->rw.dst.sge; + + for (num = 0; num < wr->rw.dst.num_sge; num++) { + if (!sge_info[num].len) + continue; + sge->va = sge_info[num].addr; + sge->length = sge_info[num].len; + sge->token_id = sge_info[num].seg->tid; + sge++; + sge_num++; + } + + sge_info = wr->rw.src.sge; + sqe_ctl->sge_num = sge_num; + sqe_ctl->toid = sge_info[0].seg->tid; + sqe_ctl->token_en = sge_info[0].seg->token_value_valid; + sqe_ctl->rmt_token_value = sge_info[0].seg->token_value; + sqe_ctl->rmt_addr_l_or_token_id = + sge_info[0].addr & (u32)SQE_CTL_RMA_ADDR_BIT; + sqe_ctl->rmt_addr_h_or_token_value = + (sge_info[0].addr >> (u32)SQE_CTL_RMA_ADDR_OFFSET) & + (u32)SQE_CTL_RMA_ADDR_BIT; + + return 0; +} + static int cdma_fill_normal_sge(struct cdma_dev *cdev, struct cdma_sqe_ctl *sqe_ctl, struct cdma_jfs_wr *wr) @@ -679,6 +719,8 @@ static int cdma_fill_normal_sge(struct cdma_dev *cdev, case CDMA_WR_OPC_WRITE: case CDMA_WR_OPC_WRITE_NOTIFY: return cdma_k_fill_write_sqe(cdev, sqe_ctl, wr); + case CDMA_WR_OPC_READ: + return cdma_k_fill_read_sqe(cdev, sqe_ctl, wr); default: dev_err(cdev->dev, "cdma wr opcode invalid, opcode = %u.\n", (u8)wr->opcode); diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index 39dff8f6378f..eb425553d6ac 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -114,6 +114,9 @@ enum dma_status dma_write_with_notify(struct dma_device *dma_dev, struct dma_seg *local_seg, int queue_id, struct dma_notify_data *data); +enum dma_status dma_read(struct dma_device *dma_dev, struct dma_seg *rmt_seg, + struct dma_seg *local_seg, int queue_id); + int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, struct dma_cr *cr); -- Gitee From 6bf84d44a6d32accc106935968ed55fd4a1cd12b Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Mon, 25 Aug 2025 21:43:46 +0800 Subject: [PATCH 087/103] ub: cdma: support dma cas semantic commit 89f3c2b942a6cc9812e123be53644044d201037a openEuler This patch implements functionality related to the configuration and issuance of DMA cas semantics in the CDMA driver. The implementation includes support for the dma_cas interface and the process of configuring and issuing semantics within this interface. Signed-off-by: Zhipeng Lu Signed-off-by: Jinjie Cui Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma_api.c | 25 ++++++++++++ drivers/ub/cdma/cdma_common.h | 5 +++ drivers/ub/cdma/cdma_handle.c | 36 +++++++++++++++++ drivers/ub/cdma/cdma_handle.h | 3 ++ drivers/ub/cdma/cdma_jfs.c | 73 ++++++++++++++++++++++++++++++++++- drivers/ub/cdma/cdma_jfs.h | 23 +++++++++++ include/ub/cdma/cdma_api.h | 9 +++++ 7 files changed, 173 insertions(+), 1 deletion(-) diff --git a/drivers/ub/cdma/cdma_api.c b/drivers/ub/cdma/cdma_api.c index c4038ad740c5..e9fec2437cd5 100644 --- a/drivers/ub/cdma/cdma_api.c +++ b/drivers/ub/cdma/cdma_api.c @@ -549,6 +549,31 @@ enum dma_status dma_read(struct dma_device *dma_dev, struct dma_seg *rmt_seg, } EXPORT_SYMBOL_GPL(dma_read); +enum dma_status dma_cas(struct dma_device *dma_dev, struct dma_seg *rmt_seg, + struct dma_seg *local_seg, int queue_id, + struct dma_cas_data *data) +{ + struct cdma_queue *cdma_queue = NULL; + struct cdma_dev *cdev = NULL; + int ret; + + if (!dma_dev || !rmt_seg || !local_seg || !data) { + pr_err("cas input parameters error.\n"); + return DMA_STATUS_INVAL; + } + + ret = cdma_param_transfer(dma_dev, queue_id, &cdev, &cdma_queue); + if (ret) + return DMA_STATUS_INVAL; + + ret = cdma_cas(cdev, cdma_queue, local_seg, rmt_seg, data); + if (ret) + return DMA_STATUS_INVAL; + + return DMA_STATUS_OK; +} +EXPORT_SYMBOL_GPL(dma_cas); + int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, struct dma_cr *cr) { diff --git a/drivers/ub/cdma/cdma_common.h b/drivers/ub/cdma/cdma_common.h index 3858756a9e5b..54d0e3e43af4 100644 --- a/drivers/ub/cdma/cdma_common.h +++ b/drivers/ub/cdma/cdma_common.h @@ -28,6 +28,10 @@ #define CDMA_DB_SIZE 64 +#define CDMA_ATOMIC_LEN_4 4 +#define CDMA_ATOMIC_LEN_8 8 +#define CDMA_ATOMIC_LEN_16 16 + #define SQE_PLD_TOKEN_ID_MASK GENMASK(19, 0) /* thanks to include/rdma/ib_verbs.h */ @@ -35,6 +39,7 @@ enum cdma_sq_opcode { CDMA_OPC_WRITE = 0x3, CDMA_OPC_WRITE_WITH_NOTIFY = 0x5, CDMA_OPC_READ = 0x6, + CDMA_OPC_CAS, CDMA_OPC_INVALID = 0x12, }; diff --git a/drivers/ub/cdma/cdma_handle.c b/drivers/ub/cdma/cdma_handle.c index 8646e2b08519..b172383e10e6 100644 --- a/drivers/ub/cdma/cdma_handle.c +++ b/drivers/ub/cdma/cdma_handle.c @@ -114,3 +114,39 @@ int cdma_read(struct cdma_dev *cdev, struct cdma_queue *queue, return ret; } + +int cdma_cas(struct cdma_dev *cdev, struct cdma_queue *queue, + struct dma_seg *local_seg, struct dma_seg *rmt_seg, + struct dma_cas_data *data) +{ + struct cdma_jfs_wr wr = { .opcode = CDMA_WR_OPC_CAS }; + struct cdma_sge_info rmt_sge, local_sge; + struct cdma_jfs_wr *bad_wr = NULL; + int ret; + + if (cdma_rw_check(cdev, rmt_seg, local_seg)) { + dev_err(cdev->dev, "cas param check failed.\n"); + return -EINVAL; + } + + cdma_fill_comm_wr(&wr, queue); + + cdma_fill_sge(&rmt_sge, &local_sge, rmt_seg, local_seg); + + wr.cas.src = &local_sge; + wr.cas.dst = &rmt_sge; + + if (local_sge.len <= CDMA_ATOMIC_LEN_8) { + wr.cas.cmp_data = data->compare_data; + wr.cas.swap_data = data->swap_data; + } else { + wr.cas.cmp_addr = data->compare_data; + wr.cas.swap_addr = data->swap_data; + } + + ret = cdma_post_jfs_wr((struct cdma_jfs *)queue->jfs, &wr, &bad_wr); + if (ret) + dev_err(cdev->dev, "post jfs for cas failed, ret = %d.\n", ret); + + return ret; +} diff --git a/drivers/ub/cdma/cdma_handle.h b/drivers/ub/cdma/cdma_handle.h index aaf7ad61044f..8c99a0a0cb32 100644 --- a/drivers/ub/cdma/cdma_handle.h +++ b/drivers/ub/cdma/cdma_handle.h @@ -13,5 +13,8 @@ int cdma_write(struct cdma_dev *cdev, struct cdma_queue *queue, struct dma_notify_data *data); int cdma_read(struct cdma_dev *cdev, struct cdma_queue *queue, struct dma_seg *local_seg, struct dma_seg *rmt_seg); +int cdma_cas(struct cdma_dev *cdev, struct cdma_queue *queue, + struct dma_seg *local_seg, struct dma_seg *rmt_seg, + struct dma_cas_data *data); #endif /* CDMA_HANDLE_H */ diff --git a/drivers/ub/cdma/cdma_jfs.c b/drivers/ub/cdma/cdma_jfs.c index a505a00361cb..79d5074ff4ef 100644 --- a/drivers/ub/cdma/cdma_jfs.c +++ b/drivers/ub/cdma/cdma_jfs.c @@ -568,6 +568,8 @@ static u8 cdma_get_jfs_opcode(enum cdma_wr_opcode opcode) return CDMA_OPC_WRITE_WITH_NOTIFY; case CDMA_WR_OPC_READ: return CDMA_OPC_READ; + case CDMA_WR_OPC_CAS: + return CDMA_OPC_CAS; default: return CDMA_OPC_INVALID; } @@ -575,13 +577,20 @@ static u8 cdma_get_jfs_opcode(enum cdma_wr_opcode opcode) static inline u32 cdma_get_normal_sge_num(u8 opcode, struct cdma_sqe_ctl *tmp_sq) { - return tmp_sq->sge_num; + switch (opcode) { + case CDMA_OPC_CAS: + return CDMA_ATOMIC_SGE_NUM_ATOMIC; + default: + return tmp_sq->sge_num; + } } static bool cdma_k_check_sge_num(u8 opcode, struct cdma_jetty_queue *sq, struct cdma_jfs_wr *wr) { switch (opcode) { + case CDMA_OPC_CAS: + return sq->max_sge_num == 0; case CDMA_OPC_READ: return wr->rw.dst.num_sge > sq->max_sge_num; case CDMA_OPC_WRITE_WITH_NOTIFY: @@ -711,6 +720,66 @@ static int cdma_k_fill_read_sqe(struct cdma_dev *cdev, return 0; } +static bool cdma_check_atomic_len(u32 len, u8 opcode) +{ + switch (len) { + case CDMA_ATOMIC_LEN_4: + case CDMA_ATOMIC_LEN_8: + return true; + case CDMA_ATOMIC_LEN_16: + if (opcode == CDMA_WR_OPC_CAS) + return true; + return false; + default: + return false; + } +} + +static int cdma_k_fill_cas_sqe(struct cdma_dev *cdev, + struct cdma_sqe_ctl *sqe_ctl, + struct cdma_jfs_wr *wr) +{ + struct cdma_sge_info *sge_info; + struct cdma_normal_sge *sge; + + sge_info = wr->cas.src; + if (!cdma_check_atomic_len(sge_info->len, wr->opcode)) { + dev_err(cdev->dev, "cdma cas sge len invalid, len = %u.\n", + sge_info->len); + return -EINVAL; + } + + sge = (struct cdma_normal_sge *)(sqe_ctl + 1); + sge->va = sge_info->addr; + sge->length = sge_info->len; + sge->token_id = sge_info->seg->tid; + + sge_info = wr->cas.dst; + sqe_ctl->sge_num = CDMA_ATOMIC_SGE_NUM; + sqe_ctl->toid = sge_info->seg->tid; + sqe_ctl->token_en = sge_info->seg->token_value_valid; + sqe_ctl->rmt_token_value = sge_info->seg->token_value; + sqe_ctl->rmt_addr_l_or_token_id = sge_info->addr & + (u32)SQE_CTL_RMA_ADDR_BIT; + sqe_ctl->rmt_addr_h_or_token_value = + (sge_info->addr >> (u32)SQE_CTL_RMA_ADDR_OFFSET) & + (u32)SQE_CTL_RMA_ADDR_BIT; + + if (sge->length <= CDMA_ATOMIC_LEN_8) { + memcpy((void *)sqe_ctl + SQE_ATOMIC_DATA_FIELD, + &wr->cas.swap_data, sge->length); + memcpy((void *)sqe_ctl + SQE_ATOMIC_DATA_FIELD + sge->length, + &wr->cas.cmp_data, sge->length); + } else { + memcpy((void *)sqe_ctl + SQE_ATOMIC_DATA_FIELD, + (char *)wr->cas.swap_addr, sge->length); + memcpy((void *)sqe_ctl + SQE_ATOMIC_DATA_FIELD + sge->length, + (char *)wr->cas.cmp_addr, sge->length); + } + + return 0; +} + static int cdma_fill_normal_sge(struct cdma_dev *cdev, struct cdma_sqe_ctl *sqe_ctl, struct cdma_jfs_wr *wr) @@ -721,6 +790,8 @@ static int cdma_fill_normal_sge(struct cdma_dev *cdev, return cdma_k_fill_write_sqe(cdev, sqe_ctl, wr); case CDMA_WR_OPC_READ: return cdma_k_fill_read_sqe(cdev, sqe_ctl, wr); + case CDMA_WR_OPC_CAS: + return cdma_k_fill_cas_sqe(cdev, sqe_ctl, wr); default: dev_err(cdev->dev, "cdma wr opcode invalid, opcode = %u.\n", (u8)wr->opcode); diff --git a/drivers/ub/cdma/cdma_jfs.h b/drivers/ub/cdma/cdma_jfs.h index b94f8aca2d99..8637c2a80074 100644 --- a/drivers/ub/cdma/cdma_jfs.h +++ b/drivers/ub/cdma/cdma_jfs.h @@ -15,6 +15,8 @@ #define CDMA_JFS_MAX_SGE_NOTIFY 11 #define CDMA_JFS_SGE_SIZE 16 #define SQE_WRITE_NOTIFY_CTL_LEN 80 +#define CDMA_ATOMIC_SGE_NUM 1 +#define CDMA_ATOMIC_SGE_NUM_ATOMIC 2 #define SQE_CTL_RMA_ADDR_OFFSET 32 #define SQE_CTL_RMA_ADDR_BIT GENMASK(31, 0) #define SQE_NOTIFY_TOKEN_ID_FIELD 48 @@ -135,6 +137,26 @@ struct cdma_rw_wr { u32 notify_tokenvalue; }; +struct cdma_cas_wr { + struct cdma_sge_info *dst; /* len in the sge is the length of CAS + * operation, only support 8/16/32B + */ + struct cdma_sge_info *src; /* local address for destination original + * value written back + */ + union { + u64 cmp_data; /* when the len is 8B, it indicates the compare value. */ + u64 cmp_addr; /* when the len is 16/32B, it indicates the data address. */ + }; + union { + /* if destination value is the same as cmp_data, + * destination value will be change to swap_data. + */ + u64 swap_data; + u64 swap_addr; + }; +}; + struct cdma_jfs_wr { enum cdma_wr_opcode opcode; union cdma_jfs_wr_flag flag; @@ -142,6 +164,7 @@ struct cdma_jfs_wr { u32 rmt_eid; union { struct cdma_rw_wr rw; + struct cdma_cas_wr cas; }; struct cdma_jfs_wr *next; }; diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index eb425553d6ac..8a70bbb4d49c 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -77,6 +77,11 @@ enum dma_status { DMA_STATUS_INVAL, }; +struct dma_cas_data { + u64 compare_data; + u64 swap_data; +}; + struct dma_notify_data { struct dma_seg *notify_seg; u64 notify_data; @@ -117,6 +122,10 @@ enum dma_status dma_write_with_notify(struct dma_device *dma_dev, enum dma_status dma_read(struct dma_device *dma_dev, struct dma_seg *rmt_seg, struct dma_seg *local_seg, int queue_id); +enum dma_status dma_cas(struct dma_device *dma_dev, struct dma_seg *rmt_seg, + struct dma_seg *local_seg, int queue_id, + struct dma_cas_data *data); + int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, struct dma_cr *cr); -- Gitee From d7fbd5f220d92b0b197083b379bfe77357f7e119 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Mon, 25 Aug 2025 21:48:38 +0800 Subject: [PATCH 088/103] ub: cdma: support dma faa semantic commit 6022413537d64ed9c15cb308617ddb27f6e128ce openEuler This patch implements functionality related to the configuration and issuance of DMA faa semantics in the CDMA driver. The implementation includes support for the dma_faa interface and the process of configuring and issuing semantics within this interface. Signed-off-by: Zhipeng Lu Signed-off-by: Jinjie Cui Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma_api.c | 24 ++++++++++++++++++ drivers/ub/cdma/cdma_common.h | 1 + drivers/ub/cdma/cdma_handle.c | 28 +++++++++++++++++++++ drivers/ub/cdma/cdma_handle.h | 2 ++ drivers/ub/cdma/cdma_jfs.c | 46 +++++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_jfs.h | 14 +++++++++++ include/ub/cdma/cdma_api.h | 3 +++ 7 files changed, 118 insertions(+) diff --git a/drivers/ub/cdma/cdma_api.c b/drivers/ub/cdma/cdma_api.c index e9fec2437cd5..8a30d20a1a09 100644 --- a/drivers/ub/cdma/cdma_api.c +++ b/drivers/ub/cdma/cdma_api.c @@ -574,6 +574,30 @@ enum dma_status dma_cas(struct dma_device *dma_dev, struct dma_seg *rmt_seg, } EXPORT_SYMBOL_GPL(dma_cas); +enum dma_status dma_faa(struct dma_device *dma_dev, struct dma_seg *rmt_seg, + struct dma_seg *local_seg, int queue_id, u64 add) +{ + struct cdma_queue *cdma_queue = NULL; + struct cdma_dev *cdev = NULL; + int ret; + + if (!dma_dev || !rmt_seg || !local_seg) { + pr_err("faa input parameters error.\n"); + return DMA_STATUS_INVAL; + } + + ret = cdma_param_transfer(dma_dev, queue_id, &cdev, &cdma_queue); + if (ret) + return DMA_STATUS_INVAL; + + ret = cdma_faa(cdev, cdma_queue, local_seg, rmt_seg, add); + if (ret) + return DMA_STATUS_INVAL; + + return DMA_STATUS_OK; +} +EXPORT_SYMBOL_GPL(dma_faa); + int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, struct dma_cr *cr) { diff --git a/drivers/ub/cdma/cdma_common.h b/drivers/ub/cdma/cdma_common.h index 54d0e3e43af4..58855991647d 100644 --- a/drivers/ub/cdma/cdma_common.h +++ b/drivers/ub/cdma/cdma_common.h @@ -40,6 +40,7 @@ enum cdma_sq_opcode { CDMA_OPC_WRITE_WITH_NOTIFY = 0x5, CDMA_OPC_READ = 0x6, CDMA_OPC_CAS, + CDMA_OPC_FAA = 0xb, CDMA_OPC_INVALID = 0x12, }; diff --git a/drivers/ub/cdma/cdma_handle.c b/drivers/ub/cdma/cdma_handle.c index b172383e10e6..183f802cfdbf 100644 --- a/drivers/ub/cdma/cdma_handle.c +++ b/drivers/ub/cdma/cdma_handle.c @@ -150,3 +150,31 @@ int cdma_cas(struct cdma_dev *cdev, struct cdma_queue *queue, return ret; } + +int cdma_faa(struct cdma_dev *cdev, struct cdma_queue *queue, + struct dma_seg *local_seg, struct dma_seg *rmt_seg, u64 add) +{ + struct cdma_jfs_wr wr = { .opcode = CDMA_WR_OPC_FADD }; + struct cdma_sge_info rmt_sge, local_sge; + struct cdma_jfs_wr *bad_wr = NULL; + int ret; + + if (cdma_rw_check(cdev, rmt_seg, local_seg)) { + dev_err(cdev->dev, "faa param check failed.\n"); + return -EINVAL; + } + + cdma_fill_comm_wr(&wr, queue); + + cdma_fill_sge(&rmt_sge, &local_sge, rmt_seg, local_seg); + + wr.faa.src = &local_sge; + wr.faa.dst = &rmt_sge; + wr.faa.operand = add; + + ret = cdma_post_jfs_wr((struct cdma_jfs *)queue->jfs, &wr, &bad_wr); + if (ret) + dev_err(cdev->dev, "post jfs for faa failed, ret = %d.\n", ret); + + return ret; +} diff --git a/drivers/ub/cdma/cdma_handle.h b/drivers/ub/cdma/cdma_handle.h index 8c99a0a0cb32..00cb8049778e 100644 --- a/drivers/ub/cdma/cdma_handle.h +++ b/drivers/ub/cdma/cdma_handle.h @@ -16,5 +16,7 @@ int cdma_read(struct cdma_dev *cdev, struct cdma_queue *queue, int cdma_cas(struct cdma_dev *cdev, struct cdma_queue *queue, struct dma_seg *local_seg, struct dma_seg *rmt_seg, struct dma_cas_data *data); +int cdma_faa(struct cdma_dev *cdev, struct cdma_queue *queue, + struct dma_seg *local_seg, struct dma_seg *rmt_seg, u64 add); #endif /* CDMA_HANDLE_H */ diff --git a/drivers/ub/cdma/cdma_jfs.c b/drivers/ub/cdma/cdma_jfs.c index 79d5074ff4ef..cbb47a7f56db 100644 --- a/drivers/ub/cdma/cdma_jfs.c +++ b/drivers/ub/cdma/cdma_jfs.c @@ -570,6 +570,8 @@ static u8 cdma_get_jfs_opcode(enum cdma_wr_opcode opcode) return CDMA_OPC_READ; case CDMA_WR_OPC_CAS: return CDMA_OPC_CAS; + case CDMA_WR_OPC_FADD: + return CDMA_OPC_FAA; default: return CDMA_OPC_INVALID; } @@ -579,6 +581,7 @@ static inline u32 cdma_get_normal_sge_num(u8 opcode, struct cdma_sqe_ctl *tmp_sq { switch (opcode) { case CDMA_OPC_CAS: + case CDMA_OPC_FAA: return CDMA_ATOMIC_SGE_NUM_ATOMIC; default: return tmp_sq->sge_num; @@ -590,6 +593,7 @@ static bool cdma_k_check_sge_num(u8 opcode, struct cdma_jetty_queue *sq, { switch (opcode) { case CDMA_OPC_CAS: + case CDMA_OPC_FAA: return sq->max_sge_num == 0; case CDMA_OPC_READ: return wr->rw.dst.num_sge > sq->max_sge_num; @@ -780,6 +784,46 @@ static int cdma_k_fill_cas_sqe(struct cdma_dev *cdev, return 0; } +static int cdma_k_fill_faa_sqe(struct cdma_dev *cdev, + struct cdma_sqe_ctl *sqe_ctl, + struct cdma_jfs_wr *wr) +{ + struct cdma_sge_info *sge_info; + struct cdma_normal_sge *sge; + + sge_info = wr->faa.src; + if (!cdma_check_atomic_len(sge_info->len, wr->opcode)) { + dev_err(cdev->dev, "cdma faa sge len invalid, len = %u.\n", + sge_info->len); + return -EINVAL; + } + + sge = (struct cdma_normal_sge *)(sqe_ctl + 1); + sge->va = sge_info->addr; + sge->length = sge_info->len; + sge->token_id = sge_info->seg->tid; + + sge_info = wr->faa.dst; + sqe_ctl->sge_num = CDMA_ATOMIC_SGE_NUM; + sqe_ctl->toid = sge_info->seg->tid; + sqe_ctl->token_en = sge_info->seg->token_value_valid; + sqe_ctl->rmt_token_value = sge_info->seg->token_value; + sqe_ctl->rmt_addr_l_or_token_id = sge_info->addr & + (u32)SQE_CTL_RMA_ADDR_BIT; + sqe_ctl->rmt_addr_h_or_token_value = + (sge_info->addr >> (u32)SQE_CTL_RMA_ADDR_OFFSET) & + (u32)SQE_CTL_RMA_ADDR_BIT; + + if (sge->length <= CDMA_ATOMIC_LEN_8) + memcpy((void *)sqe_ctl + SQE_ATOMIC_DATA_FIELD, + &wr->faa.operand, sge->length); + else + memcpy((void *)sqe_ctl + SQE_ATOMIC_DATA_FIELD, + (void *)wr->faa.operand_addr, sge->length); + + return 0; +} + static int cdma_fill_normal_sge(struct cdma_dev *cdev, struct cdma_sqe_ctl *sqe_ctl, struct cdma_jfs_wr *wr) @@ -792,6 +836,8 @@ static int cdma_fill_normal_sge(struct cdma_dev *cdev, return cdma_k_fill_read_sqe(cdev, sqe_ctl, wr); case CDMA_WR_OPC_CAS: return cdma_k_fill_cas_sqe(cdev, sqe_ctl, wr); + case CDMA_WR_OPC_FADD: + return cdma_k_fill_faa_sqe(cdev, sqe_ctl, wr); default: dev_err(cdev->dev, "cdma wr opcode invalid, opcode = %u.\n", (u8)wr->opcode); diff --git a/drivers/ub/cdma/cdma_jfs.h b/drivers/ub/cdma/cdma_jfs.h index 8637c2a80074..fe46955c925b 100644 --- a/drivers/ub/cdma/cdma_jfs.h +++ b/drivers/ub/cdma/cdma_jfs.h @@ -157,6 +157,19 @@ struct cdma_cas_wr { }; }; +struct cdma_faa_wr { + struct cdma_sge_info *dst; /* len in the sge is the length of FAA + * operation, only support 4/8B + */ + struct cdma_sge_info *src; /* local address for destination original + * value written back + */ + union { + u64 operand; /* Addend */ + u64 operand_addr; + }; +}; + struct cdma_jfs_wr { enum cdma_wr_opcode opcode; union cdma_jfs_wr_flag flag; @@ -165,6 +178,7 @@ struct cdma_jfs_wr { union { struct cdma_rw_wr rw; struct cdma_cas_wr cas; + struct cdma_faa_wr faa; }; struct cdma_jfs_wr *next; }; diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index 8a70bbb4d49c..6809ba074c05 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -126,6 +126,9 @@ enum dma_status dma_cas(struct dma_device *dma_dev, struct dma_seg *rmt_seg, struct dma_seg *local_seg, int queue_id, struct dma_cas_data *data); +enum dma_status dma_faa(struct dma_device *dma_dev, struct dma_seg *rmt_seg, + struct dma_seg *local_seg, int queue_id, u64 add); + int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, struct dma_cr *cr); -- Gitee From 57cd2eb629adf6d2c33eef55c79f5ae7e484dc98 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Tue, 26 Aug 2025 09:32:48 +0800 Subject: [PATCH 089/103] ub: cdma: support debugfs interface commit 45ae057d001f39e6e83556d75f18da5aea2b0186 openEuler This patch implements functionality related to debugfs in the CDMA driver. The implementation includes the registration of debugfs and file registration, allowing users to view DFX information of devices and resources by reading the corresponding files. Signed-off-by: Zhipeng Lu Signed-off-by: Sunyi Nan Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/Makefile | 2 +- drivers/ub/cdma/cdma.h | 2 + drivers/ub/cdma/cdma_debugfs.c | 783 +++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_debugfs.h | 58 +++ drivers/ub/cdma/cdma_jfs.h | 5 + drivers/ub/cdma/cdma_main.c | 7 + drivers/ub/cdma/cdma_queue.h | 3 +- 7 files changed, 858 insertions(+), 2 deletions(-) create mode 100644 drivers/ub/cdma/cdma_debugfs.c create mode 100644 drivers/ub/cdma/cdma_debugfs.h diff --git a/drivers/ub/cdma/Makefile b/drivers/ub/cdma/Makefile index cb3ea219f9e2..2ce4eefa2d84 100644 --- a/drivers/ub/cdma/Makefile +++ b/drivers/ub/cdma/Makefile @@ -3,6 +3,6 @@ cdma-$(CONFIG_UB_CDMA) := cdma_main.o cdma_dev.o cdma_chardev.o cdma_cmd.o cdma_tid.o cdma_ioctl.o \ cdma_api.o cdma_context.o cdma_queue.o cdma_uobj.o cdma_jfc.o cdma_common.o \ cdma_db.o cdma_mbox.o cdma_tp.o cdma_jfs.o cdma_eq.o cdma_event.o cdma_segment.o \ - cdma_handle.o + cdma_handle.o cdma_debugfs.o obj-m += cdma.o diff --git a/drivers/ub/cdma/cdma.h b/drivers/ub/cdma/cdma.h index 8ed8fdb4d6fa..e782b0229943 100644 --- a/drivers/ub/cdma/cdma.h +++ b/drivers/ub/cdma/cdma.h @@ -9,6 +9,7 @@ #include #include #include +#include "cdma_debugfs.h" #include extern u32 jfc_arm_mode; @@ -163,6 +164,7 @@ struct cdma_dev { struct auxiliary_device *adev; struct cdma_chardev chardev; struct cdma_caps caps; + struct cdma_dbgfs cdbgfs; u32 eid; u32 upi; diff --git a/drivers/ub/cdma/cdma_debugfs.c b/drivers/ub/cdma/cdma_debugfs.c new file mode 100644 index 000000000000..d0de451e92ca --- /dev/null +++ b/drivers/ub/cdma/cdma_debugfs.c @@ -0,0 +1,783 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define dev_fmt(fmt) "CDMA: " fmt + +#include +#include +#include +#include +#include +#include "cdma_queue.h" +#include "cdma.h" +#include "cdma_jfc.h" +#include "cdma_jfs.h" +#include "cdma_mbox.h" +#include "cdma_cmd.h" +#include "cdma_debugfs.h" + +#define CDMA_DBG_READ_LEN 65536 +#define BUF_10_BASE 10 +#define BUF_SIZE 8 + +/* ctx debugfs start */ +static void cdma_get_ctx_info(struct cdma_dev *cdev, + struct cdma_queue *queue, + enum cdma_dbg_ctx_type ctx_type, + struct cdma_ctx_info *ctx_info) +{ + struct auxiliary_device *adev = cdev->adev; + +#define CDMA_DBG_CTX_SIZE_256 256 +#define UBASE_CTX_SIZE_128 128 + switch (ctx_type) { + case CDMA_DBG_JFS_CTX: + ctx_info->start_idx = queue->jfs_id; + ctx_info->ctx_size = CDMA_DBG_CTX_SIZE_256; + ctx_info->op = UBASE_MB_QUERY_JFS_CONTEXT; + ctx_info->ctx_name = "jfs"; + break; + case CDMA_DBG_SQ_JFC_CTX: + ctx_info->start_idx = queue->jfc_id; + ctx_info->ctx_size = UBASE_CTX_SIZE_128; + ctx_info->op = UBASE_MB_QUERY_JFC_CONTEXT; + ctx_info->ctx_name = "sq_jfc"; + break; + default: + dev_err(&adev->dev, "get ctx info failed, ctx_type = %d.\n", + ctx_type); + break; + } +} + +static void cdma_print_ctx_hw_bytype(struct seq_file *s, + enum cdma_dbg_ctx_type ctx_type, + struct cdma_ctx_info *ctx_info, + struct ubase_cmd_mailbox *mailbox) +{ + struct cdma_jfs_ctx *jfs_ctx; + struct cdma_jfc_ctx *jfc_ctx; + + seq_printf(s, "offset\t%s%u\n", ctx_info->ctx_name, ctx_info->start_idx); + + if (ctx_type == CDMA_DBG_JFS_CTX) { + jfs_ctx = (struct cdma_jfs_ctx *)mailbox->buf; + jfs_ctx->sqe_base_addr_l = 0; + jfs_ctx->sqe_base_addr_h = 0; + jfs_ctx->user_data_l = 0; + jfs_ctx->user_data_h = 0; + ubase_print_context_hw(s, jfs_ctx, ctx_info->ctx_size); + } else if (ctx_type == CDMA_DBG_SQ_JFC_CTX) { + jfc_ctx = (struct cdma_jfc_ctx *)mailbox->buf; + jfc_ctx->cqe_va_l = 0; + jfc_ctx->cqe_va_h = 0; + jfc_ctx->cqe_token_value = 0; + jfc_ctx->record_db_addr_l = 0; + jfc_ctx->record_db_addr_h = 0; + jfc_ctx->remote_token_value = 0; + ubase_print_context_hw(s, jfc_ctx, ctx_info->ctx_size); + } + + seq_puts(s, "\n"); +} + +static int cdma_dbg_dump_ctx_hw(struct seq_file *s, enum cdma_dbg_ctx_type ctx_type) +{ + struct cdma_dev *cdev = dev_get_drvdata(s->private); + struct auxiliary_device *adev = cdev->adev; + u32 queue_id = cdev->cdbgfs.cfg.queue_id; + struct cdma_ctx_info ctx_info = { 0 }; + struct ubase_cmd_mailbox *mailbox; + struct ubase_mbx_attr attr; + struct cdma_queue *queue; + + spin_lock(&cdev->queue_table.lock); + queue = idr_find(&cdev->queue_table.idr_tbl.idr, queue_id); + if (!queue) { + spin_unlock(&cdev->queue_table.lock); + dev_err(&adev->dev, "find queue[%u] for dump context hw failed.\n", queue_id); + return -EINVAL; + } + + if (!queue->jfs_id) { + spin_unlock(&cdev->queue_table.lock); + dev_warn(&adev->dev, "queue resource is not initialized.\n"); + return -EINVAL; + } + + cdma_get_ctx_info(cdev, queue, ctx_type, &ctx_info); + spin_unlock(&cdev->queue_table.lock); + + cdma_fill_mbx_attr(&attr, ctx_info.start_idx, ctx_info.op, 0); + mailbox = cdma_mailbox_query_ctx(cdev, &attr); + if (!mailbox) { + dev_err(&adev->dev, "cdma dbg post query %s ctx mbx failed.\n", + ctx_info.ctx_name); + return -ENOMEM; + } + + cdma_print_ctx_hw_bytype(s, ctx_type, &ctx_info, mailbox); + + cdma_free_cmd_mailbox(cdev, mailbox); + + return 0; +} + +static int cdma_dbg_dump_jfs_ctx_hw(struct seq_file *s, void *data) +{ + if (!s || !s->private) + return -EINVAL; + + return cdma_dbg_dump_ctx_hw(s, CDMA_DBG_JFS_CTX); +} + +static int cdma_dbg_dump_sq_jfc_ctx_hw(struct seq_file *s, void *data) +{ + if (!s || !s->private) + return -EINVAL; + + return cdma_dbg_dump_ctx_hw(s, CDMA_DBG_SQ_JFC_CTX); +} + +static void cdma_get_jfs_cfg(struct cdma_queue *queue, struct seq_file *s) +{ + struct cdma_jfs_cfg *cfg; + + if (!queue->jfs) + return; + + cfg = &queue->jfs->cfg; + seq_printf(s, "%-13u", cfg->depth); + seq_printf(s, "%-12u", cfg->flag.value); + seq_printf(s, "%-17u", cfg->eid_index); + seq_printf(s, "%-10u", cfg->priority); + seq_printf(s, "%-9u", cfg->max_sge); + seq_printf(s, "%-10u", cfg->max_rsge); + seq_printf(s, "%-11u", cfg->rnr_retry); + seq_printf(s, "%-13u", cfg->err_timeout); + seq_printf(s, "%-14u", cfg->jfc_id); + seq_printf(s, "%-15u", cfg->sqe_pos); + seq_printf(s, "%-11u", cfg->tpn); + seq_printf(s, "%-15u", cfg->pld_pos); + seq_printf(s, "%-16u", cfg->queue_id); +} + +static void cdma_get_jfc_cfg(struct cdma_queue *queue, struct seq_file *s) +{ + struct cdma_jfc_cfg *cfg; + + if (!queue->jfc) + return; + + cfg = &queue->jfc->jfc_cfg; + seq_printf(s, "%-13u", cfg->depth); + seq_printf(s, "%-12u", cfg->ceqn); + seq_printf(s, "%-16u", cfg->queue_id); +} + +static void cdma_get_jfs_title(struct seq_file *s) +{ + seq_puts(s, "depth "); + seq_puts(s, "flag "); + seq_puts(s, "eid_index "); + seq_puts(s, "priority "); + seq_puts(s, "max_sge "); + seq_puts(s, "max_rsge "); + seq_puts(s, "rnr_retry "); + seq_puts(s, "err_timeout "); + seq_puts(s, "jfc_id "); + seq_puts(s, "sqe_pos "); + seq_puts(s, "tpn "); + seq_puts(s, "pld_pos "); + seq_puts(s, "queue_id "); + seq_puts(s, "\n"); +} + +static void cdma_get_jfc_title(struct seq_file *s) +{ + seq_puts(s, "depth "); + seq_puts(s, "flag "); + seq_puts(s, "ceqn "); + seq_puts(s, "queue_id "); + seq_puts(s, "\n"); +} + +static int cdma_dbg_dump_ctx(struct seq_file *s, enum cdma_dbg_ctx_type ctx_type) +{ + struct cdma_dbg_context { + void (*get_title)(struct seq_file *s); + void (*get_cfg)(struct cdma_queue *queue, struct seq_file *s); + } dbg_ctx[] = { + {cdma_get_jfs_title, cdma_get_jfs_cfg}, + {cdma_get_jfc_title, cdma_get_jfc_cfg}, + }; + struct cdma_dev *cdev = dev_get_drvdata(s->private); + u32 queue_id = cdev->cdbgfs.cfg.queue_id; + struct cdma_queue *queue; + + dbg_ctx[ctx_type].get_title(s); + + spin_lock(&cdev->queue_table.lock); + queue = idr_find(&cdev->queue_table.idr_tbl.idr, queue_id); + if (!queue) { + spin_unlock(&cdev->queue_table.lock); + dev_err(&cdev->adev->dev, "find queue[%u] for dump context failed.\n", queue_id); + return -EINVAL; + } + + dbg_ctx[ctx_type].get_cfg(queue, s); + + spin_unlock(&cdev->queue_table.lock); + + return 0; +} + +int cdma_dbg_dump_jfs_ctx(struct seq_file *s, void *data) +{ + if (!s || !s->private) + return -EINVAL; + + return cdma_dbg_dump_ctx(s, CDMA_DBG_JFS_CTX); +} + +int cdma_dbg_dump_sq_jfc_ctx(struct seq_file *s, void *data) +{ + if (!s || !s->private) + return -EINVAL; + + return cdma_dbg_dump_ctx(s, CDMA_DBG_SQ_JFC_CTX); +} +/* ctx debugfs end */ + +/* resource debugfs start */ +static int cdma_dbg_dump_dev_info(struct seq_file *s, void *data) +{ + if (!s || !s->private) + return -EINVAL; + + struct cdma_dev *cdev = dev_get_drvdata(s->private); + u8 eu_num = cdev->base.attr.eu_num; + u32 seid_idx, seid, upi, i; + + seq_printf(s, "EU_ENTRY_NUM: %u\n", eu_num); + for (i = 0; i < eu_num; i++) { + seid_idx = cdev->base.attr.eus[i].eid_idx; + seid = cdev->base.attr.eus[i].eid.dw0; + upi = cdev->base.attr.eus[i].upi; + seq_printf(s, "SEID_IDX: %u, SEID: %u, UPI: %u\n", seid_idx, seid, upi); + } + + return 0; +} + +static int cdma_dbg_dump_cap_info(struct seq_file *s, void *data) +{ + if (!s || !s->private) + return -EINVAL; + + struct cdma_dev *cdev = dev_get_drvdata(s->private); + struct cdma_caps *caps = &cdev->caps; + + seq_printf(s, "MAX_JFC: %u\n", caps->jfc.max_cnt); + seq_printf(s, "MAX_JFS: %u\n", caps->jfs.max_cnt); + seq_printf(s, "MAX_JFC_DEPTH: %u\n", caps->jfc.depth); + seq_printf(s, "MAX_JFS_DEPTH: %u\n", caps->jfs.depth); + seq_printf(s, "MAX_JFS_SGE: %u\n", caps->jfs_sge); + seq_printf(s, "MAX_JFS_RSGE: %u\n", caps->jfs_rsge); + seq_printf(s, "MAX_MSG_SIZE: %u\n", caps->max_msg_len); + seq_printf(s, "TRANS_MODE: %u\n", caps->trans_mode); + seq_printf(s, "CEQ_CNT: %u\n", caps->comp_vector_cnt); + + return 0; +} + +static int cdma_dbg_dump_queue_info(struct seq_file *s, void *data) +{ + if (!s || !s->private) + return -EINVAL; + + struct cdma_dev *cdev = dev_get_drvdata(s->private); + u32 queue_id = cdev->cdbgfs.cfg.queue_id; + struct cdma_queue *queue; + + spin_lock(&cdev->queue_table.lock); + queue = idr_find(&cdev->queue_table.idr_tbl.idr, queue_id); + if (!queue) { + spin_unlock(&cdev->queue_table.lock); + dev_err(&cdev->adev->dev, "find queue[%u] for dump queue info failed.\n", queue_id); + return -EINVAL; + } + + seq_printf(s, "QUEUE_DEPTH: %u\n", queue->cfg.queue_depth); + seq_printf(s, "DST CNA: 0x%x\n", queue->cfg.dcna); + seq_printf(s, "RMT EID: 0x%x\n", queue->cfg.rmt_eid.dw0); + seq_printf(s, "PRIORITY: %u\n", queue->cfg.priority); + + spin_unlock(&cdev->queue_table.lock); + + return 0; +} +/* resource debugfs end */ + +/* entry info start */ +static void cdma_dbg_dump_sqe_info(struct cdma_sqe_ctl *sqe_ctl, struct seq_file *s) +{ + seq_printf(s, "sqe bb idx: %u\n", sqe_ctl->sqe_bb_idx); + seq_printf(s, "place odr: %u\n", sqe_ctl->place_odr); + seq_printf(s, "comp order: %u\n", sqe_ctl->comp_order); + seq_printf(s, "fence: %u\n", sqe_ctl->fence); + seq_printf(s, "se: %u\n", sqe_ctl->se); + seq_printf(s, "cqe: %u\n", sqe_ctl->cqe); + seq_printf(s, "owner: %u\n", sqe_ctl->owner); + seq_printf(s, "opcode: %u\n", sqe_ctl->opcode); + seq_printf(s, "tpn: %u\n", sqe_ctl->tpn); + seq_printf(s, "sge num: %u\n", sqe_ctl->sge_num); + seq_printf(s, "rmt eid: %u\n", sqe_ctl->rmt_eid[0]); +} + +static void cdma_dbg_dump_cqe_info(struct cdma_jfc_cqe *cqe, struct seq_file *s) +{ + seq_printf(s, "sr: %u\n", cqe->s_r); + seq_printf(s, "owner: %u\n", cqe->owner); + seq_printf(s, "opcode: %u\n", cqe->opcode); + seq_printf(s, "fd: %u\n", cqe->fd); + seq_printf(s, "substatus: %u\n", cqe->substatus); + seq_printf(s, "status: %u\n", cqe->status); + seq_printf(s, "entry idx: %u\n", cqe->entry_idx); + seq_printf(s, "tpn: %u\n", cqe->tpn); + seq_printf(s, "rmt eid: %u\n", cqe->rmt_eid[0]); + seq_printf(s, "byte cnt: %u\n", cqe->byte_cnt); +} + +static void cdma_dbg_dum_eu(struct cdma_dev *cdev, int i, struct seq_file *s) +{ + struct eu_info *eu = &cdev->base.attr.eus[i]; + + seq_printf(s, "%d: ", i); + seq_printf(s, "idx[0x%x] ", eu->eid_idx); + seq_printf(s, "eid[0x%x] ", eu->eid.dw0); + seq_printf(s, "upi[0x%x]\n", eu->upi); +} + +static int cdma_dbg_dump_sqe(struct seq_file *s, void *data) +{ + if (!s || !s->private) + return -EINVAL; + + struct cdma_dev *cdev = dev_get_drvdata(s->private); + u32 queue_id = cdev->cdbgfs.cfg.queue_id; + u32 entry_pi = cdev->cdbgfs.cfg.entry_pi; + struct cdma_sqe_ctl *sqe_ctl; + struct cdma_queue *queue; + struct cdma_jfs *jfs; + + spin_lock(&cdev->queue_table.lock); + queue = idr_find(&cdev->queue_table.idr_tbl.idr, queue_id); + if (!queue) { + spin_unlock(&cdev->queue_table.lock); + dev_err(&cdev->adev->dev, "find queue[%u] for dump sqe failed.\n", queue_id); + return -EINVAL; + } + + if (queue->jfs && queue->is_kernel) { + jfs = to_cdma_jfs(queue->jfs); + if (entry_pi >= jfs->base_jfs.cfg.depth) { + spin_unlock(&cdev->queue_table.lock); + dev_err(&cdev->adev->dev, "pi [%u] overflow for dump sqe.\n", entry_pi); + return -EINVAL; + } + + spin_lock(&jfs->sq.lock); + sqe_ctl = (struct cdma_sqe_ctl *)(jfs->sq.buf.kva + + (entry_pi & (jfs->sq.buf.entry_cnt - 1)) * + jfs->sq.buf.entry_size); + cdma_dbg_dump_sqe_info(sqe_ctl, s); + spin_unlock(&jfs->sq.lock); + } else { + dev_warn(&cdev->adev->dev, "not support queue[%u] for dump sqe.\n", queue_id); + } + + spin_unlock(&cdev->queue_table.lock); + + return 0; +} + +static int cdma_dbg_dump_cqe(struct seq_file *s, void *data) +{ + if (!s || !s->private) + return -EINVAL; + + struct cdma_dev *cdev = dev_get_drvdata(s->private); + u32 queue_id = cdev->cdbgfs.cfg.queue_id; + u32 entry_ci = cdev->cdbgfs.cfg.entry_ci; + struct cdma_queue *queue; + struct cdma_jfc_cqe *cqe; + struct cdma_jfc *jfc; + + spin_lock(&cdev->queue_table.lock); + queue = idr_find(&cdev->queue_table.idr_tbl.idr, queue_id); + if (!queue) { + spin_unlock(&cdev->queue_table.lock); + dev_err(&cdev->adev->dev, "find queue[%u] for dump cqe failed.\n", queue_id); + return -EINVAL; + } + + if (queue->jfc && queue->is_kernel) { + jfc = to_cdma_jfc(queue->jfc); + if (entry_ci >= jfc->base.jfc_cfg.depth) { + spin_unlock(&cdev->queue_table.lock); + dev_err(&cdev->adev->dev, "ci [%u] overflow for dump cqe.\n", entry_ci); + return -EINVAL; + } + + spin_lock(&jfc->lock); + cqe = (struct cdma_jfc_cqe *)(jfc->buf.kva + + (entry_ci & (jfc->buf.entry_cnt - 1)) * + jfc->buf.entry_size); + cdma_dbg_dump_cqe_info(cqe, s); + spin_unlock(&jfc->lock); + } else { + dev_warn(&cdev->adev->dev, "not support queue[%u] for dump cqe.\n", queue_id); + } + + spin_unlock(&cdev->queue_table.lock); + + return 0; +} + +/* Dump eu info */ +static int cdma_dbg_dump_eu(struct seq_file *s, void *data) +{ + if (!s || !s->private) + return -EINVAL; + + struct cdma_dev *cdev = dev_get_drvdata(s->private); + int ret, i; + + ret = cdma_ctrlq_query_eu(cdev); + if (ret) + return ret; + + for (i = 0; i < cdev->base.attr.eu_num; i++) + cdma_dbg_dum_eu(cdev, i, s); + + return 0; +} +/* entry info end */ + +static bool cdma_dbg_dentry_support(struct device *dev, u32 property) +{ + struct cdma_dev *cdev = dev_get_drvdata(dev); + + return ubase_dbg_dentry_support(cdev->adev, property); +} + +static struct ubase_dbg_dentry_info cdma_dbg_dentry[] = { + { + .name = "context", + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + }, { + .name = "resource_info", + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + }, { + .name = "entry_info", + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + }, + /* keep "cdma" at the bottom and add new directory above */ + { + .name = "cdma", + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + }, +}; + +static struct ubase_dbg_cmd_info cdma_dbg_cmd[] = { + { + .name = "jfs_context", + .dentry_index = CDMA_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = cdma_dbg_dump_jfs_ctx, + }, { + .name = "sq_jfc_context", + .dentry_index = CDMA_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = cdma_dbg_dump_sq_jfc_ctx, + }, { + .name = "jfs_context_hw", + .dentry_index = CDMA_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = cdma_dbg_dump_jfs_ctx_hw, + }, { + .name = "sq_jfc_context_hw", + .dentry_index = CDMA_DBG_DENTRY_CONTEXT, + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = cdma_dbg_dump_sq_jfc_ctx_hw, + }, { + .name = "dev_info", + .dentry_index = CDMA_DBG_DENTRY_RES_INFO, + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = cdma_dbg_dump_dev_info, + }, { + .name = "cap_info", + .dentry_index = CDMA_DBG_DENTRY_RES_INFO, + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = cdma_dbg_dump_cap_info, + }, { + .name = "queue_info", + .dentry_index = CDMA_DBG_DENTRY_RES_INFO, + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = cdma_dbg_dump_queue_info, + }, { + .name = "sqe", + .dentry_index = CDMA_DBG_DENTRY_ENTRY_INFO, + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = cdma_dbg_dump_sqe, + }, { + .name = "cqe", + .dentry_index = CDMA_DBG_DENTRY_ENTRY_INFO, + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = cdma_dbg_dump_cqe, + }, { + .name = "eu", + .dentry_index = CDMA_DBG_DENTRY_ENTRY_INFO, + .property = UBASE_SUP_CDMA | UBASE_SUP_UBL, + .support = cdma_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = cdma_dbg_dump_eu, + }, +}; + +static ssize_t cdma_dbgfs_cfg_write_val(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos, + enum cdma_dbgfs_cfg_type type) +{ + struct cdma_dbgfs_cfg *cfg = (struct cdma_dbgfs_cfg *)filp->private_data; + char buf[BUF_SIZE] = { 0 }; + ssize_t len, ret; + u32 value; + + len = simple_write_to_buffer(buf, BUF_SIZE - 1, ppos, buffer, count); + if (len < 0) + return len; + + ret = kstrtouint(buf, BUF_10_BASE, &value); + if (ret) + return ret; + + switch (type) { + case CDMA_QUEUE_ID: + cfg->queue_id = value; + break; + case CDMA_ENTRY_PI: + cfg->entry_pi = value; + break; + case CDMA_ENTRY_CI: + cfg->entry_ci = value; + break; + default: + return -EINVAL; + } + + return len; +} + +static ssize_t cdma_dbgfs_cfg_read_val(struct file *filp, + char *buffer, size_t count, loff_t *ppos, + enum cdma_dbgfs_cfg_type type) +{ + struct cdma_dbgfs_cfg *cfg = (struct cdma_dbgfs_cfg *)filp->private_data; + char buf[BUF_SIZE] = { 0 }; + u32 value = 0; + size_t len; + + switch (type) { + case CDMA_QUEUE_ID: + value = cfg->queue_id; + break; + case CDMA_ENTRY_PI: + value = cfg->entry_pi; + break; + case CDMA_ENTRY_CI: + value = cfg->entry_ci; + break; + default: + break; + } + + len = scnprintf(buf, sizeof(buf), "%u\n", value); + + return simple_read_from_buffer(buffer, count, ppos, buf, len); +} + +static ssize_t cdma_dbgfs_cfg_write_queue_id(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos) +{ + return cdma_dbgfs_cfg_write_val(filp, buffer, count, ppos, CDMA_QUEUE_ID); +} + +static ssize_t cdma_dbgfs_cfg_read_queue_id(struct file *filp, + char *buffer, size_t count, + loff_t *ppos) +{ + return cdma_dbgfs_cfg_read_val(filp, buffer, count, ppos, CDMA_QUEUE_ID); +} + +static ssize_t cdma_dbgfs_cfg_write_entry_pi(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos) +{ + return cdma_dbgfs_cfg_write_val(filp, buffer, count, ppos, CDMA_ENTRY_PI); +} + +static ssize_t cdma_dbgfs_cfg_read_entry_pi(struct file *filp, + char *buffer, size_t count, + loff_t *ppos) +{ + return cdma_dbgfs_cfg_read_val(filp, buffer, count, ppos, CDMA_ENTRY_PI); +} + +static ssize_t cdma_dbgfs_cfg_write_entry_ci(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos) +{ + return cdma_dbgfs_cfg_write_val(filp, buffer, count, ppos, CDMA_ENTRY_CI); +} + +static ssize_t cdma_dbgfs_cfg_read_entry_ci(struct file *filp, + char *buffer, size_t count, + loff_t *ppos) +{ + return cdma_dbgfs_cfg_read_val(filp, buffer, count, ppos, CDMA_ENTRY_CI); +} + +static struct cdma_dbgfs_cfg_info cdma_dbg_cfg[] = { + { + .name = "queue_id", + {true, true, true}, + {.owner = THIS_MODULE, + .read = cdma_dbgfs_cfg_read_queue_id, + .write = cdma_dbgfs_cfg_write_queue_id, + .open = simple_open, }, + }, { + .name = "entry_pi", + {false, false, true}, + {.owner = THIS_MODULE, + .read = cdma_dbgfs_cfg_read_entry_pi, + .write = cdma_dbgfs_cfg_write_entry_pi, + .open = simple_open, }, + }, { + .name = "entry_ci", + {false, false, true}, + {.owner = THIS_MODULE, + .read = cdma_dbgfs_cfg_read_entry_ci, + .write = cdma_dbgfs_cfg_write_entry_ci, + .open = simple_open, }, + }, +}; + +static int cdma_dbg_create_cfg_file(struct cdma_dev *cdev, + struct ubase_dbg_dentry_info *dentry_info, + u8 array_size) +{ + struct dentry *debugfs_file; + struct dentry *cur_dir; + size_t i, j; + + for (i = 0; i < array_size - 1; i++) { + cur_dir = dentry_info[i].dentry; + for (j = 0; j < ARRAY_SIZE(cdma_dbg_cfg); j++) { + if (!cdma_dbg_cfg[j].dentry_valid[i]) + continue; + debugfs_file = debugfs_create_file(cdma_dbg_cfg[j].name, + 0400, cur_dir, &cdev->cdbgfs.cfg, + &cdma_dbg_cfg[j].file_ops); + if (!debugfs_file) + return -ENOMEM; + } + } + + return 0; +} + +int cdma_dbg_init(struct auxiliary_device *adev) +{ + struct ubase_dbg_dentry_info dbg_dentry[CDMA_DBG_DENTRY_ROOT + 1] = {0}; + struct dentry *ubase_root_dentry = ubase_diag_debugfs_root(adev); + struct device *dev = &adev->dev; + struct cdma_dev *cdev; + int ret; + + cdev = dev_get_drvdata(dev); + + if (!ubase_root_dentry) { + dev_err(dev, "dbgfs root dentry does not exist.\n"); + return -ENOENT; + } + + memcpy(dbg_dentry, cdma_dbg_dentry, sizeof(cdma_dbg_dentry)); + cdev->cdbgfs.dbgfs.dentry = debugfs_create_dir( + dbg_dentry[ARRAY_SIZE(dbg_dentry) - 1].name, ubase_root_dentry); + if (IS_ERR(cdev->cdbgfs.dbgfs.dentry)) { + dev_err(dev, "create cdma debugfs root dir failed.\n"); + return PTR_ERR(cdev->cdbgfs.dbgfs.dentry); + } + + dbg_dentry[CDMA_DBG_DENTRY_ROOT].dentry = cdev->cdbgfs.dbgfs.dentry; + cdev->cdbgfs.dbgfs.cmd_info = cdma_dbg_cmd; + cdev->cdbgfs.dbgfs.cmd_info_size = ARRAY_SIZE(cdma_dbg_cmd); + + ret = ubase_dbg_create_dentry(dev, &cdev->cdbgfs.dbgfs, dbg_dentry, + ARRAY_SIZE(dbg_dentry) - 1); + if (ret) { + dev_err(dev, "create cdma debugfs dentry failed, ret = %d.\n", ret); + goto create_dentry_err; + } + + ret = cdma_dbg_create_cfg_file(cdev, dbg_dentry, ARRAY_SIZE(dbg_dentry)); + if (ret) { + dev_err(dev, "create cdma debugfs cfg file failed, ret = %d.\n", ret); + goto create_dentry_err; + } + + return 0; + +create_dentry_err: + debugfs_remove_recursive(cdev->cdbgfs.dbgfs.dentry); + cdev->cdbgfs.dbgfs.dentry = NULL; + + return ret; +} + +void cdma_dbg_uninit(struct auxiliary_device *adev) +{ + struct cdma_dev *cdev = dev_get_drvdata(&adev->dev); + + if (!cdev->cdbgfs.dbgfs.dentry) + return; + + debugfs_remove_recursive(cdev->cdbgfs.dbgfs.dentry); + cdev->cdbgfs.dbgfs.dentry = NULL; +} diff --git a/drivers/ub/cdma/cdma_debugfs.h b/drivers/ub/cdma/cdma_debugfs.h new file mode 100644 index 000000000000..1cd0f2ada9dc --- /dev/null +++ b/drivers/ub/cdma/cdma_debugfs.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_DEBUGFS_H__ +#define __CDMA_DEBUGFS_H__ + +#include +#include + +enum cdma_dbg_dentry_type { + CDMA_DBG_DENTRY_CONTEXT, + CDMA_DBG_DENTRY_RES_INFO, + CDMA_DBG_DENTRY_ENTRY_INFO, + /* must be the last entry. */ + CDMA_DBG_DENTRY_ROOT, +}; + +/* ctx debugfs start */ +struct cdma_ctx_info { + u32 start_idx; + u32 ctx_size; + u8 op; + const char *ctx_name; +}; + +enum cdma_dbg_ctx_type { + CDMA_DBG_JFS_CTX = 0, + CDMA_DBG_SQ_JFC_CTX = 1, +}; +/* ctx debugfs end */ + +struct cdma_dbgfs_cfg_info { + const char *name; + bool dentry_valid[CDMA_DBG_DENTRY_ROOT]; + const struct file_operations file_ops; +}; + +struct cdma_dbgfs_cfg { + u32 queue_id; + u32 entry_pi; + u32 entry_ci; +}; + +enum cdma_dbgfs_cfg_type { + CDMA_QUEUE_ID = 0, + CDMA_ENTRY_PI, + CDMA_ENTRY_CI +}; + +struct cdma_dbgfs { + struct ubase_dbgfs dbgfs; + struct cdma_dbgfs_cfg cfg; +}; + +int cdma_dbg_init(struct auxiliary_device *adev); +void cdma_dbg_uninit(struct auxiliary_device *adev); + +#endif /* CDMA_DEBUGFS_H */ diff --git a/drivers/ub/cdma/cdma_jfs.h b/drivers/ub/cdma/cdma_jfs.h index fe46955c925b..3d0391b03d97 100644 --- a/drivers/ub/cdma/cdma_jfs.h +++ b/drivers/ub/cdma/cdma_jfs.h @@ -314,6 +314,11 @@ struct cdma_jfs_ctx { u32 taack_nack_bm[32]; }; +static inline struct cdma_jfs *to_cdma_jfs(struct cdma_base_jfs *jfs) +{ + return container_of(jfs, struct cdma_jfs, base_jfs); +} + struct cdma_base_jfs *cdma_create_jfs(struct cdma_dev *cdev, struct cdma_jfs_cfg *cfg, struct cdma_udata *udata); diff --git a/drivers/ub/cdma/cdma_main.c b/drivers/ub/cdma/cdma_main.c index 82dc5ab40cf8..cfdb1869e176 100644 --- a/drivers/ub/cdma/cdma_main.c +++ b/drivers/ub/cdma/cdma_main.c @@ -11,6 +11,7 @@ #include "cdma_chardev.h" #include #include "cdma_eq.h" +#include "cdma_debugfs.h" #include "cdma_cmd.h" /* Enabling jfc_arm_mode will cause jfc to report cqe; otherwise, it will not. */ @@ -64,6 +65,11 @@ static int cdma_init_dev_info(struct auxiliary_device *auxdev, struct cdma_dev * if (ret) dev_warn(&auxdev->dev, "query eu failed, ret = %d.\n", ret); + ret = cdma_dbg_init(auxdev); + if (ret) + dev_warn(&auxdev->dev, "init cdma debugfs failed, ret = %d.\n", + ret); + return 0; } @@ -108,6 +114,7 @@ static void cdma_uninit_dev(struct auxiliary_device *auxdev) return; } + cdma_dbg_uninit(auxdev); cdma_unregister_event(auxdev); cdma_destroy_chardev(cdev); cdma_destroy_dev(cdev); diff --git a/drivers/ub/cdma/cdma_queue.h b/drivers/ub/cdma/cdma_queue.h index 5b434ae66bb9..08b24cb0b3fc 100644 --- a/drivers/ub/cdma/cdma_queue.h +++ b/drivers/ub/cdma/cdma_queue.h @@ -4,9 +4,10 @@ #ifndef __CDMA_QUEUE_H__ #define __CDMA_QUEUE_H__ +#include + struct cdma_dev; struct cdma_context; -struct queue_cfg; enum cdma_queue_res_type { QUEUE_RES_TP, -- Gitee From 3c338e47bd32fabaa926c4f2f44156a2eaee3115 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Mon, 29 Sep 2025 18:44:01 +0800 Subject: [PATCH 090/103] ub: cdma: support RX stop flow function commit 9184f7dd7e6ad431f6d076c1b95e0ab7fad255cb openEuler This patch implements the functionality of stopping RX flow during the UE deregistration process in the CDMA driver and intercepts user-space interfaces during the reset process. Signed-off-by: Zhipeng Lu Signed-off-by: Xinchi Ma Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/Makefile | 2 +- drivers/ub/cdma/cdma.h | 14 ++++ drivers/ub/cdma/cdma_api.c | 82 ++++++++++++++++++ drivers/ub/cdma/cdma_chardev.c | 55 +++++++++++- drivers/ub/cdma/cdma_cmd.c | 18 ++++ drivers/ub/cdma/cdma_cmd.h | 3 + drivers/ub/cdma/cdma_context.h | 1 + drivers/ub/cdma/cdma_dev.c | 30 +++++-- drivers/ub/cdma/cdma_dev.h | 2 +- drivers/ub/cdma/cdma_event.c | 47 +++++++---- drivers/ub/cdma/cdma_jfc.c | 8 +- drivers/ub/cdma/cdma_jfs.c | 8 +- drivers/ub/cdma/cdma_main.c | 100 +++++++++++++++++++++- drivers/ub/cdma/cdma_mmap.c | 149 +++++++++++++++++++++++++++++++++ drivers/ub/cdma/cdma_mmap.h | 14 ++++ drivers/ub/cdma/cdma_types.h | 16 ++++ drivers/ub/cdma/cdma_uobj.c | 6 +- drivers/ub/cdma/cdma_uobj.h | 2 +- include/ub/cdma/cdma_api.h | 12 +++ 19 files changed, 529 insertions(+), 40 deletions(-) create mode 100644 drivers/ub/cdma/cdma_mmap.c create mode 100644 drivers/ub/cdma/cdma_mmap.h diff --git a/drivers/ub/cdma/Makefile b/drivers/ub/cdma/Makefile index 2ce4eefa2d84..88dc9946a092 100644 --- a/drivers/ub/cdma/Makefile +++ b/drivers/ub/cdma/Makefile @@ -3,6 +3,6 @@ cdma-$(CONFIG_UB_CDMA) := cdma_main.o cdma_dev.o cdma_chardev.o cdma_cmd.o cdma_tid.o cdma_ioctl.o \ cdma_api.o cdma_context.o cdma_queue.o cdma_uobj.o cdma_jfc.o cdma_common.o \ cdma_db.o cdma_mbox.o cdma_tp.o cdma_jfs.o cdma_eq.o cdma_event.o cdma_segment.o \ - cdma_handle.o cdma_debugfs.o + cdma_handle.o cdma_debugfs.o cdma_mmap.o obj-m += cdma.o diff --git a/drivers/ub/cdma/cdma.h b/drivers/ub/cdma/cdma.h index e782b0229943..b7d00bcf39ac 100644 --- a/drivers/ub/cdma/cdma.h +++ b/drivers/ub/cdma/cdma.h @@ -14,6 +14,10 @@ extern u32 jfc_arm_mode; extern bool cqe_mode; +extern struct list_head g_client_list; +extern struct rw_semaphore g_clients_rwsem; +extern struct rw_semaphore g_device_rwsem; +extern struct mutex g_cdma_reset_mutex; #define CDMA_HW_PAGE_SHIFT 12 #define CDMA_HW_PAGE_SIZE (1 << CDMA_HW_PAGE_SHIFT) @@ -24,6 +28,8 @@ extern bool cqe_mode; #define CDMA_UPI_MASK 0x7FFF +#define DMA_MAX_DEV_NAME 64 + enum cdma_cqe_size { CDMA_64_CQE_SIZE, CDMA_128_CQE_SIZE, @@ -34,6 +40,12 @@ enum cdma_status { CDMA_SUSPEND, }; +enum cdma_client_ops { + CDMA_CLIENT_STOP, + CDMA_CLIENT_REMOVE, + CDMA_CLIENT_ADD, +}; + enum { CDMA_CAP_FEATURE_AR = BIT(0), CDMA_CAP_FEATURE_JFC_INLINE = BIT(4), @@ -195,6 +207,8 @@ struct cdma_dev { struct mutex file_mutex; struct list_head file_list; struct page *arm_db_page; + atomic_t cmdcnt; + struct completion cmddone; }; struct cdma_jfs_event { diff --git a/drivers/ub/cdma/cdma_api.c b/drivers/ub/cdma/cdma_api.c index 8a30d20a1a09..cc3aa6ce4921 100644 --- a/drivers/ub/cdma/cdma_api.c +++ b/drivers/ub/cdma/cdma_api.c @@ -4,6 +4,8 @@ #define pr_fmt(fmt) "CDMA: " fmt #define dev_fmt pr_fmt +#include +#include #include "cdma_segment.h" #include "cdma_dev.h" #include "cdma_cmd.h" @@ -14,6 +16,10 @@ #include "cdma_handle.h" #include +LIST_HEAD(g_client_list); +DECLARE_RWSEM(g_clients_rwsem); +DECLARE_RWSEM(g_device_rwsem); + struct dma_device *dma_get_device_list(u32 *num_devices) { struct cdma_device_attr *attr; @@ -632,3 +638,79 @@ int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, return cdma_poll_jfc(cdma_queue->jfc, cr_cnt, cr); } EXPORT_SYMBOL_GPL(dma_poll_queue); + +int dma_register_client(struct dma_client *client) +{ + struct cdma_dev *cdev = NULL; + struct xarray *cdma_devs_tbl; + unsigned long index = 0; + u32 devs_num; + + if (client == NULL || client->client_name == NULL || + client->add == NULL || client->remove == NULL || + client->stop == NULL) { + pr_err("invalid parameter.\n"); + return -EINVAL; + } + + if (strnlen(client->client_name, DMA_MAX_DEV_NAME) >= DMA_MAX_DEV_NAME) { + pr_err("invalid parameter, client name.\n"); + return -EINVAL; + } + + down_write(&g_device_rwsem); + + cdma_devs_tbl = get_cdma_dev_tbl(&devs_num); + + xa_for_each(cdma_devs_tbl, index, cdev) { + if (client->add && client->add(cdev->eid)) + pr_info("dma client: %s add failed.\n", + client->client_name); + } + down_write(&g_clients_rwsem); + list_add_tail(&client->list_node, &g_client_list); + up_write(&g_clients_rwsem); + up_write(&g_device_rwsem); + + pr_info("dma client: %s register success.\n", client->client_name); + return 0; +} +EXPORT_SYMBOL_GPL(dma_register_client); + +void dma_unregister_client(struct dma_client *client) +{ + struct cdma_dev *cdev = NULL; + struct xarray *cdma_devs_tbl; + unsigned long index = 0; + u32 devs_num; + + if (client == NULL || client->client_name == NULL || + client->add == NULL || client->remove == NULL || + client->stop == NULL) { + pr_err("Invalid parameter.\n"); + return; + } + + if (strnlen(client->client_name, DMA_MAX_DEV_NAME) >= DMA_MAX_DEV_NAME) { + pr_err("invalid parameter, client name.\n"); + return; + } + + down_write(&g_device_rwsem); + cdma_devs_tbl = get_cdma_dev_tbl(&devs_num); + + xa_for_each(cdma_devs_tbl, index, cdev) { + if (client->stop && client->remove) { + client->stop(cdev->eid); + client->remove(cdev->eid); + } + } + + down_write(&g_clients_rwsem); + list_del(&client->list_node); + up_write(&g_clients_rwsem); + up_write(&g_device_rwsem); + + pr_info("dma client: %s unregister success.\n", client->client_name); +} +EXPORT_SYMBOL_GPL(dma_unregister_client); diff --git a/drivers/ub/cdma/cdma_chardev.c b/drivers/ub/cdma/cdma_chardev.c index a1a289eb0e91..3614609d683e 100644 --- a/drivers/ub/cdma/cdma_chardev.c +++ b/drivers/ub/cdma/cdma_chardev.c @@ -6,6 +6,7 @@ #include #include +#include "cdma_cmd.h" #include "cdma_ioctl.h" #include "cdma_context.h" #include "cdma_chardev.h" @@ -13,6 +14,7 @@ #include "cdma_types.h" #include "cdma_uobj.h" #include "cdma.h" +#include "cdma_mmap.h" #define CDMA_DEVICE_NAME "cdma/dev" @@ -65,18 +67,27 @@ static long cdma_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct cdma_ioctl_hdr hdr = { 0 }; int ret; + if (!cfile->cdev || cfile->cdev->status == CDMA_SUSPEND) { + pr_info("ioctl cdev is invalid.\n"); + return -ENODEV; + } + cdma_cmd_inc(cfile->cdev); + if (cmd == CDMA_SYNC) { ret = copy_from_user(&hdr, (void *)arg, sizeof(hdr)); if (ret || hdr.args_len > CDMA_MAX_CMD_SIZE) { pr_err("copy user ret = %d, input parameter len = %u.\n", ret, hdr.args_len); + cdma_cmd_dec(cfile->cdev); return -EINVAL; } ret = cdma_cmd_parse(cfile, &hdr); + cdma_cmd_dec(cfile->cdev); return ret; } pr_err("invalid ioctl command, command = %u.\n", cmd); + cdma_cmd_dec(cfile->cdev); return -ENOIOCTLCMD; } @@ -115,6 +126,11 @@ static int cdma_remap_pfn_range(struct cdma_file *cfile, struct vm_area_struct * u32 jfs_id; u32 cmd; + if (cdev->status == CDMA_SUSPEND) { + dev_warn(cdev->dev, "cdev is resetting.\n"); + return -EBUSY; + } + db_addr = cdev->db_base; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); @@ -158,21 +174,37 @@ static int cdma_remap_pfn_range(struct cdma_file *cfile, struct vm_area_struct * static int cdma_mmap(struct file *file, struct vm_area_struct *vma) { struct cdma_file *cfile = (struct cdma_file *)file->private_data; + struct cdma_umap_priv *priv; int ret; + if (!cfile->cdev || cfile->cdev->status == CDMA_SUSPEND) { + pr_info("mmap cdev is invalid.\n"); + return -ENODEV; + } + if (((vma->vm_end - vma->vm_start) % PAGE_SIZE) != 0) { pr_err("mmap failed, expect vm area size to be an integer multiple of page size.\n"); return -EINVAL; } + priv = kzalloc(sizeof(struct cdma_umap_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + vma->vm_ops = cdma_get_umap_ops(); + vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND | VM_WIPEONFORK | VM_IO); + mutex_lock(&cfile->ctx_mutex); ret = cdma_remap_pfn_range(cfile, vma); if (ret) { mutex_unlock(&cfile->ctx_mutex); + kfree(priv); return ret; } mutex_unlock(&cfile->ctx_mutex); + cdma_umap_priv_init(priv, vma); + return 0; } @@ -188,7 +220,7 @@ static void cdma_mmu_release(struct mmu_notifier *mn, struct mm_struct *mm) mn_notifier->mm = NULL; mutex_lock(&cfile->ctx_mutex); - cdma_cleanup_context_uobj(cfile); + cdma_cleanup_context_uobj(cfile, CDMA_REMOVE_CLOSE); if (cfile->uctx) cdma_cleanup_context_res(cfile->uctx); cfile->uctx = NULL; @@ -235,6 +267,11 @@ static int cdma_open(struct inode *inode, struct file *file) chardev = container_of(inode->i_cdev, struct cdma_chardev, cdev); cdev = container_of(chardev, struct cdma_dev, chardev); + if (cdev->status == CDMA_SUSPEND) { + dev_warn(cdev->dev, "cdev is resetting.\n"); + return -EBUSY; + } + cfile = kzalloc(sizeof(struct cdma_file), GFP_KERNEL); if (!cfile) return -ENOMEM; @@ -254,6 +291,8 @@ static int cdma_open(struct inode *inode, struct file *file) file->private_data = cfile; mutex_init(&cfile->ctx_mutex); list_add_tail(&cfile->list, &cdev->file_list); + mutex_init(&cfile->umap_mutex); + INIT_LIST_HEAD(&cfile->umaps_list); nonseekable_open(inode, file); mutex_unlock(&cdev->file_mutex); @@ -265,19 +304,28 @@ static int cdma_close(struct inode *inode, struct file *file) struct cdma_file *cfile = (struct cdma_file *)file->private_data; struct cdma_dev *cdev; + mutex_lock(&g_cdma_reset_mutex); + cdev = cfile->cdev; + if (!cdev) { + mutex_unlock(&g_cdma_reset_mutex); + kref_put(&cfile->ref, cdma_release_file); + inode->i_cdev = NULL; + return 0; + } mutex_lock(&cdev->file_mutex); list_del(&cfile->list); mutex_unlock(&cdev->file_mutex); mutex_lock(&cfile->ctx_mutex); - cdma_cleanup_context_uobj(cfile); + cdma_cleanup_context_uobj(cfile, CDMA_REMOVE_CLOSE); if (cfile->uctx) cdma_cleanup_context_res(cfile->uctx); cfile->uctx = NULL; mutex_unlock(&cfile->ctx_mutex); + mutex_unlock(&g_cdma_reset_mutex); kref_put(&cfile->ref, cdma_release_file); pr_debug("cdma close success.\n"); @@ -361,7 +409,10 @@ void cdma_release_file(struct kref *ref) { struct cdma_file *cfile = container_of(ref, struct cdma_file, ref); + if (cfile->fault_page) + __free_pages(cfile->fault_page, 0); cdma_unregister_mmu(cfile); + mutex_destroy(&cfile->umap_mutex); mutex_destroy(&cfile->ctx_mutex); idr_destroy(&cfile->idr); kfree(cfile); diff --git a/drivers/ub/cdma/cdma_cmd.c b/drivers/ub/cdma/cdma_cmd.c index 74e6b32a58c7..c8bf01d930ad 100644 --- a/drivers/ub/cdma/cdma_cmd.c +++ b/drivers/ub/cdma/cdma_cmd.c @@ -214,3 +214,21 @@ int cdma_ctrlq_query_eu(struct cdma_dev *cdev) return 0; } + +void cdma_cmd_inc(struct cdma_dev *cdev) +{ + atomic_inc(&cdev->cmdcnt); +} + +void cdma_cmd_dec(struct cdma_dev *cdev) +{ + if (atomic_dec_and_test(&cdev->cmdcnt)) + complete(&cdev->cmddone); +} + +void cdma_cmd_flush(struct cdma_dev *cdev) +{ + cdma_cmd_dec(cdev); + pr_info("cmd flush cmdcnt is %d\n", atomic_read(&cdev->cmdcnt)); + wait_for_completion(&cdev->cmddone); +} diff --git a/drivers/ub/cdma/cdma_cmd.h b/drivers/ub/cdma/cdma_cmd.h index 550f60640b36..f85331c8c51b 100644 --- a/drivers/ub/cdma/cdma_cmd.h +++ b/drivers/ub/cdma/cdma_cmd.h @@ -76,4 +76,7 @@ struct eu_query_out { int cdma_init_dev_caps(struct cdma_dev *cdev); int cdma_ctrlq_query_eu(struct cdma_dev *cdev); +void cdma_cmd_inc(struct cdma_dev *cdev); +void cdma_cmd_dec(struct cdma_dev *cdev); +void cdma_cmd_flush(struct cdma_dev *cdev); #endif diff --git a/drivers/ub/cdma/cdma_context.h b/drivers/ub/cdma/cdma_context.h index 47736a281257..0eb40763c29d 100644 --- a/drivers/ub/cdma/cdma_context.h +++ b/drivers/ub/cdma/cdma_context.h @@ -24,6 +24,7 @@ struct cdma_context { atomic_t ref_cnt; struct list_head queue_list; struct list_head seg_list; + bool invalid; }; struct cdma_ctx_res { diff --git a/drivers/ub/cdma/cdma_dev.c b/drivers/ub/cdma/cdma_dev.c index f08e60716edc..2b69a44b346e 100644 --- a/drivers/ub/cdma/cdma_dev.c +++ b/drivers/ub/cdma/cdma_dev.c @@ -55,15 +55,18 @@ static int cdma_add_device_to_list(struct cdma_dev *cdev) return -EINVAL; } + down_write(&g_device_rwsem); ret = xa_err(xa_store(&cdma_devs_tbl, adev->id, cdev, GFP_KERNEL)); if (ret) { dev_err(cdev->dev, "store cdma device to table failed, adev id = %u.\n", adev->id); + up_write(&g_device_rwsem); return ret; } atomic_inc(&cdma_devs_num); + up_write(&g_device_rwsem); return 0; } @@ -77,8 +80,10 @@ static void cdma_del_device_from_list(struct cdma_dev *cdev) return; } + down_write(&g_device_rwsem); atomic_dec(&cdma_devs_num); xa_erase(&cdma_devs_tbl, adev->id); + up_write(&g_device_rwsem); } static void cdma_tbl_init(struct cdma_table *table, u32 max, u32 min) @@ -393,6 +398,8 @@ struct cdma_dev *cdma_create_dev(struct auxiliary_device *adev) idr_init(&cdev->ctx_idr); spin_lock_init(&cdev->ctx_lock); + atomic_set(&cdev->cmdcnt, 1); + init_completion(&cdev->cmddone); dev_dbg(&adev->dev, "cdma.%u init succeeded.\n", adev->id); @@ -411,7 +418,7 @@ struct cdma_dev *cdma_create_dev(struct auxiliary_device *adev) return NULL; } -void cdma_destroy_dev(struct cdma_dev *cdev) +void cdma_destroy_dev(struct cdma_dev *cdev, bool is_remove) { struct cdma_context *tmp; int id; @@ -421,21 +428,26 @@ void cdma_destroy_dev(struct cdma_dev *cdev) ubase_virt_unregister(cdev->adev); - cdma_release_table_res(cdev); + if (is_remove) { + cdma_release_table_res(cdev); - idr_for_each_entry(&cdev->ctx_idr, tmp, id) - cdma_free_context(cdev, tmp); - idr_destroy(&cdev->ctx_idr); + idr_for_each_entry(&cdev->ctx_idr, tmp, id) + cdma_free_context(cdev, tmp); + idr_destroy(&cdev->ctx_idr); + } cdma_destroy_arm_db_page(cdev); ubase_ctrlq_unregister_crq_event(cdev->adev, UBASE_CTRLQ_SER_TYPE_DEV_REGISTER, CDMA_CTRLQ_EU_UPDATE); - cdma_free_dev_tid(cdev); - cdma_del_device_from_list(cdev); - cdma_uninit_dev_param(cdev); - kfree(cdev); + if (is_remove) { + cdma_free_dev_tid(cdev); + + cdma_del_device_from_list(cdev); + cdma_uninit_dev_param(cdev); + kfree(cdev); + } } bool cdma_find_seid_in_eus(struct eu_info *eus, u8 eu_num, struct dev_eid *eid, diff --git a/drivers/ub/cdma/cdma_dev.h b/drivers/ub/cdma/cdma_dev.h index 85d41cbe0773..d433218934f1 100644 --- a/drivers/ub/cdma/cdma_dev.h +++ b/drivers/ub/cdma/cdma_dev.h @@ -24,7 +24,7 @@ enum cdma_ctrlq_eu_op { }; struct cdma_dev *cdma_create_dev(struct auxiliary_device *adev); -void cdma_destroy_dev(struct cdma_dev *cdev); +void cdma_destroy_dev(struct cdma_dev *cdev, bool is_remove); struct cdma_dev *get_cdma_dev_by_eid(u32 eid); struct xarray *get_cdma_dev_tbl(u32 *devices_num); bool cdma_find_seid_in_eus(struct eu_info *eus, u8 eu_num, struct dev_eid *eid, diff --git a/drivers/ub/cdma/cdma_event.c b/drivers/ub/cdma/cdma_event.c index f2c51d4833ee..057bf2daefc3 100644 --- a/drivers/ub/cdma/cdma_event.c +++ b/drivers/ub/cdma/cdma_event.c @@ -520,28 +520,40 @@ static int cdma_get_async_event(struct cdma_jfae *jfae, struct file *filp, return -EINVAL; } - INIT_LIST_HEAD(&event_list); - ret = cdma_wait_event(&jfae->jfe, filp->f_flags & O_NONBLOCK, 1, - &event_cnt, &event_list); - if (ret < 0) { - pr_err("wait event failed, ret = %d.\n", ret); - return ret; - } - event = list_first_entry(&event_list, struct cdma_jfe_event, node); - if (event == NULL) - return -EIO; - - cdma_set_async_event(&async_event, event); - list_del(&event->node); - kfree(event); - - if (event_cnt > 0) { + if (!jfae->cfile->cdev || jfae->cfile->cdev->status == CDMA_SUSPEND) { + pr_info("wait dev invalid event success.\n"); + async_event.event_data = 0; + async_event.event_type = CDMA_EVENT_DEV_INVALID; ret = (int)copy_to_user((void *)arg, &async_event, sizeof(async_event)); if (ret) { pr_err("dev copy to user failed, ret = %d\n", ret); return -EFAULT; } + } else { + INIT_LIST_HEAD(&event_list); + ret = cdma_wait_event(&jfae->jfe, filp->f_flags & O_NONBLOCK, 1, + &event_cnt, &event_list); + if (ret < 0) { + pr_err("wait event failed, ret = %d.\n", ret); + return ret; + } + event = list_first_entry(&event_list, struct cdma_jfe_event, node); + if (event == NULL) + return -EIO; + + cdma_set_async_event(&async_event, event); + list_del(&event->node); + kfree(event); + + if (event_cnt > 0) { + ret = (int)copy_to_user((void *)arg, &async_event, + sizeof(async_event)); + if (ret) { + pr_err("dev copy to user failed, ret = %d\n", ret); + return -EFAULT; + } + } } return 0; @@ -554,6 +566,9 @@ static __poll_t cdma_jfae_poll(struct file *filp, struct poll_table_struct *wait if (!jfae || !jfae->cfile || !jfae->cfile->cdev) return POLLERR; + if (jfae->cfile->cdev->status == CDMA_SUSPEND) + return POLLIN | POLLRDNORM; + return cdma_jfe_poll(&jfae->jfe, filp, wait); } diff --git a/drivers/ub/cdma/cdma_jfc.c b/drivers/ub/cdma/cdma_jfc.c index cd92f90461ff..0b3611c3d27d 100644 --- a/drivers/ub/cdma/cdma_jfc.c +++ b/drivers/ub/cdma/cdma_jfc.c @@ -555,9 +555,11 @@ int cdma_delete_jfc(struct cdma_dev *cdev, u32 jfcn, return -EINVAL; } - ret = cdma_destroy_and_flush_jfc(cdev, jfc->jfcn); - if (ret) - dev_err(cdev->dev, "jfc delete failed, jfcn = %u.\n", jfcn); + if (!(jfc->base.ctx && jfc->base.ctx->invalid)) { + ret = cdma_destroy_and_flush_jfc(cdev, jfc->jfcn); + if (ret) + dev_err(cdev->dev, "jfc delete failed, jfcn = %u.\n", jfcn); + } if (refcount_dec_and_test(&jfc->event_refcount)) complete(&jfc->event_comp); diff --git a/drivers/ub/cdma/cdma_jfs.c b/drivers/ub/cdma/cdma_jfs.c index cbb47a7f56db..8a62e2a2fd6b 100644 --- a/drivers/ub/cdma/cdma_jfs.c +++ b/drivers/ub/cdma/cdma_jfs.c @@ -538,9 +538,11 @@ int cdma_delete_jfs(struct cdma_dev *cdev, u32 jfs_id) return -EINVAL; } - ret = cdma_modify_and_destroy_jfs(cdev, &jfs->sq); - if (ret) - dev_err(cdev->dev, "jfs delete failed, id = %u.\n", jfs->id); + if (!(jfs->base_jfs.ctx && jfs->base_jfs.ctx->invalid)) { + ret = cdma_modify_and_destroy_jfs(cdev, &jfs->sq); + if (ret) + dev_err(cdev->dev, "jfs delete failed, id = %u.\n", jfs->id); + } if (refcount_dec_and_test(&jfs->ae_ref_cnt)) complete(&jfs->ae_comp); diff --git a/drivers/ub/cdma/cdma_main.c b/drivers/ub/cdma/cdma_main.c index cfdb1869e176..817bcd6232e3 100644 --- a/drivers/ub/cdma/cdma_main.c +++ b/drivers/ub/cdma/cdma_main.c @@ -13,6 +13,14 @@ #include "cdma_eq.h" #include "cdma_debugfs.h" #include "cdma_cmd.h" +#include "cdma_types.h" +#include "cdma_mmap.h" +#include "cdma_context.h" +#include "cdma_uobj.h" +#include "cdma_event.h" + +static bool is_rmmod; +DEFINE_MUTEX(g_cdma_reset_mutex); /* Enabling jfc_arm_mode will cause jfc to report cqe; otherwise, it will not. */ uint jfc_arm_mode; @@ -52,6 +60,47 @@ static inline void cdma_unregister_event(struct auxiliary_device *adev) cdma_unreg_ae_event(adev); } +static void cdma_reset_unmap_vma_pages(struct cdma_dev *cdev, bool is_reset) +{ + struct cdma_file *cfile; + + mutex_lock(&cdev->file_mutex); + list_for_each_entry(cfile, &cdev->file_list, list) { + mutex_lock(&cfile->ctx_mutex); + cdma_unmap_vma_pages(cfile); + if (is_reset && cfile->uctx != NULL) + cfile->uctx->invalid = true; + mutex_unlock(&cfile->ctx_mutex); + } + mutex_unlock(&cdev->file_mutex); +} + +static void cdma_client_handler(struct cdma_dev *cdev, + enum cdma_client_ops client_ops) +{ + struct dma_client *client; + + down_write(&g_clients_rwsem); + list_for_each_entry(client, &g_client_list, list_node) { + switch (client_ops) { + case CDMA_CLIENT_STOP: + if (client->stop) + client->stop(cdev->eid); + break; + case CDMA_CLIENT_REMOVE: + if (client->remove) + client->remove(cdev->eid); + break; + case CDMA_CLIENT_ADD: + if (client->add && client->add(cdev->eid)) + dev_warn(&cdev->adev->dev, "add eid:0x%x, cdev for client:%s failed.\n", + cdev->eid, client->client_name); + break; + } + } + up_write(&g_clients_rwsem); +} + static int cdma_init_dev_info(struct auxiliary_device *auxdev, struct cdma_dev *cdev) { int ret; @@ -73,9 +122,33 @@ static int cdma_init_dev_info(struct auxiliary_device *auxdev, struct cdma_dev * return 0; } +static void cdma_free_cfile_uobj(struct cdma_dev *cdev) +{ + struct cdma_file *cfile, *next_cfile; + struct cdma_jfae *jfae; + + mutex_lock(&cdev->file_mutex); + list_for_each_entry_safe(cfile, next_cfile, &cdev->file_list, list) { + list_del(&cfile->list); + mutex_lock(&cfile->ctx_mutex); + cdma_cleanup_context_uobj(cfile, CDMA_REMOVE_DRIVER_REMOVE); + cfile->cdev = NULL; + if (cfile->uctx) { + jfae = (struct cdma_jfae *)cfile->uctx->jfae; + if (jfae) + wake_up_interruptible(&jfae->jfe.poll_wait); + cdma_cleanup_context_res(cfile->uctx); + } + cfile->uctx = NULL; + mutex_unlock(&cfile->ctx_mutex); + } + mutex_unlock(&cdev->file_mutex); +} + static int cdma_init_dev(struct auxiliary_device *auxdev) { struct cdma_dev *cdev; + bool is_remove = true; int ret; dev_dbg(&auxdev->dev, "%s called, matched aux dev(%s.%u).\n", @@ -87,37 +160,56 @@ static int cdma_init_dev(struct auxiliary_device *auxdev) ret = cdma_create_chardev(cdev); if (ret) { - cdma_destroy_dev(cdev); + cdma_destroy_dev(cdev, is_remove); return ret; } ret = cdma_init_dev_info(auxdev, cdev); if (ret) { cdma_destroy_chardev(cdev); - cdma_destroy_dev(cdev); + cdma_destroy_dev(cdev, is_remove); return ret; } + cdma_client_handler(cdev, CDMA_CLIENT_ADD); return ret; } static void cdma_uninit_dev(struct auxiliary_device *auxdev) { struct cdma_dev *cdev; + int ret; dev_dbg(&auxdev->dev, "%s called, matched aux dev(%s.%u).\n", __func__, auxdev->name, auxdev->id); + mutex_lock(&g_cdma_reset_mutex); cdev = dev_get_drvdata(&auxdev->dev); if (!cdev) { dev_err(&auxdev->dev, "get drvdata from ubase failed.\n"); + ubase_reset_unregister(auxdev); + mutex_unlock(&g_cdma_reset_mutex); return; } + cdev->status = CDMA_SUSPEND; + cdma_cmd_flush(cdev); + cdma_client_handler(cdev, CDMA_CLIENT_STOP); + cdma_client_handler(cdev, CDMA_CLIENT_REMOVE); + cdma_reset_unmap_vma_pages(cdev, false); + + if (!is_rmmod) { + ret = ubase_deactivate_dev(auxdev); + dev_info(&auxdev->dev, "ubase deactivate dev ret = %d.\n", ret); + } + + ubase_reset_unregister(auxdev); cdma_dbg_uninit(auxdev); cdma_unregister_event(auxdev); cdma_destroy_chardev(cdev); - cdma_destroy_dev(cdev); + cdma_free_cfile_uobj(cdev); + cdma_destroy_dev(cdev, true); + mutex_unlock(&g_cdma_reset_mutex); } static int cdma_probe(struct auxiliary_device *auxdev, @@ -135,6 +227,7 @@ static int cdma_probe(struct auxiliary_device *auxdev, static void cdma_remove(struct auxiliary_device *auxdev) { cdma_uninit_dev(auxdev); + pr_info("cdma device remove success.\n"); } static const struct auxiliary_device_id cdma_id_table[] = { @@ -178,6 +271,7 @@ static int __init cdma_init(void) static void __exit cdma_exit(void) { + is_rmmod = true; auxiliary_driver_unregister(&cdma_driver); class_destroy(cdma_cdev_class); } diff --git a/drivers/ub/cdma/cdma_mmap.c b/drivers/ub/cdma/cdma_mmap.c new file mode 100644 index 000000000000..eaef6a9a4152 --- /dev/null +++ b/drivers/ub/cdma/cdma_mmap.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#define pr_fmt(fmt) "CDMA: " fmt + +#include +#include +#include "cdma_mmap.h" + +void cdma_umap_priv_init(struct cdma_umap_priv *priv, + struct vm_area_struct *vma) +{ + struct cdma_file *cfile = (struct cdma_file *)vma->vm_file->private_data; + + priv->vma = vma; + vma->vm_private_data = priv; + + mutex_lock(&cfile->umap_mutex); + list_add(&priv->node, &cfile->umaps_list); + mutex_unlock(&cfile->umap_mutex); +} + +/* thanks to drivers/infiniband/core/ib_core_uverbs.c */ +void cdma_unmap_vma_pages(struct cdma_file *cfile) +{ + struct cdma_umap_priv *priv, *next_priv; + struct mm_struct *mm = NULL; + struct vm_area_struct *vma; + int ret; + + while (1) { + mm = NULL; + mutex_lock(&cfile->umap_mutex); + list_for_each_entry_safe(priv, next_priv, &cfile->umaps_list, node) { + mm = priv->vma->vm_mm; + ret = mmget_not_zero(mm); + if (!ret) { + list_del_init(&priv->node); + mm = NULL; + continue; + } + break; + } + mutex_unlock(&cfile->umap_mutex); + if (!mm) + return; + + mutex_lock(&cfile->umap_mutex); + list_for_each_entry_safe(priv, next_priv, &cfile->umaps_list, node) { + vma = priv->vma; + if (vma->vm_mm != mm) + continue; + list_del_init(&priv->node); + zap_vma_ptes(vma, vma->vm_start, vma->vm_end - vma->vm_start); + } + mutex_unlock(&cfile->umap_mutex); + + mmput(mm); + } +} + +static void cdma_umap_open(struct vm_area_struct *vma) +{ + struct cdma_umap_priv *priv; + + priv = kzalloc(sizeof(struct cdma_umap_priv), GFP_KERNEL); + if (!priv) + goto out_zap; + + cdma_umap_priv_init(priv, vma); + + return; + +out_zap: + vma->vm_private_data = NULL; + zap_vma_ptes(vma, vma->vm_start, vma->vm_end - vma->vm_start); +} + +static void cdma_umap_close(struct vm_area_struct *vma) +{ + struct cdma_umap_priv *priv = (struct cdma_umap_priv *)vma->vm_private_data; + struct cdma_file *cfile = (struct cdma_file *)vma->vm_file->private_data; + + if (!priv) + return; + + mutex_lock(&cfile->umap_mutex); + list_del(&priv->node); + mutex_unlock(&cfile->umap_mutex); + kfree(priv); + vma->vm_private_data = NULL; + + pr_info("cdma umap close success.\n"); +} + +static vm_fault_t cdma_umap_fault(struct vm_fault *vmf) +{ + struct cdma_umap_priv *priv = (struct cdma_umap_priv *)vmf->vma->vm_private_data; + struct cdma_file *cfile = (struct cdma_file *)vmf->vma->vm_file->private_data; + vm_fault_t ret = 0; + + if (!priv) + return VM_FAULT_SIGBUS; + + if (!(vmf->vma->vm_flags & (VM_WRITE | VM_MAYWRITE))) { + vmf->page = ZERO_PAGE(0); + get_page(vmf->page); + return 0; + } + + mutex_lock(&cfile->umap_mutex); + if (!cfile->fault_page) + cfile->fault_page = alloc_pages(vmf->gfp_mask | __GFP_ZERO, 0); + + if (cfile->fault_page) { + vmf->page = cfile->fault_page; + get_page(vmf->page); + } else { + ret = VM_FAULT_SIGBUS; + } + mutex_unlock(&cfile->umap_mutex); + + return ret; +} + +static int cdma_umap_remap(struct vm_area_struct *vma) +{ + pr_err("cdma umap remap is not permitted.\n"); + return -EINVAL; +} + +static int cdma_umap_can_split(struct vm_area_struct *vma, unsigned long addr) +{ + pr_err("cdma umap split is not permitted.\n"); + return -EINVAL; +} + +static const struct vm_operations_struct g_cdma_umap_ops = { + .open = cdma_umap_open, + .close = cdma_umap_close, + .fault = cdma_umap_fault, + .mremap = cdma_umap_remap, + .may_split = cdma_umap_can_split, +}; + +const struct vm_operations_struct *cdma_get_umap_ops(void) +{ + return (const struct vm_operations_struct *)&g_cdma_umap_ops; +} diff --git a/drivers/ub/cdma/cdma_mmap.h b/drivers/ub/cdma/cdma_mmap.h new file mode 100644 index 000000000000..0dd6c609a85e --- /dev/null +++ b/drivers/ub/cdma/cdma_mmap.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ + +#ifndef __CDMA_MMAP_H__ +#define __CDMA_MMAP_H__ + +#include +#include "cdma_types.h" + +void cdma_unmap_vma_pages(struct cdma_file *cfile); +const struct vm_operations_struct *cdma_get_umap_ops(void); +void cdma_umap_priv_init(struct cdma_umap_priv *priv, struct vm_area_struct *vma); + +#endif /* CDMA_MMAP_H */ diff --git a/drivers/ub/cdma/cdma_types.h b/drivers/ub/cdma/cdma_types.h index 0b861c891558..947c360ba2ef 100644 --- a/drivers/ub/cdma/cdma_types.h +++ b/drivers/ub/cdma/cdma_types.h @@ -12,6 +12,14 @@ enum cdma_event_type { CDMA_EVENT_JFC_ERR, CDMA_EVENT_JFS_ERR, + CDMA_EVENT_DEV_INVALID, +}; + +enum cdma_remove_reason { + /* Context deletion. This call should delete the actual object itself */ + CDMA_REMOVE_CLOSE, + /* Driver is being hot-unplugged. This call should delete the actual object itself */ + CDMA_REMOVE_DRIVER_REMOVE, }; struct cdma_ucontext { @@ -142,8 +150,16 @@ struct cdma_file { struct cdma_context *uctx; struct idr idr; spinlock_t idr_lock; + struct mutex umap_mutex; + struct list_head umaps_list; + struct page *fault_page; struct cdma_mn mn_notifier; struct kref ref; }; +struct cdma_umap_priv { + struct vm_area_struct *vma; + struct list_head node; +}; + #endif diff --git a/drivers/ub/cdma/cdma_uobj.c b/drivers/ub/cdma/cdma_uobj.c index 3e6e1f9ad1b6..92fe4da441ea 100644 --- a/drivers/ub/cdma/cdma_uobj.c +++ b/drivers/ub/cdma/cdma_uobj.c @@ -2,6 +2,7 @@ /* Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved. */ #include +#include "cdma_mmap.h" #include "cdma_uobj.h" #include "cdma_chardev.h" @@ -104,11 +105,14 @@ struct cdma_uobj *cdma_uobj_get(struct cdma_file *cfile, int id, return uobj; } -void cdma_cleanup_context_uobj(struct cdma_file *cfile) +void cdma_cleanup_context_uobj(struct cdma_file *cfile, enum cdma_remove_reason why) { struct cdma_uobj *uobj; int id; + if (why == CDMA_REMOVE_DRIVER_REMOVE) + cdma_unmap_vma_pages(cfile); + spin_lock(&cfile->idr_lock); idr_for_each_entry(&cfile->idr, uobj, id) cdma_uobj_remove(uobj); diff --git a/drivers/ub/cdma/cdma_uobj.h b/drivers/ub/cdma/cdma_uobj.h index 505a66911960..f343559a33ce 100644 --- a/drivers/ub/cdma/cdma_uobj.h +++ b/drivers/ub/cdma/cdma_uobj.h @@ -28,7 +28,7 @@ struct cdma_uobj *cdma_uobj_create(struct cdma_file *cfile, void cdma_uobj_delete(struct cdma_uobj *uobj); struct cdma_uobj *cdma_uobj_get(struct cdma_file *cfile, int id, enum UOBJ_TYPE type); -void cdma_cleanup_context_uobj(struct cdma_file *cfile); +void cdma_cleanup_context_uobj(struct cdma_file *cfile, enum cdma_remove_reason why); void cdma_close_uobj_fd(struct cdma_file *cfile); #endif diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index 6809ba074c05..b90a64f128b9 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -87,6 +87,14 @@ struct dma_notify_data { u64 notify_data; }; +struct dma_client { + struct list_head list_node; + char *client_name; + int (*add)(u32 eid); + void (*remove)(u32 eid); + void (*stop)(u32 eid); +}; + struct dma_device *dma_get_device_list(u32 *num_devices); void dma_free_device_list(struct dma_device *dev_list, u32 num_devices); @@ -132,4 +140,8 @@ enum dma_status dma_faa(struct dma_device *dma_dev, struct dma_seg *rmt_seg, int dma_poll_queue(struct dma_device *dma_dev, int queue_id, u32 cr_cnt, struct dma_cr *cr); +int dma_register_client(struct dma_client *client); + +void dma_unregister_client(struct dma_client *client); + #endif -- Gitee From c784897855c32cc8b540be9eaf341d3bf46128f3 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Mon, 29 Sep 2025 18:47:20 +0800 Subject: [PATCH 091/103] ub: cdma: support reset function commit 710a287ef643833af2d9ac6a4892bb8829a77983 openEuler This patch implements the RX stop flow function during the driver unload or UE reset process in the CDMA driver, the RX resume flow function during the UE reset process, and the process of notifying the control plane to delete the corresponding UE connection information during the UE reset process. Signed-off-by: Zhipeng Lu Signed-off-by: Xinchi Ma Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/cdma/cdma_main.c | 104 ++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/drivers/ub/cdma/cdma_main.c b/drivers/ub/cdma/cdma_main.c index 817bcd6232e3..8ec5849ade39 100644 --- a/drivers/ub/cdma/cdma_main.c +++ b/drivers/ub/cdma/cdma_main.c @@ -101,6 +101,48 @@ static void cdma_client_handler(struct cdma_dev *cdev, up_write(&g_clients_rwsem); } +static void cdma_reset_down(struct auxiliary_device *adev) +{ + struct cdma_dev *cdev; + + mutex_lock(&g_cdma_reset_mutex); + cdev = get_cdma_dev(adev); + if (!cdev || cdev->status == CDMA_SUSPEND) { + dev_warn(&adev->dev, "cdma device is not ready.\n"); + mutex_unlock(&g_cdma_reset_mutex); + return; + } + + cdev->status = CDMA_SUSPEND; + cdma_cmd_flush(cdev); + cdma_reset_unmap_vma_pages(cdev, true); + cdma_client_handler(cdev, CDMA_CLIENT_STOP); + cdma_unregister_event(adev); + cdma_dbg_uninit(adev); + mutex_unlock(&g_cdma_reset_mutex); +} + +static void cdma_reset_uninit(struct auxiliary_device *adev) +{ + enum ubase_reset_stage stage; + struct cdma_dev *cdev; + + mutex_lock(&g_cdma_reset_mutex); + cdev = get_cdma_dev(adev); + if (!cdev) { + dev_info(&adev->dev, "cdma device is not exist.\n"); + mutex_unlock(&g_cdma_reset_mutex); + return; + } + + stage = ubase_get_reset_stage(adev); + if (stage == UBASE_RESET_STAGE_UNINIT && cdev->status == CDMA_SUSPEND) { + cdma_client_handler(cdev, CDMA_CLIENT_REMOVE); + cdma_destroy_dev(cdev, is_rmmod); + } + mutex_unlock(&g_cdma_reset_mutex); +} + static int cdma_init_dev_info(struct auxiliary_device *auxdev, struct cdma_dev *cdev) { int ret; @@ -212,6 +254,66 @@ static void cdma_uninit_dev(struct auxiliary_device *auxdev) mutex_unlock(&g_cdma_reset_mutex); } +static void cdma_reset_init(struct auxiliary_device *adev) +{ + struct cdma_dev *cdev; + + mutex_lock(&g_cdma_reset_mutex); + cdev = get_cdma_dev(adev); + if (!cdev) { + dev_err(&adev->dev, "cdma device is not exist.\n"); + mutex_unlock(&g_cdma_reset_mutex); + return; + } + + if (cdma_register_crq_event(adev)) { + mutex_unlock(&g_cdma_reset_mutex); + return; + } + + if (cdma_create_arm_db_page(cdev)) + goto unregister_crq; + + if (cdma_init_dev_info(adev, cdev)) + goto destory_arm_db_page; + + idr_init(&cdev->ctx_idr); + spin_lock_init(&cdev->ctx_lock); + atomic_set(&cdev->cmdcnt, 1); + cdev->status = CDMA_NORMAL; + cdma_client_handler(cdev, CDMA_CLIENT_ADD); + mutex_unlock(&g_cdma_reset_mutex); + return; + +destory_arm_db_page: + cdma_destroy_arm_db_page(cdev); +unregister_crq: + cdma_unregister_crq_event(adev); + mutex_unlock(&g_cdma_reset_mutex); +} + +static void cdma_reset_handler(struct auxiliary_device *adev, + enum ubase_reset_stage stage) +{ + if (!adev) + return; + + switch (stage) { + case UBASE_RESET_STAGE_DOWN: + cdma_reset_down(adev); + break; + case UBASE_RESET_STAGE_UNINIT: + cdma_reset_uninit(adev); + break; + case UBASE_RESET_STAGE_INIT: + if (!is_rmmod) + cdma_reset_init(adev); + break; + default: + break; + } +} + static int cdma_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *auxdev_id) { @@ -221,6 +323,8 @@ static int cdma_probe(struct auxiliary_device *auxdev, if (ret) return ret; + ubase_reset_register(auxdev, cdma_reset_handler); + return 0; } -- Gitee From 5cd589774f817cc21cb0c6bb4d4956bca309bce4 Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Tue, 11 Nov 2025 15:00:50 +0800 Subject: [PATCH 092/103] ub: cdma: support for cdma kernelspace north-south compatibility requirements commit 34c67ed8f4c1070bd35c18026a36845b26f89b55 openEuler This patch adds north-south compatibility for CDMA. Signed-off-by: Zhipeng Lu Signed-off-by: Lin Yuan Signed-off-by: zhaolichang <943677312@qq.com> --- include/uapi/ub/cdma/cdma_abi.h | 62 +++++++++++++++++++++++++++++++++ include/ub/cdma/cdma_api.h | 16 +++++++++ 2 files changed, 78 insertions(+) diff --git a/include/uapi/ub/cdma/cdma_abi.h b/include/uapi/ub/cdma/cdma_abi.h index b32954f28636..681854ed9765 100644 --- a/include/uapi/ub/cdma/cdma_abi.h +++ b/include/uapi/ub/cdma/cdma_abi.h @@ -142,6 +142,8 @@ struct cdma_cmd_create_jfs_args { __u32 tpn; __u64 dma_jfs; /* dma jfs pointer */ __u32 trans_mode; + __u32 rsv_bitmap; + __u32 rsvd[4]; } in; struct { __u32 id; @@ -149,6 +151,8 @@ struct cdma_cmd_create_jfs_args { __u8 max_sge; __u8 max_rsge; __u64 handle; + __u32 rsv_bitmap; + __u32 rsvd[4]; } out; struct cdma_cmd_udrv_priv udata; }; @@ -163,8 +167,12 @@ struct cdma_cmd_delete_jfs_args { __u32 jfs_id; __u64 handle; __u32 queue_id; + __u32 rsv_bitmap; + __u32 rsvd[4]; } in; struct { + __u32 rsv_bitmap; + __u32 rsvd[4]; } out; }; @@ -178,10 +186,14 @@ struct cdma_cmd_create_ctp_args { __u32 seid; __u32 deid; __u32 queue_id; + __u32 rsv_bitmap; + __u32 rsvd[4]; } in; struct { __u32 tpn; __u64 handle; + __u32 rsv_bitmap; + __u32 rsvd[4]; } out; }; @@ -190,15 +202,25 @@ struct cdma_cmd_delete_ctp_args { __u32 tpn; __u64 handle; __u32 queue_id; + __u32 rsv_bitmap; + __u32 rsvd[4]; } in; struct { + __u32 rsv_bitmap; + __u32 rsvd[4]; } out; }; struct cdma_cmd_create_jfce_args { + struct { + __u32 rsv_bitmap; + __u32 rsvd[4]; + } in; struct { int fd; int id; + __u32 rsv_bitmap; + __u32 rsvd[4]; } out; }; @@ -209,11 +231,15 @@ struct cdma_cmd_create_jfc_args { int jfce_id; __u32 ceqn; __u32 queue_id; + __u32 rsv_bitmap; + __u32 rsvd[4]; } in; struct { __u32 id; __u32 depth; __u64 handle; /* handle of the allocated jfc obj in kernel */ + __u32 rsv_bitmap; + __u32 rsvd[4]; } out; struct cdma_cmd_udrv_priv udata; }; @@ -223,10 +249,14 @@ struct cdma_cmd_delete_jfc_args { __u32 jfcn; __u64 handle; /* handle of jfc */ __u32 queue_id; + __u32 rsv_bitmap; + __u32 rsvd[4]; } in; struct { __u32 comp_events_reported; __u32 async_events_reported; + __u32 rsv_bitmap; + __u32 rsvd[4]; } out; }; @@ -234,16 +264,26 @@ struct cdma_cmd_register_seg_args { struct { __u64 addr; __u64 len; + __u32 rsv_bitmap; + __u32 rsvd[4]; } in; struct { __u64 handle; + __u32 rsv_bitmap; + __u32 rsvd[4]; } out; }; struct cdma_cmd_unregister_seg_args { struct { __u64 handle; + __u32 rsv_bitmap; + __u32 rsvd[4]; } in; + struct { + __u32 rsv_bitmap; + __u32 rsvd[4]; + } out; }; struct dev_eid { @@ -285,16 +325,28 @@ struct cdma_device_attr { }; struct cdma_cmd_query_device_attr_args { + struct { + __u32 rsv_bitmap; + __u32 rsvd[4]; + } in; struct { struct cdma_device_attr attr; + __u32 rsv_bitmap; + __u32 rsvd[4]; } out; }; struct cdma_create_context_args { + struct { + __u32 rsv_bitmap; + __u32 rsvd[4]; + } in; struct { __u8 cqe_size; __u8 dwqe_enable; int async_fd; + __u32 rsv_bitmap; + __u32 rsvd[4]; } out; }; @@ -324,10 +376,14 @@ struct cdma_cmd_create_queue_args { __u8 priority; __u64 user_ctx; __u32 trans_mode; + __u32 rsv_bitmap; + __u32 rsvd[4]; } in; struct { int queue_id; __u64 handle; + __u32 rsv_bitmap; + __u32 rsvd[4]; } out; }; @@ -335,7 +391,13 @@ struct cdma_cmd_delete_queue_args { struct { __u32 queue_id; __u64 handle; + __u32 rsv_bitmap; + __u32 rsvd[4]; } in; + struct { + __u32 rsv_bitmap; + __u32 rsvd[4]; + } out; }; struct cdma_cmd_jfce_wait_args { diff --git a/include/ub/cdma/cdma_api.h b/include/ub/cdma/cdma_api.h index b90a64f128b9..61449ab9ee26 100644 --- a/include/ub/cdma/cdma_api.h +++ b/include/ub/cdma/cdma_api.h @@ -11,6 +11,8 @@ struct dma_device { struct cdma_device_attr attr; atomic_t ref_cnt; void *private_data; + u32 rsv_bitmap; + u32 rsvd[4]; }; enum dma_cr_opcode { @@ -40,6 +42,8 @@ struct dma_cr { u32 local_id; u32 remote_id; u32 tpn; + u32 rsv_bitmap; + u32 rsvd[4]; }; struct queue_cfg { @@ -49,6 +53,8 @@ struct queue_cfg { u32 dcna; struct dev_eid rmt_eid; u32 trans_mode; + u32 rsv_bitmap; + u32 rsvd[6]; }; struct dma_seg { @@ -58,6 +64,8 @@ struct dma_seg { u32 tid; /* data valid only in bit 0-19 */ u32 token_value; bool token_value_valid; + u32 rsv_bitmap; + u32 rsvd[4]; }; struct dma_seg_cfg { @@ -65,6 +73,8 @@ struct dma_seg_cfg { u64 len; u32 token_value; bool token_value_valid; + u32 rsv_bitmap; + u32 rsvd[4]; }; struct dma_context { @@ -80,11 +90,15 @@ enum dma_status { struct dma_cas_data { u64 compare_data; u64 swap_data; + u32 rsv_bitmap; + u32 rsvd[4]; }; struct dma_notify_data { struct dma_seg *notify_seg; u64 notify_data; + u32 rsv_bitmap; + u32 rsvd[4]; }; struct dma_client { @@ -93,6 +107,8 @@ struct dma_client { int (*add)(u32 eid); void (*remove)(u32 eid); void (*stop)(u32 eid); + u32 rsv_bitmap; + u32 rsvd[4]; }; struct dma_device *dma_get_device_list(u32 *num_devices); -- Gitee From ab89ece0400a9ac97b83310efb82c8241cea5a8c Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Thu, 20 Nov 2025 10:20:15 +0800 Subject: [PATCH 093/103] ub: ubase: Fix priqos infomaton interface functions to query and check sl_bitmap commit a2e12d759c3b3669b6318ab54457559d2cd1679e openEuler Previously, in the function 'ubase_get_priqos_info', the input parameter 'sl_priqos->sl_bitmap' was assumed to be provided by the caller. However, the caller doesn't know which SLs can be used. Therefore, this patch sets 'sl_priqos->sl_bitmap' to the union of SLs supported by UNIC and UDMA. And, in the function 'ubase_set_priqos_info', a check process for the input parameter 'sl_priqos->sl_bitmap' is added to ensure that the corresponding SLs in sl_bitmap are those supported by UNIC or UDMA. Fixes: b21a0a4a5d45 ("ub: ubase: Added QoS and traffic management debugging features") Signed-off-by: Zhang Lei Signed-off-by: Fengyan Mu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/ubase/ubase_dev.h | 1 - drivers/ub/ubase/ubase_qos_hw.c | 36 ++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/ub/ubase/ubase_dev.h b/drivers/ub/ubase/ubase_dev.h index d32d9fb98377..c8ccd5bd107a 100644 --- a/drivers/ub/ubase/ubase_dev.h +++ b/drivers/ub/ubase/ubase_dev.h @@ -429,7 +429,6 @@ static inline u32 ubase_ta_timer_align_size(struct ubase_dev *udev) static inline bool ubase_mbx_ue_id_is_valid(u16 mbx_ue_id, struct ubase_dev *udev) { - if (!mbx_ue_id || (mbx_ue_id > udev->caps.dev_caps.ue_num - 1)) return false; diff --git a/drivers/ub/ubase/ubase_qos_hw.c b/drivers/ub/ubase/ubase_qos_hw.c index 5a5881f79547..bfd5c4e0f5c1 100644 --- a/drivers/ub/ubase/ubase_qos_hw.c +++ b/drivers/ub/ubase/ubase_qos_hw.c @@ -409,6 +409,36 @@ int ubase_query_fst_fvt_rqmt(struct ubase_dev *udev, return ret; } +static unsigned long ubase_get_sl_bitmap(struct ubase_dev *udev) +{ + struct ubase_adev_qos *qos = &udev->qos; + unsigned long sl_bitmap = 0; + u8 i; + + for (i = 0; i < qos->nic_sl_num; i++) + sl_bitmap |= 1 << qos->nic_sl[i]; + for (i = 0; i < qos->sl_num; i++) + sl_bitmap |= 1 << qos->sl[i]; + + return sl_bitmap; +} + +static int ubase_check_sl_bitmap(struct ubase_dev *udev, unsigned long sl_bitmap) +{ + unsigned long sl_bitmap_cap; + u8 i; + + sl_bitmap_cap = ubase_get_sl_bitmap(udev); + for (i = 0; i < UBASE_MAX_SL_NUM; i++) { + if (!test_bit(i, &sl_bitmap)) + continue; + if (!test_bit(i, &sl_bitmap_cap)) + return -EINVAL; + } + + return 0; +} + int ubase_check_qos_sch_param(struct auxiliary_device *adev, u16 vl_bitmap, u8 *vl_bw, u8 *vl_tsa, bool is_ets) { @@ -447,6 +477,9 @@ int ubase_set_priqos_info(struct device *dev, struct ubase_sl_priqos *sl_priqos) udev = dev_get_drvdata(dev); + if (ubase_check_sl_bitmap(udev, sl_priqos->sl_bitmap)) + return -EINVAL; + if (sl_priqos->port_bitmap) return ubase_set_ets_priqos(udev, sl_priqos); @@ -458,11 +491,12 @@ int ubase_get_priqos_info(struct device *dev, struct ubase_sl_priqos *sl_priqos) { struct ubase_dev *udev; - if (!dev || !sl_priqos || !sl_priqos->sl_bitmap) + if (!dev || !sl_priqos) return -EINVAL; udev = dev_get_drvdata(dev); + sl_priqos->sl_bitmap = ubase_get_sl_bitmap(udev); if (sl_priqos->port_bitmap) return ubase_get_ets_priqos(udev, sl_priqos); -- Gitee From a4ec6413f379cd8a6c5fc7d2b0350355e5b32b03 Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Thu, 20 Nov 2025 10:34:28 +0800 Subject: [PATCH 094/103] ub: ubase: add CMDQ&CTRLQ compatibility code commit 313470c59d7f1158d832074319e35b823e4ccd29 openEuler The ubase driver and firmware communicate through the CMDQ interface, which needs to be forward and backward compatible. When pairing new drivers with old firmware or old drivers with new firmware, it is essential to ensure that the program can still work. Therefore, some compatibility design needs to be done in advance, and the relevant interfaces should be implemented. In subsequent versions, the predefined compatibility plan should be followed to handle these scenarios. Specifically, during the ubase dev probe, the driver first queries the firmware for the chip version using a message with opcode 0x0001. It then informs the firmware of its supported feature capability set through a message with opcode 0x0007. Subsequently, it queries the firmware for the feature capability sets supported by both the chip and the firmware using a message with opcode 0x0030. These commands could ensure backward and forward compatibility. In the CTRLQ interface, the version number check is addedd. If the version is not supported or the command is not supported, an error response of EOPNOTSUPP is returned. In the CMDQ interface, we removed some obsolete capability bit definitions and interface parameters. And optimized the code for handling scenarios where firmware returns an unauthorized error. In the CTRLQ interface, we add an version number check for requests coming from the control plane. By the way, we have also optimized the parameters of some commands. Fixes: 8d68017f37fa ("ub: ubase: support for command process") Signed-off-by: Chuan Wu Signed-off-by: Fengyan Mu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/net/ub/unic/debugfs/unic_debugfs.c | 1 - drivers/net/ub/unic/unic.h | 5 --- drivers/net/ub/unic/unic_cmd.h | 2 +- drivers/net/ub/unic/unic_dev.c | 21 ++++------- drivers/net/ub/unic/unic_dev.h | 5 --- drivers/net/ub/unic/unic_ethtool.c | 3 -- drivers/net/ub/unic/unic_hw.c | 14 +++---- drivers/net/ub/unic/unic_qos_hw.c | 3 +- drivers/net/ub/unic/unic_rack_ip.c | 7 +++- drivers/net/ub/unic/unic_stats.c | 29 ++++++-------- drivers/ub/ubase/debugfs/ubase_debugfs.c | 10 +---- drivers/ub/ubase/ubase_cmd.c | 16 ++++---- drivers/ub/ubase/ubase_cmd.h | 18 ++++++--- drivers/ub/ubase/ubase_ctrlq.c | 41 +++++++++++++++++--- drivers/ub/ubase/ubase_dev.c | 22 ++++++++--- drivers/ub/ubase/ubase_hw.c | 10 ++--- drivers/ub/ubase/ubase_hw.h | 44 +++++++++------------- drivers/ub/ubase/ubase_qos_hw.c | 9 ++--- include/ub/ubase/ubase_comm_cmd.h | 1 + include/ub/ubase/ubase_comm_dev.h | 5 --- 20 files changed, 132 insertions(+), 134 deletions(-) diff --git a/drivers/net/ub/unic/debugfs/unic_debugfs.c b/drivers/net/ub/unic/debugfs/unic_debugfs.c index 63703934613d..0a6dbdaffedc 100644 --- a/drivers/net/ub/unic/debugfs/unic_debugfs.c +++ b/drivers/net/ub/unic/debugfs/unic_debugfs.c @@ -46,7 +46,6 @@ static const struct unic_dbg_cap_bit_info { {"\tsupport_ubl: %u\n", &unic_dev_ubl_supported}, {"\tsupport_ets: %u\n", &unic_dev_ets_supported}, {"\tsupport_fec: %u\n", &unic_dev_fec_supported}, - {"\tsupport_rss: %u\n", &unic_dev_rss_supported}, {"\tsupport_tc_speed_limit: %u\n", &unic_dev_tc_speed_limit_supported}, {"\tsupport_tx_csum_offload: %u\n", &unic_dev_tx_csum_offload_supported}, {"\tsupport_rx_csum_offload: %u\n", &unic_dev_rx_csum_offload_supported}, diff --git a/drivers/net/ub/unic/unic.h b/drivers/net/ub/unic/unic.h index 7f6572c50a0c..e63ee6e900ff 100644 --- a/drivers/net/ub/unic/unic.h +++ b/drivers/net/ub/unic/unic.h @@ -20,16 +20,11 @@ enum { UNIC_SUPPORT_ETS_B = 1, UNIC_SUPPORT_FEC_B = 2, UNIC_SUPPORT_PAUSE_B = 3, - UNIC_SUPPORT_GRO_B = 5, UNIC_SUPPORT_ETH_B = 7, - UNIC_SUPPORT_TSO_B = 8, - UNIC_SUPPORT_RSS_B = 9, UNIC_SUPPORT_SERIAL_SERDES_LB_B = 10, UNIC_SUPPORT_TC_SPEED_LIMIT_B = 12, UNIC_SUPPORT_TX_CSUM_OFFLOAD_B = 13, - UNIC_SUPPORT_TUNNEL_CSUM_OFFLOAD_B = 14, - UNIC_SUPPORT_PTP_B = 15, UNIC_SUPPORT_RX_CSUM_OFFLOAD_B = 16, UNIC_SUPPORT_APP_LB_B = 17, diff --git a/drivers/net/ub/unic/unic_cmd.h b/drivers/net/ub/unic/unic_cmd.h index bf3e11e343cd..125802234e6b 100644 --- a/drivers/net/ub/unic/unic_cmd.h +++ b/drivers/net/ub/unic/unic_cmd.h @@ -150,7 +150,7 @@ struct unic_config_vl_map_cmd { }; struct unic_config_vl_speed_cmd { - __le16 bus_ue_id; + u8 resv0[2]; __le16 vl_bitmap; __le32 max_speed[UBASE_MAX_VL_NUM]; u8 resv1[20]; diff --git a/drivers/net/ub/unic/unic_dev.c b/drivers/net/ub/unic/unic_dev.c index ef79194c24bb..f8d5676bfc1f 100644 --- a/drivers/net/ub/unic/unic_dev.c +++ b/drivers/net/ub/unic/unic_dev.c @@ -248,10 +248,12 @@ static int unic_init_vl_info(struct unic_dev *unic_dev) return ret; ret = unic_init_vl_maxrate(unic_dev); - if (ret) + if (ret && ret != -EPERM) return ret; - return unic_init_vl_sch(unic_dev); + ret = unic_init_vl_sch(unic_dev); + + return ret == -EPERM ? 0 : ret; } static int unic_init_channels_attr(struct unic_dev *unic_dev) @@ -559,17 +561,12 @@ static int unic_dev_init_mtu(struct unic_dev *unic_dev) { struct net_device *netdev = unic_dev->comdev.netdev; struct unic_caps *caps = &unic_dev->caps; - int ret; netdev->mtu = UB_DATA_LEN; netdev->max_mtu = caps->max_trans_unit; netdev->min_mtu = caps->min_trans_unit; - ret = unic_config_mtu(unic_dev, netdev->mtu); - if (ret == -EPERM) - return 0; - - return ret; + return unic_config_mtu(unic_dev, netdev->mtu); } static int unic_init_mac(struct unic_dev *unic_dev) @@ -583,11 +580,11 @@ static int unic_init_mac(struct unic_dev *unic_dev) ret = unic_set_mac_speed_duplex(unic_dev, mac->speed, mac->duplex, mac->lanes); - if (ret && ret != -EPERM) + if (ret) return ret; ret = unic_set_mac_autoneg(unic_dev, mac->autoneg); - if (ret && ret != -EPERM) + if (ret) return ret; ret = unic_dev_fec_supported(unic_dev) && mac->user_fec_mode ? @@ -621,9 +618,7 @@ int unic_set_mtu(struct unic_dev *unic_dev, int new_mtu) new_mtu = max(new_mtu, UB_DATA_LEN); ret = unic_check_validate_dump_mtu(unic_dev, new_mtu, &max_frame_size); - if (ret == -EPERM) { - return 0; - } else if (ret < 0) { + if (ret) { unic_err(unic_dev, "invalid MTU(%d), please check, ret = %d.\n", new_mtu, ret); return -EINVAL; diff --git a/drivers/net/ub/unic/unic_dev.h b/drivers/net/ub/unic/unic_dev.h index a20744b810e8..51708850e38d 100644 --- a/drivers/net/ub/unic/unic_dev.h +++ b/drivers/net/ub/unic/unic_dev.h @@ -293,11 +293,6 @@ static inline bool unic_dev_fec_supported(struct unic_dev *unic_dev) return unic_get_cap_bit(unic_dev, UNIC_SUPPORT_FEC_B); } -static inline bool unic_dev_rss_supported(struct unic_dev *unic_dev) -{ - return unic_get_cap_bit(unic_dev, UNIC_SUPPORT_RSS_B); -} - static inline bool unic_dev_tc_speed_limit_supported(struct unic_dev *unic_dev) { return unic_get_cap_bit(unic_dev, UNIC_SUPPORT_TC_SPEED_LIMIT_B); diff --git a/drivers/net/ub/unic/unic_ethtool.c b/drivers/net/ub/unic/unic_ethtool.c index c9593ba74fe4..22f530c45107 100644 --- a/drivers/net/ub/unic/unic_ethtool.c +++ b/drivers/net/ub/unic/unic_ethtool.c @@ -67,9 +67,6 @@ static int unic_get_fecparam(struct net_device *ndev, struct unic_dev *unic_dev = netdev_priv(ndev); struct unic_mac *mac = &unic_dev->hw.mac; - if (!unic_dev_fec_supported(unic_dev)) - return -EOPNOTSUPP; - fec->fec = mac->fec_ability; fec->active_fec = mac->fec_mode; diff --git a/drivers/net/ub/unic/unic_hw.c b/drivers/net/ub/unic/unic_hw.c index d2b7026514c4..be606bfb6495 100644 --- a/drivers/net/ub/unic/unic_hw.c +++ b/drivers/net/ub/unic/unic_hw.c @@ -76,7 +76,7 @@ int unic_set_mac_autoneg(struct unic_dev *unic_dev, u8 autoneg) sizeof(req), &req); ret = ubase_cmd_send_in(unic_dev->comdev.adev, &in); - if (ret && ret != -EPERM) + if (ret) dev_err(unic_dev->comdev.adev->dev.parent, "failed to send cmd in config autoneg(%u), ret = %d.\n", autoneg, ret); @@ -105,7 +105,7 @@ int unic_set_mac_speed_duplex(struct unic_dev *unic_dev, u32 speed, u8 duplex, sizeof(req), &req); ret = ubase_cmd_send_in(unic_dev->comdev.adev, &in); - if (ret && ret != -EPERM) + if (ret) dev_err(unic_dev->comdev.adev->dev.parent, "failed to send cmd in config speed(%u), ret = %d.\n", speed, ret); @@ -334,9 +334,7 @@ int unic_set_promisc_mode(struct unic_dev *unic_dev, time_out = unic_cmd_timeout(unic_dev); ret = ubase_cmd_send_in_ex(adev, &in, time_out); - if (ret == -EPERM) - return 0; - else if (ret) + if (ret) unic_err(unic_dev, "failed to set promisc mode, ret = %d.\n", ret); @@ -561,15 +559,15 @@ static int unic_query_flush_status(struct unic_dev *unic_dev, u8 *status) struct ubase_cmd_buf in; int ret; + if (unic_dev_ubl_supported(unic_dev)) + return -EOPNOTSUPP; + ubase_fill_inout_buf(&in, UBASE_OPC_QUERY_FLUSH_STATUS, true, 0, NULL); ubase_fill_inout_buf(&out, UBASE_OPC_QUERY_FLUSH_STATUS, false, sizeof(resp), &resp); ret = ubase_cmd_send_inout(unic_dev->comdev.adev, &in, &out); if (ret) { - if (ret == -EPERM) - return -EOPNOTSUPP; - unic_err(unic_dev, "failed to send cmd when query flush status, ret = %d.\n", ret); diff --git a/drivers/net/ub/unic/unic_qos_hw.c b/drivers/net/ub/unic/unic_qos_hw.c index 79fb7271c08e..bba05964156b 100644 --- a/drivers/net/ub/unic/unic_qos_hw.c +++ b/drivers/net/ub/unic/unic_qos_hw.c @@ -59,7 +59,6 @@ int unic_config_vl_rate_limit(struct unic_dev *unic_dev, u64 *vl_maxrate, u32 vl_rate; int i, ret; - req.bus_ue_id = cpu_to_le16(USHRT_MAX); req.vl_bitmap = cpu_to_le16(vl_bitmap); for (i = 0; i < caps->vl_num; i++) { vl_rate = vl_maxrate[i] / UNIC_MBYTE_PER_SEND; @@ -72,7 +71,7 @@ int unic_config_vl_rate_limit(struct unic_dev *unic_dev, u64 *vl_maxrate, sizeof(req), &req); ret = ubase_cmd_send_in(adev, &in); - if (ret) + if (ret && ret != -EPERM) dev_err(adev->dev.parent, "failed to config vl rate limit, ret = %d.\n", ret); diff --git a/drivers/net/ub/unic/unic_rack_ip.c b/drivers/net/ub/unic/unic_rack_ip.c index f2ff97304e78..529856dcff73 100644 --- a/drivers/net/ub/unic/unic_rack_ip.c +++ b/drivers/net/ub/unic/unic_rack_ip.c @@ -41,7 +41,7 @@ static void unic_update_rack_addr_state(struct unic_vport *vport, addr_node->state = UNIC_COMM_ADDR_TO_ADD; unic_format_masked_ip_addr(format_masked_ip_addr, addr); unic_info(unic_dev, - "deleted an existing ip %s by accident and need to add it.\n", + "stack deleted an planned ip %s, need to re-add it.\n", format_masked_ip_addr); } break; @@ -90,7 +90,7 @@ static int unic_update_stack_ip_addr(struct unic_vport *vport, list_add_tail(&addr_node->node, list); unic_format_masked_ip_addr(format_masked_ip_addr, addr); unic_info(unic_dev, - "added a new ip %s by accident and need to delete it.\n", + "stack added a non-planned ip %s, need to delete it.\n", format_masked_ip_addr); set_bit(UNIC_VPORT_STATE_IP_TBL_CHANGE, &vport->state); goto unlock_and_exit; @@ -469,6 +469,9 @@ int unic_handle_notify_ip_event(struct auxiliary_device *adev, u8 service_ver, struct unic_stack_ip_info st_ip; int ret; + if (service_ver != UBASE_CTRLQ_SER_VER_01) + return -EOPNOTSUPP; + if (len < sizeof(*req)) { unic_err(priv, "failed to verify ip info size, len = %u.\n", len); return -EINVAL; diff --git a/drivers/net/ub/unic/unic_stats.c b/drivers/net/ub/unic/unic_stats.c index dcefeab1bb2d..d8ccd1876500 100644 --- a/drivers/net/ub/unic/unic_stats.c +++ b/drivers/net/ub/unic/unic_stats.c @@ -88,7 +88,7 @@ static int unic_get_dfx_reg_num(struct unic_dev *unic_dev, u32 *reg_num, ubase_fill_inout_buf(&out, UBASE_OPC_DFX_REG_NUM, true, reg_arr_size * sizeof(u32), reg_num); ret = ubase_cmd_send_inout(unic_dev->comdev.adev, &in, &out); - if (ret && ret != -EPERM) + if (ret) unic_err(unic_dev, "failed to query dfx reg num, ret = %d.\n", ret); @@ -149,17 +149,13 @@ int unic_get_regs_len(struct net_device *netdev) return -ENOMEM; ret = unic_get_dfx_reg_num(unic_dev, reg_num, reg_arr_size); - if (!ret) { - count += unic_get_dfx_regs_len(unic_dev, unic_dfx_reg_arr, - reg_arr_size, reg_num); - } else if (ret != -EPERM) { - unic_err(unic_dev, - "failed to get dfx regs length, ret = %d.\n", ret); + if (ret) { kfree(reg_num); - return -EBUSY; } + count += unic_get_dfx_regs_len(unic_dev, unic_dfx_reg_arr, + reg_arr_size, reg_num); kfree(reg_num); return count; @@ -286,17 +282,16 @@ void unic_get_regs(struct net_device *netdev, struct ethtool_regs *cmd, pdata += unic_get_res_regs(unic_dev, pdata); ret = unic_get_dfx_reg_num(unic_dev, reg_num, reg_arr_size); - if (!ret) { - ret = unic_get_dfx_regs(unic_dev, pdata, unic_dfx_reg_arr, - reg_arr_size, reg_num); - if (ret) - unic_err(unic_dev, - "failed to get dfx regs, ret = %d.\n", ret); - } else if (ret != -EPERM) { - unic_err(unic_dev, - "failed to get dfx reg num, ret = %d.\n", ret); + if (ret) { + kfree(reg_num); + return; } + ret = unic_get_dfx_regs(unic_dev, pdata, unic_dfx_reg_arr, + reg_arr_size, reg_num); + if (ret) + unic_err(unic_dev, "failed to get dfx regs, ret = %d.\n", ret); + kfree(reg_num); } diff --git a/drivers/ub/ubase/debugfs/ubase_debugfs.c b/drivers/ub/ubase/debugfs/ubase_debugfs.c index ad97d7a58188..bf49fc3fdc93 100644 --- a/drivers/ub/ubase/debugfs/ubase_debugfs.c +++ b/drivers/ub/ubase/debugfs/ubase_debugfs.c @@ -94,6 +94,7 @@ static void ubase_dbg_dump_caps_info(struct seq_file *s, struct ubase_dev *udev) {"\tdie_id: %u\n", dev_caps->die_id}, {"\tue_id: %u\n", dev_caps->ue_id}, {"\tnl_id: %u\n", dev_caps->nl_id}, + {"\tfw_version: %u\n", dev_caps->fw_version}, }; int i; @@ -123,29 +124,20 @@ static void ubase_dbg_dump_adev_caps(struct seq_file *s, u32 caps_info; } ubase_adev_caps_info[] = { {"\tjfs_max_cnt: %u\n", caps->jfs.max_cnt}, - {"\tjfs_reserved_cnt: %u\n", caps->jfs.reserved_cnt}, {"\tjfs_depth: %u\n", caps->jfs.depth}, {"\tjfr_max_cnt: %u\n", caps->jfr.max_cnt}, - {"\tjfr_reserved_cnt: %u\n", caps->jfr.reserved_cnt}, {"\tjfr_depth: %u\n", caps->jfr.depth}, {"\tjfc_max_cnt: %u\n", caps->jfc.max_cnt}, - {"\tjfc_reserved_cnt: %u\n", caps->jfc.reserved_cnt}, {"\tjfc_depth: %u\n", caps->jfc.depth}, {"\ttp_max_cnt: %u\n", caps->tp.max_cnt}, - {"\ttp_reserved_cnt: %u\n", caps->tp.reserved_cnt}, {"\ttp_depth: %u\n", caps->tp.depth}, {"\ttpg_max_cnt: %u\n", caps->tpg.max_cnt}, - {"\ttpg_reserved_cnt: %u\n", caps->tpg.reserved_cnt}, {"\ttpg_depth: %u\n", caps->tpg.depth}, {"\tcqe_size: %hu\n", caps->cqe_size}, {"\tutp_port_bitmap: 0x%x\n", caps->utp_port_bitmap}, {"\tjtg_max_cnt: %u\n", caps->jtg_max_cnt}, {"\trc_max_cnt: %u\n", caps->rc_max_cnt}, {"\trc_depth: %u\n", caps->rc_que_depth}, - {"\tccc_max_cnt: %u\n", caps->ccc_max_cnt}, - {"\tdest_addr_max_cnt: %u\n", caps->dest_addr_max_cnt}, - {"\tseid_upi_max_cnt: %u\n", caps->seid_upi_max_cnt}, - {"\ttpm_max_cnt: %u\n", caps->tpm_max_cnt}, {"\tprealloc_mem_dma_len: %llu\n", caps->pmem.dma_len}, }; int i; diff --git a/drivers/ub/ubase/ubase_cmd.c b/drivers/ub/ubase/ubase_cmd.c index 4526f92ac117..4eedb6eff530 100644 --- a/drivers/ub/ubase/ubase_cmd.c +++ b/drivers/ub/ubase/ubase_cmd.c @@ -306,10 +306,11 @@ int ubase_send_cmd(struct ubase_dev *udev, return ret; } -static int ubase_cmd_query_version(struct ubase_dev *udev, u32 *fw_version) +static int ubase_cmd_query_version(struct ubase_dev *udev) { struct ubase_query_version_cmd *resp; struct ubase_cmdq_desc desc; + u32 fw_ver; int ret; ubase_cmd_setup_basic_desc(&desc, UBASE_OPC_QUERY_FW_VER, true, 1); @@ -321,13 +322,14 @@ static int ubase_cmd_query_version(struct ubase_dev *udev, u32 *fw_version) } resp = (struct ubase_query_version_cmd *)desc.data; - *fw_version = le32_to_cpu(resp->firmware); + udev->caps.dev_caps.fw_version = le32_to_cpu(resp->fw_version); + fw_ver = udev->caps.dev_caps.fw_version; ubase_info(udev, "The firmware version is %u.%u.%u.%u\n", - u32_get_bits(*fw_version, UBASE_FW_VERSION_BYTE3_MASK), - u32_get_bits(*fw_version, UBASE_FW_VERSION_BYTE2_MASK), - u32_get_bits(*fw_version, UBASE_FW_VERSION_BYTE1_MASK), - u32_get_bits(*fw_version, UBASE_FW_VERSION_BYTE0_MASK)); + u32_get_bits(fw_ver, UBASE_FW_VERSION_BYTE3_MASK), + u32_get_bits(fw_ver, UBASE_FW_VERSION_BYTE2_MASK), + u32_get_bits(fw_ver, UBASE_FW_VERSION_BYTE1_MASK), + u32_get_bits(fw_ver, UBASE_FW_VERSION_BYTE0_MASK)); return 0; } @@ -366,7 +368,7 @@ int ubase_cmd_init(struct ubase_dev *udev) clear_bit(UBASE_STATE_CMD_DISABLE, &udev->hw.state); - ret = ubase_cmd_query_version(udev, &udev->caps.dev_caps.fw_version); + ret = ubase_cmd_query_version(udev); if (ret) goto err_query_version; diff --git a/drivers/ub/ubase/ubase_cmd.h b/drivers/ub/ubase/ubase_cmd.h index 63b67179f2fb..263e88c9fa49 100644 --- a/drivers/ub/ubase/ubase_cmd.h +++ b/drivers/ub/ubase/ubase_cmd.h @@ -43,10 +43,16 @@ enum ubase_cmd_state { }; struct ubase_query_version_cmd { - __le32 firmware; - __le32 hardware; - __le32 rsv; - __le32 caps[UBASE_CAP_LEN]; + __le32 fw_version; + u8 rsv[20]; +}; + +enum ubase_drv_cap_bit { + UBASE_CAP_SUP_ACTIVATE_B = 0, +}; + +struct ubase_notify_drv_cap_cmd { + u8 cap_bits[24]; /* see ubase_drv_cap_bit */ }; #define UBASE_UBCL_CFG_DATA_ALIGN 4 @@ -106,10 +112,10 @@ struct ubase_cfg_ets_vl_sch_cmd { }; struct ubase_cfg_tm_vl_sch_cmd { - __le16 bus_ue_id; + u8 rsvd0[2]; __le16 vl_bitmap; __le16 vl_tsa; - u8 rsvd[2]; + u8 rsvd1[2]; u8 vl_bw[UBASE_MAX_VL_NUM]; }; diff --git a/drivers/ub/ubase/ubase_ctrlq.c b/drivers/ub/ubase/ubase_ctrlq.c index d590463b0efc..b8d7681dd518 100644 --- a/drivers/ub/ubase/ubase_ctrlq.c +++ b/drivers/ub/ubase/ubase_ctrlq.c @@ -742,6 +742,32 @@ static void ubase_ctrlq_read_msg_data(struct ubase_dev *udev, u8 num, u8 *msg) } } +static void ubase_ctrlq_send_unsupported_resp(struct ubase_dev *udev, + struct ubase_ctrlq_base_block *head, + void *msg_data, u16 msg_data_len, + u16 seq) +{ + struct ubase_ctrlq_msg msg = {0}; + int ret; + + msg.service_ver = head->service_ver; + msg.service_type = head->service_type; + msg.opcode = head->opcode; + msg.in_size = msg_data_len; + msg.in = msg_data; + msg.is_resp = 1; + msg.resp_seq = seq; + msg.resp_ret = EOPNOTSUPP; + + ubase_info(udev, "ctrlq received unsupported req. seq=%u, ser_type=%d, ser_ver=%d, opc=%u.", + seq, head->service_type, head->service_ver, head->opcode); + + ret = __ubase_ctrlq_send(udev, &msg, NULL); + if (ret) + ubase_warn(udev, "failed to send ctrlq unsupported resp. seq=%u, ser_type=%d, ser_ver=%d, opc=%u.", + seq, head->service_type, head->service_ver, head->opcode); +} + static void ubase_ctrlq_crq_event_callback(struct ubase_dev *udev, struct ubase_ctrlq_base_block *head, void *msg_data, u16 msg_data_len, @@ -749,20 +775,25 @@ static void ubase_ctrlq_crq_event_callback(struct ubase_dev *udev, { struct ubase_ctrlq_crq_table *crq_tab = &udev->ctrlq.crq_table; struct ubase_ctrlq_crq_event_nbs *nbs; + int ret = -EOPNOTSUPP; mutex_lock(&crq_tab->lock); list_for_each_entry(nbs, &crq_tab->crq_nbs.list, list) { if (nbs->crq_nb.service_type == head->service_type && nbs->crq_nb.opcode == head->opcode) { - nbs->crq_nb.crq_handler(nbs->crq_nb.back, - head->service_ver, - msg_data, - msg_data_len, - seq); + ret = nbs->crq_nb.crq_handler(nbs->crq_nb.back, + head->service_ver, + msg_data, + msg_data_len, + seq); break; } } mutex_unlock(&crq_tab->lock); + + if (ret == -EOPNOTSUPP) + ubase_ctrlq_send_unsupported_resp(udev, head, msg_data, + msg_data_len, seq); } static void ubase_ctrlq_notify_completed(struct ubase_dev *udev, diff --git a/drivers/ub/ubase/ubase_dev.c b/drivers/ub/ubase/ubase_dev.c index 3921cd0ff824..fa61159d4295 100644 --- a/drivers/ub/ubase/ubase_dev.c +++ b/drivers/ub/ubase/ubase_dev.c @@ -454,11 +454,6 @@ static int ubase_handle_ue2ue_ctrlq_req(struct ubase_dev *udev, return -EINVAL; } - if (cmd->in_size > (len - (sizeof(*cmd) + UBASE_CTRLQ_HDR_LEN))) { - ubase_err(udev, "ubase e2e cmd len = %u error.\n", cmd->in_size); - return -EINVAL; - } - msg.service_ver = head->service_ver; msg.service_type = head->service_type; msg.opcode = head->opcode; @@ -621,6 +616,19 @@ static int ubase_register_cmdq_crq_event(struct ubase_dev *udev) return ret; } +static int ubase_notify_drv_capbilities(struct ubase_dev *udev) +{ + struct ubase_notify_drv_cap_cmd req = {0}; + struct ubase_cmd_buf in; + + set_bit(UBASE_CAP_SUP_ACTIVATE_B, (unsigned long *)req.cap_bits); + + __ubase_fill_inout_buf(&in, UBASE_OPC_NOTIFY_DRV_CAPS, false, + sizeof(req), &req); + + return __ubase_cmd_send_in(udev, &in); +} + static const struct ubase_init_function ubase_init_func_map[] = { { "init work queue", UBASE_SUP_ALL, 0, @@ -630,6 +638,10 @@ static const struct ubase_init_function ubase_init_func_map[] = { "init cmd queue", UBASE_SUP_ALL, 1, ubase_cmd_init, ubase_cmd_uninit }, + { + "notify drv capbilities", UBASE_SUP_ALL, 0, + ubase_notify_drv_capbilities, NULL + }, { "query dev res", UBASE_SUP_ALL, 0, ubase_query_dev_res, NULL diff --git a/drivers/ub/ubase/ubase_hw.c b/drivers/ub/ubase/ubase_hw.c index d728dd47f116..290a03a74b0e 100644 --- a/drivers/ub/ubase/ubase_hw.c +++ b/drivers/ub/ubase/ubase_hw.c @@ -156,13 +156,10 @@ static void ubase_parse_dev_caps_unic(struct ubase_dev *udev, struct ubase_adev_caps *unic_caps = &udev->caps.unic_caps; unic_caps->jfs.max_cnt = le32_to_cpu(resp->nic_jfs_max_cnt); - unic_caps->jfs.reserved_cnt = le32_to_cpu(resp->nic_jfs_reserved_cnt); unic_caps->jfs.depth = le32_to_cpu(resp->nic_jfs_depth); unic_caps->jfr.max_cnt = le32_to_cpu(resp->nic_jfr_max_cnt); - unic_caps->jfr.reserved_cnt = le32_to_cpu(resp->nic_jfr_reserved_cnt); unic_caps->jfr.depth = le32_to_cpu(resp->nic_jfr_depth); unic_caps->jfc.max_cnt = le32_to_cpu(resp->nic_jfc_max_cnt); - unic_caps->jfc.reserved_cnt = le32_to_cpu(resp->nic_jfc_reserved_cnt); unic_caps->jfc.depth = le32_to_cpu(resp->nic_jfc_depth); unic_caps->cqe_size = le16_to_cpu(resp->nic_cqe_size); unic_caps->utp_port_bitmap = le32_to_cpu(resp->port_bitmap); @@ -174,13 +171,10 @@ static void ubase_parse_dev_caps_udma(struct ubase_dev *udev, struct ubase_adev_caps *udma_caps = &udev->caps.udma_caps; udma_caps->jfs.max_cnt = le32_to_cpu(resp->udma_jfs_max_cnt); - udma_caps->jfs.reserved_cnt = le32_to_cpu(resp->udma_jfs_reserved_cnt); udma_caps->jfs.depth = le32_to_cpu(resp->udma_jfs_depth); udma_caps->jfr.max_cnt = le32_to_cpu(resp->udma_jfr_max_cnt); - udma_caps->jfr.reserved_cnt = le32_to_cpu(resp->udma_jfr_reserved_cnt); udma_caps->jfr.depth = le32_to_cpu(resp->udma_jfr_depth); udma_caps->jfc.max_cnt = le32_to_cpu(resp->udma_jfc_max_cnt); - udma_caps->jfc.reserved_cnt = le32_to_cpu(resp->udma_jfc_reserved_cnt); udma_caps->jfc.depth = le32_to_cpu(resp->udma_jfc_depth); udma_caps->cqe_size = le16_to_cpu(resp->udma_cqe_size); udma_caps->jtg_max_cnt = le32_to_cpu(resp->jtg_max_cnt); @@ -951,7 +945,7 @@ int __ubase_perf_stats(struct ubase_dev *udev, u64 port_bitmap, u32 period, struct ubase_perf_stats_result *data, u32 data_size) { #define UBASE_MS_TO_US(ms) (1000 * (ms)) - struct ubase_stop_perf_stats_cmd resp = {0}; + struct ubase_stop_perf_stats_cmd resp; unsigned long logic_port_bitmap; int ret, j, k, port_num; u8 i; @@ -988,6 +982,8 @@ int __ubase_perf_stats(struct ubase_dev *udev, u64 port_bitmap, u32 period, for (i = 0, k = 0; i < UBASE_MAX_PORT_NUM && k < port_num; i++) { if (!test_bit(i, (unsigned long *)&port_bitmap)) continue; + + memset(&resp, 0, sizeof(resp)); ret = ubase_stop_perf_stats(udev, &resp, period, i); if (ret) goto unlock; diff --git a/drivers/ub/ubase/ubase_hw.h b/drivers/ub/ubase/ubase_hw.h index ee455ba317d1..12bc101cd04f 100644 --- a/drivers/ub/ubase/ubase_hw.h +++ b/drivers/ub/ubase/ubase_hw.h @@ -30,7 +30,7 @@ struct ubase_caps_item { struct ubase_res_cmd_resp { __le32 cap_bits[UBASE_CAP_LEN]; - __le32 rsvd[3]; + __le32 rsvd0[3]; u8 rsvd1[2]; __le16 ceq_vector_num; @@ -43,37 +43,32 @@ struct ubase_res_cmd_resp { __le32 aeqe_depth; __le32 ceqe_depth; __le32 udma_jfs_max_cnt; - __le32 udma_jfs_reserved_cnt; + u8 rsvd2[4]; __le32 udma_jfs_depth; __le32 udma_jfr_max_cnt; - __le32 udma_jfr_reserved_cnt; + u8 rsvd3[4]; __le32 udma_jfr_depth; u8 nic_vl_num; - u8 rsvd2[3]; + u8 rsvd4[3]; u8 nic_vl[UBASE_MAX_REQ_VL_NUM]; __le32 udma_jfc_max_cnt; - __le32 udma_jfc_reserved_cnt; + u8 rsvd5[4]; __le32 udma_jfc_depth; - __le32 udma_tp_max_cnt; - __le32 udma_tp_reserved_cnt; - __le32 udma_tp_depth; - __le32 udma_tpg_max_cnt; - __le32 udma_tpg_reserved_cnt; - __le32 udma_tpg_depth; + u8 rsvd6[24]; __le32 nic_jfs_max_cnt; - __le32 nic_jfs_reserved_cnt; + u8 rsvd7[4]; __le32 nic_jfs_depth; __le32 nic_jfr_max_cnt; - __le32 nic_jfr_reserved_cnt; + u8 rsvd8[4]; __le32 nic_jfr_depth; - __le32 rsvd3[2]; + __le32 rsvd9[2]; - __le32 rsvd4; + __le32 rsvd10; __le32 nic_jfc_max_cnt; - __le32 nic_jfc_reserved_cnt; + u8 rsvd11[4]; __le32 nic_jfc_depth; __le32 nic_tp_max_cnt; __le32 nic_tp_reserved_cnt; @@ -83,10 +78,7 @@ struct ubase_res_cmd_resp { __le32 nic_tpg_reserved_cnt; __le32 nic_tpg_depth; __le32 total_ue_num; - __le32 jfs_ctx_size; - __le32 jfr_ctx_size; - __le32 jfc_ctx_size; - __le32 tp_ctx_size; + u8 rsvd12[16]; __le16 rsvd_jetty_cnt; __le16 mac_stats_num; @@ -95,24 +87,22 @@ struct ubase_res_cmd_resp { __le32 public_jetty_cnt; __le32 tp_extdb_buf_size; __le32 tp_timer_buf_size; - u8 port_work_mode; + u8 resv13; u8 udma_vl_num; u8 udma_tp_resp_vl_offset; u8 ue_num; __le32 port_bitmap; - u8 rsvd5[4]; + u8 rsvd14[4]; /* include udma tp and ctp req vl */ u8 udma_req_vl[UBASE_MAX_REQ_VL_NUM]; __le32 udma_rc_depth; - u8 rsvd6[4]; + u8 rsvd15[4]; __le32 jtg_max_cnt; __le32 rc_max_cnt_per_vl; - __le32 dest_addr_max_cnt; - __le32 seid_upi_max_cnt; + u8 rsvd16[8]; - __le32 tpm_max_cnt; - __le32 ccc_max_cnt; + u8 rsvd17[32]; }; struct ubase_query_oor_resp { diff --git a/drivers/ub/ubase/ubase_qos_hw.c b/drivers/ub/ubase/ubase_qos_hw.c index bfd5c4e0f5c1..8145edc4401c 100644 --- a/drivers/ub/ubase/ubase_qos_hw.c +++ b/drivers/ub/ubase/ubase_qos_hw.c @@ -195,13 +195,10 @@ static int __ubase_config_tm_vl_sch(struct ubase_dev *udev, u16 vl_bitmap, int ret; u8 i; - /* the configuration takes effect for all entities. */ - req.bus_ue_id = cpu_to_le16(USHRT_MAX); - req.vl_bitmap = cpu_to_le16(vl_bitmap); - for (i = 0; i < UBASE_MAX_VL_NUM; i++) tsa_bitmap |= vl_tsa[i] ? 1 << i : 0; + req.vl_bitmap = cpu_to_le16(vl_bitmap); req.vl_tsa = cpu_to_le16(tsa_bitmap); memcpy(req.vl_bw, vl_bw, UBASE_MAX_VL_NUM); @@ -209,7 +206,7 @@ static int __ubase_config_tm_vl_sch(struct ubase_dev *udev, u16 vl_bitmap, sizeof(req), &req); ret = __ubase_cmd_send_in(udev, &in); - if (ret) + if (ret && ret != -EPERM) ubase_err(udev, "failed to config tm vl sch, ret = %d", ret); return ret; @@ -230,7 +227,7 @@ static int __ubase_config_ets_vl_sch(struct ubase_dev *udev, u16 vl_bitmap, &req); ret = __ubase_cmd_send_in(udev, &in); - if (ret) + if (ret && ret != -EPERM) ubase_err(udev, "failed to cfg ets vl sch, ret = %d.", ret); return ret; diff --git a/include/ub/ubase/ubase_comm_cmd.h b/include/ub/ubase/ubase_comm_cmd.h index 4eb3c435a8f9..492b5e8513ea 100644 --- a/include/ub/ubase/ubase_comm_cmd.h +++ b/include/ub/ubase/ubase_comm_cmd.h @@ -30,6 +30,7 @@ enum ubase_opcode_type { /* Generic commands */ UBASE_OPC_QUERY_FW_VER = 0x0001, UBASE_OPC_QUERY_CTL_INFO = 0x0003, + UBASE_OPC_NOTIFY_DRV_CAPS = 0x0007, UBASE_OPC_QUERY_COMM_RSRC_PARAM = 0x0030, UBASE_OPC_QUERY_NIC_RSRC_PARAM = 0x0031, UBASE_OPC_QUERY_LINK_STATUS = 0x0032, diff --git a/include/ub/ubase/ubase_comm_dev.h b/include/ub/ubase/ubase_comm_dev.h index ac85c20311dd..35e0496ac01d 100644 --- a/include/ub/ubase/ubase_comm_dev.h +++ b/include/ub/ubase/ubase_comm_dev.h @@ -103,7 +103,6 @@ struct ubase_caps { struct ubase_res_caps { u32 max_cnt; u32 start_idx; - u32 reserved_cnt; u32 depth; }; @@ -123,10 +122,6 @@ struct ubase_adev_caps { u32 jtg_max_cnt; u32 rc_max_cnt; u32 rc_que_depth; - u32 ccc_max_cnt; - u32 dest_addr_max_cnt; - u32 seid_upi_max_cnt; - u32 tpm_max_cnt; u16 cqe_size; }; -- Gitee From 0bc1563f7bc09440cff67f6b1e5cf5b138868793 Mon Sep 17 00:00:00 2001 From: Xiongchuan Zhou Date: Mon, 10 Nov 2025 20:33:36 +0800 Subject: [PATCH 095/103] net: unic: Fix the ethtool stats and basic capability information query interface commit 15bde327170a99bf1cc5e4869d70872c53b69ba6 openEuler The ethtool tool supports querying stats information for the ub network port. Resolving issues with stats information collection and failure to query FEC and speed-related configurations. Fixes: 4420dfeed31d ("net: unic: Support to query and clear historical NIC link status information") Signed-off-by: Xiongchuan Zhou Signed-off-by: Fengyan Mu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/net/ub/unic/unic_ethtool.c | 50 ++++++++++ drivers/net/ub/unic/unic_stats.c | 142 +++++++++++++++++++++++++++++ drivers/net/ub/unic/unic_stats.h | 21 +++++ 3 files changed, 213 insertions(+) diff --git a/drivers/net/ub/unic/unic_ethtool.c b/drivers/net/ub/unic/unic_ethtool.c index 22f530c45107..960477451df5 100644 --- a/drivers/net/ub/unic/unic_ethtool.c +++ b/drivers/net/ub/unic/unic_ethtool.c @@ -24,6 +24,46 @@ static u32 unic_get_link_status(struct net_device *netdev) return unic_dev->sw_link_status; } +static void unic_get_port_type(struct unic_dev *unic_dev, + struct ethtool_link_ksettings *cmd) +{ + u8 module_type = unic_dev->hw.mac.module_type; + u8 media_type = unic_dev->hw.mac.media_type; + + switch (media_type) { + case UNIC_MEDIA_TYPE_NONE: + case UNIC_MEDIA_TYPE_BACKPLANE: + cmd->base.port = PORT_NONE; + break; + case UNIC_MEDIA_TYPE_FIBER: + if (module_type == UNIC_MODULE_TYPE_CR) + cmd->base.port = PORT_DA; + else + cmd->base.port = PORT_FIBRE; + break; + default: + cmd->base.port = PORT_NONE; + break; + } +} + +static void unic_get_ksettings(struct unic_dev *unic_dev, + struct ethtool_link_ksettings *cmd) +{ + struct unic_mac *mac = &unic_dev->hw.mac; + + unic_get_port_type(unic_dev, cmd); + + cmd->base.speed = mac->speed; + cmd->base.duplex = mac->duplex; + cmd->base.autoneg = mac->autoneg; + + linkmode_copy(cmd->link_modes.supported, mac->supported); + linkmode_copy(cmd->link_modes.advertising, mac->advertising); + + cmd->lanes = mac->lanes; +} + static int unic_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { @@ -32,6 +72,13 @@ static int unic_get_link_ksettings(struct net_device *netdev, /* Ensure that the latest information is obtained. */ unic_update_port_info(unic_dev); + unic_get_ksettings(unic_dev, cmd); + + if (!unic_get_link_status(netdev)) { + cmd->base.speed = SPEED_UNKNOWN; + cmd->base.duplex = DUPLEX_UNKNOWN; + } + return 0; } @@ -326,6 +373,9 @@ static const struct ethtool_ops unic_ethtool_ops = { .get_drvinfo = unic_get_driver_info, .get_regs_len = unic_get_regs_len, .get_regs = unic_get_regs, + .get_ethtool_stats = unic_get_stats, + .get_strings = unic_get_stats_strings, + .get_sset_count = unic_get_sset_count, .get_channels = unic_get_channels, .set_channels = unic_set_channels, .get_ringparam = unic_get_channels_param, diff --git a/drivers/net/ub/unic/unic_stats.c b/drivers/net/ub/unic/unic_stats.c index d8ccd1876500..4647ba5e3e5e 100644 --- a/drivers/net/ub/unic/unic_stats.c +++ b/drivers/net/ub/unic/unic_stats.c @@ -78,6 +78,36 @@ static struct unic_dfx_regs_group unic_dfx_reg_arr[] = { }, }; +static const struct unic_stats_desc unic_sq_stats_str[] = { + {"pad_err", UNIC_SQ_STATS_FIELD_OFF(pad_err)}, + {"packets", UNIC_SQ_STATS_FIELD_OFF(packets)}, + {"bytes", UNIC_SQ_STATS_FIELD_OFF(bytes)}, + {"busy", UNIC_SQ_STATS_FIELD_OFF(busy)}, + {"more", UNIC_SQ_STATS_FIELD_OFF(more)}, + {"restart_queue", UNIC_SQ_STATS_FIELD_OFF(restart_queue)}, + {"over_max_sge_num", UNIC_SQ_STATS_FIELD_OFF(over_max_sge_num)}, + {"csum_err", UNIC_SQ_STATS_FIELD_OFF(csum_err)}, + {"ci_mismatch", UNIC_SQ_STATS_FIELD_OFF(ci_mismatch)}, + {"vlan_err", UNIC_SQ_STATS_FIELD_OFF(vlan_err)}, + {"fd_cnt", UNIC_SQ_STATS_FIELD_OFF(fd_cnt)}, + {"drop_cnt", UNIC_SQ_STATS_FIELD_OFF(drop_cnt)}, + {"cfg5_drop_cnt", UNIC_SQ_STATS_FIELD_OFF(cfg5_drop_cnt)} +}; + +static const struct unic_stats_desc unic_rq_stats_str[] = { + {"alloc_skb_err", UNIC_RQ_STATS_FIELD_OFF(alloc_skb_err)}, + {"packets", UNIC_RQ_STATS_FIELD_OFF(packets)}, + {"bytes", UNIC_RQ_STATS_FIELD_OFF(bytes)}, + {"err_pkt_len_cnt", UNIC_RQ_STATS_FIELD_OFF(err_pkt_len_cnt)}, + {"doi_cnt", UNIC_RQ_STATS_FIELD_OFF(doi_cnt)}, + {"trunc_cnt", UNIC_RQ_STATS_FIELD_OFF(trunc_cnt)}, + {"multicast", UNIC_RQ_STATS_FIELD_OFF(multicast)}, + {"l2_err", UNIC_RQ_STATS_FIELD_OFF(l2_err)}, + {"l3_l4_csum_err", UNIC_RQ_STATS_FIELD_OFF(l3_l4_csum_err)}, + {"alloc_frag_err", UNIC_RQ_STATS_FIELD_OFF(alloc_frag_err)}, + {"csum_complete", UNIC_RQ_STATS_FIELD_OFF(csum_complete)}, +}; + static int unic_get_dfx_reg_num(struct unic_dev *unic_dev, u32 *reg_num, u32 reg_arr_size) { @@ -295,6 +325,118 @@ void unic_get_regs(struct net_device *netdev, struct ethtool_regs *cmd, kfree(reg_num); } +static u64 *unic_get_queues_stats(struct unic_dev *unic_dev, + const struct unic_stats_desc *stats, + u32 stats_size, enum unic_queue_type type, + u64 *data) +{ + struct unic_channel *c; + u32 i, j; + u8 *q; + + for (i = 0; i < unic_dev->channels.num; i++) { + c = &unic_dev->channels.c[i]; + q = (type == UNIC_QUEUE_TYPE_SQ) ? (u8 *)c->sq : (u8 *)c->rq; + for (j = 0; j < stats_size; j++) { + *data = UNIC_STATS_READ(q, stats[j].offset); + data++; + } + } + + return data; +} + +void unic_get_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + u64 *p = data; + + if (unic_resetting(netdev) || !unic_dev->channels.c) { + unic_err(unic_dev, + "dev resetting or channel is null, could not get stats.\n"); + return; + } + + p = unic_get_queues_stats(unic_dev, unic_sq_stats_str, + ARRAY_SIZE(unic_sq_stats_str), + UNIC_QUEUE_TYPE_SQ, p); + + p = unic_get_queues_stats(unic_dev, unic_rq_stats_str, + ARRAY_SIZE(unic_rq_stats_str), + UNIC_QUEUE_TYPE_RQ, p); +} + +static u8 *unic_get_strings(u8 *data, const char *prefix, u32 num, + const struct unic_stats_desc *strs, u32 stats_size) +{ + u32 i, j; + + for (i = 0; i < num; i++) { + for (j = 0; j < stats_size; j++) { + data[ETH_GSTRING_LEN - 1] = '\0'; + + if (prefix) + scnprintf(data, ETH_GSTRING_LEN - 1, "%s%u_%s", + prefix, i, strs[j].desc); + else + scnprintf(data, ETH_GSTRING_LEN - 1, "%s", + strs[j].desc); + + data += ETH_GSTRING_LEN; + } + } + + return data; +} + +static u8 *unic_get_queues_strings(struct unic_dev *unic_dev, u8 *data) +{ + u32 channel_num = unic_dev->channels.num; + + /* get desc for Tx */ + data = unic_get_strings(data, "txq", channel_num, unic_sq_stats_str, + ARRAY_SIZE(unic_sq_stats_str)); + + /* get desc for Rx */ + data = unic_get_strings(data, "rxq", channel_num, unic_rq_stats_str, + ARRAY_SIZE(unic_rq_stats_str)); + + return data; +} + +void unic_get_stats_strings(struct net_device *netdev, u32 stringset, u8 *data) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + u8 *p = data; + + switch (stringset) { + case ETH_SS_STATS: + p = unic_get_queues_strings(unic_dev, p); + break; + default: + break; + } +} + +int unic_get_sset_count(struct net_device *netdev, int stringset) +{ + struct unic_dev *unic_dev = netdev_priv(netdev); + u32 channel_num = unic_dev->channels.num; + int count; + + switch (stringset) { + case ETH_SS_STATS: + count = ARRAY_SIZE(unic_sq_stats_str) * channel_num; + count += ARRAY_SIZE(unic_rq_stats_str) * channel_num; + break; + default: + return -EOPNOTSUPP; + } + + return count; +} + static void unic_get_fec_stats_total(struct unic_dev *unic_dev, u8 stats_flags, struct ethtool_fec_stats *fec_stats) { diff --git a/drivers/net/ub/unic/unic_stats.h b/drivers/net/ub/unic/unic_stats.h index 2a2a8746d838..623b732f3d8e 100644 --- a/drivers/net/ub/unic/unic_stats.h +++ b/drivers/net/ub/unic/unic_stats.h @@ -12,6 +12,13 @@ #include #include +#define UNIC_SQ_STATS_FIELD_OFF(fld) (offsetof(struct unic_sq, stats) + \ + offsetof(struct unic_sq_stats, fld)) +#define UNIC_RQ_STATS_FIELD_OFF(fld) (offsetof(struct unic_rq, stats) + \ + offsetof(struct unic_rq_stats, fld)) + +#define UNIC_STATS_READ(p, offset) (*(u64 *)((u8 *)(p) + (offset))) + #define UNIC_FEC_CORR_BLOCKS BIT(0) #define UNIC_FEC_UNCORR_BLOCKS BIT(1) #define UNIC_FEC_CORR_BITS BIT(2) @@ -58,6 +65,11 @@ enum unic_reg_tag { UNIC_TAG_MAX, }; +enum unic_queue_type { + UNIC_QUEUE_TYPE_SQ = 0, + UNIC_QUEUE_TYPE_RQ, +}; + struct unic_res_regs_group { u16 tag; u32 *regs_addr; @@ -83,9 +95,18 @@ struct unic_dfx_regs_group { bool (*is_supported)(struct unic_dev *unic_dev, u32 property); }; +struct unic_stats_desc { + char desc[ETH_GSTRING_LEN]; + u16 offset; +}; + int unic_get_regs_len(struct net_device *netdev); void unic_get_regs(struct net_device *netdev, struct ethtool_regs *cmd, void *data); +void unic_get_stats_strings(struct net_device *netdev, u32 stringset, u8 *data); +int unic_get_sset_count(struct net_device *netdev, int stringset); +void unic_get_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data); void unic_get_fec_stats(struct net_device *ndev, struct ethtool_fec_stats *fec_stats); -- Gitee From a07236c507f6b6f8cc6108c9cff048db6a598b67 Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Wed, 12 Nov 2025 18:21:17 +0800 Subject: [PATCH 096/103] ub: ubase: Fix verification to ctrlq message seq commit e87c0f1d745bd8cea6ec52d5b79c163ba12d4a1d openEuler The data sent by the UE to the UE will be accessed through seq, but the value of seq may not be trustworthy. Accessing untrusted seq data can cause anomalies. a new check for seq values has been added. Fixes: d7ce08663cc5 ("ub: ubase: Supports for ctrl queue management.") Signed-off-by: Yixi Shen Signed-off-by: Fengyan Mu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/ubase/ubase_ctrlq.c | 13 +++++++++---- drivers/ub/ubase/ubase_ctrlq.h | 1 + drivers/ub/ubase/ubase_dev.c | 5 +++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/ub/ubase/ubase_ctrlq.c b/drivers/ub/ubase/ubase_ctrlq.c index b8d7681dd518..c49f713226c5 100644 --- a/drivers/ub/ubase/ubase_ctrlq.c +++ b/drivers/ub/ubase/ubase_ctrlq.c @@ -569,6 +569,11 @@ static int ubase_ctrlq_msg_check(struct ubase_dev *udev, return -EINVAL; } + if (msg->is_resp && msg->need_resp) { + ubase_err(udev, "ctrlq input resp type is invalid.\n"); + return -EINVAL; + } + if (msg->is_resp && !(msg->resp_seq & UBASE_CTRLQ_SEQ_MASK)) { ubase_err(udev, "ctrlq input resp_seq(%u) is invalid.\n", msg->resp_seq); @@ -759,13 +764,13 @@ static void ubase_ctrlq_send_unsupported_resp(struct ubase_dev *udev, msg.resp_seq = seq; msg.resp_ret = EOPNOTSUPP; - ubase_info(udev, "ctrlq received unsupported req. seq=%u, ser_type=%d, ser_ver=%d, opc=%u.", + ubase_info(udev, "ctrlq received unsupported req. seq=%u, ser_type=%d, ser_ver=%d, opc=0x%x.", seq, head->service_type, head->service_ver, head->opcode); ret = __ubase_ctrlq_send(udev, &msg, NULL); if (ret) - ubase_warn(udev, "failed to send ctrlq unsupported resp. seq=%u, ser_type=%d, ser_ver=%d, opc=%u.", - seq, head->service_type, head->service_ver, head->opcode); + ubase_warn(udev, "failed to send ctrlq unsupported resp. seq=%u, ser_type=%d, ser_ver=%d, opc=0x%x, ret=%d.", + seq, head->service_type, head->service_ver, head->opcode, ret); } static void ubase_ctrlq_crq_event_callback(struct ubase_dev *udev, @@ -809,7 +814,7 @@ static void ubase_ctrlq_notify_completed(struct ubase_dev *udev, complete(&ctx->done); } -static bool ubase_ctrlq_check_seq(struct ubase_dev *udev, u16 seq) +bool ubase_ctrlq_check_seq(struct ubase_dev *udev, u16 seq) { bool is_pushed = !!(seq & UBASE_CTRLQ_SEQ_MASK); u16 max_seq = ubase_ctrlq_max_seq(udev); diff --git a/drivers/ub/ubase/ubase_ctrlq.h b/drivers/ub/ubase/ubase_ctrlq.h index 431253df5054..b868ace06ab1 100644 --- a/drivers/ub/ubase/ubase_ctrlq.h +++ b/drivers/ub/ubase/ubase_ctrlq.h @@ -94,6 +94,7 @@ void ubase_ctrlq_disable(struct ubase_dev *udev); int __ubase_ctrlq_send(struct ubase_dev *udev, struct ubase_ctrlq_msg *msg, struct ubase_ctrlq_ue_info *ue_info); +bool ubase_ctrlq_check_seq(struct ubase_dev *udev, u16 seq); void ubase_ctrlq_service_task(struct ubase_delay_work *ubase_work); void ubase_ctrlq_handle_crq_msg(struct ubase_dev *udev, struct ubase_ctrlq_base_block *head, diff --git a/drivers/ub/ubase/ubase_dev.c b/drivers/ub/ubase/ubase_dev.c index fa61159d4295..76d179093abe 100644 --- a/drivers/ub/ubase/ubase_dev.c +++ b/drivers/ub/ubase/ubase_dev.c @@ -492,6 +492,11 @@ static int ubase_handle_ue2ue_ctrlq_event(struct ubase_dev *udev, void *data, if (ubase_dev_ctrlq_supported(udev)) return ubase_handle_ue2ue_ctrlq_req(udev, cmd, len); + if (!ubase_ctrlq_check_seq(udev, cmd->seq)) { + ubase_err(udev, "invalid ue2ue ctrlq seq(%u).\n", cmd->seq); + return -EINVAL; + } + head = (struct ubase_ctrlq_base_block *)(cmd + 1); data_len = len - sizeof(*cmd) - UBASE_CTRLQ_HDR_LEN; ubase_ctrlq_handle_crq_msg(udev, head, cmd->seq, -- Gitee From 18ce4ddc14d2ee2e749b486ffe83c21faf88d7e9 Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Wed, 12 Nov 2025 18:37:23 +0800 Subject: [PATCH 097/103] ub: ubase: Optimization of ubase_ctrlq_send_msg interface parameters commit 0ee149f4767688691a85b306b128d9d84f4232ec openEuler This patch optimizes the parameters of the ubase_ctrlq_send_msg interface by adding the is_async parameter to specify whether to call it synchronously. Fixes: d7ce08663cc5 ("ub: ubase: Supports for ctrl queue management.") Signed-off-by: Guangwei Zhang Signed-off-by: Fengyan Mu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/ubase/ubase_cmd.h | 3 +- drivers/ub/ubase/ubase_ctrlq.c | 96 +++++++++++++++++++---------- drivers/ub/ubase/ubase_ctrlq.h | 20 ++++++ drivers/ub/ubase/ubase_dev.c | 3 + include/ub/ubase/ubase_comm_ctrlq.h | 3 +- 5 files changed, 91 insertions(+), 34 deletions(-) diff --git a/drivers/ub/ubase/ubase_cmd.h b/drivers/ub/ubase/ubase_cmd.h index 263e88c9fa49..a99422b59dc4 100644 --- a/drivers/ub/ubase/ubase_cmd.h +++ b/drivers/ub/ubase/ubase_cmd.h @@ -83,7 +83,8 @@ struct ubase_ue2ue_ctrlq_head { u16 out_size; u8 need_resp : 1; u8 is_resp : 1; - u8 rsv : 6; + u8 is_async : 1; + u8 rsv : 5; }; struct ubase_start_perf_stats_cmd { diff --git a/drivers/ub/ubase/ubase_ctrlq.c b/drivers/ub/ubase/ubase_ctrlq.c index c49f713226c5..352342ee01dc 100644 --- a/drivers/ub/ubase/ubase_ctrlq.c +++ b/drivers/ub/ubase/ubase_ctrlq.c @@ -369,11 +369,13 @@ static void ubase_ctrlq_fill_first_bb(struct ubase_dev *udev, head->service_type = msg->service_type; head->opcode = msg->opcode; head->mbx_ue_id = ue_info ? ue_info->mbx_ue_id : 0; - head->ret = msg->is_resp ? msg->resp_ret : 0; + head->ret = ubase_ctrlq_msg_is_resp(msg) ? msg->resp_ret : 0; head->bus_ue_id = cpu_to_le16(ue_info ? ue_info->bus_ue_id : ue->entity_idx); - memcpy(head->data, msg->in, min(msg->in_size, UBASE_CTRLQ_DATA_LEN)); + if (msg->in) + memcpy(head->data, msg->in, + min(msg->in_size, UBASE_CTRLQ_DATA_LEN)); } static inline void ubase_ctrlq_csq_report_irq(struct ubase_dev *udev) @@ -408,10 +410,12 @@ static int ubase_ctrlq_send_to_cmdq(struct ubase_dev *udev, ue2ue_head.out_size = msg->out_size; ue2ue_head.need_resp = msg->need_resp; ue2ue_head.is_resp = msg->is_resp; + ue2ue_head.is_async = msg->is_async; memcpy(req, &ue2ue_head, sizeof(ue2ue_head)); memcpy((u8 *)req + sizeof(ue2ue_head), head, UBASE_CTRLQ_HDR_LEN); - memcpy((u8 *)req + sizeof(ue2ue_head) + UBASE_CTRLQ_HDR_LEN, msg->in, - msg->in_size); + if (msg->in) + memcpy((u8 *)req + sizeof(ue2ue_head) + UBASE_CTRLQ_HDR_LEN, + msg->in, msg->in_size); __ubase_fill_inout_buf(&in, UBASE_OPC_UE2UE_UBASE, false, req_len, req); ret = __ubase_cmd_send_in(udev, &in); @@ -541,18 +545,17 @@ static void ubase_ctrlq_addto_msg_queue(struct ubase_dev *udev, u16 seq, { struct ubase_ctrlq_msg_ctx *ctx; - if (!msg->need_resp) + if (!(ubase_ctrlq_msg_is_sync_req(msg) || + ubase_ctrlq_msg_is_async_req(msg))) return; ctx = &udev->ctrlq.msg_queue[seq]; ctx->valid = 1; - ctx->is_sync = msg->need_resp && msg->out && msg->out_size ? 1 : 0; + ctx->is_sync = ubase_ctrlq_msg_is_sync_req(msg) ? 1 : 0; ctx->result = ETIME; ctx->dead_jiffies = jiffies + msecs_to_jiffies(UBASE_CTRLQ_DEAD_TIME); - if (ctx->is_sync) { - ctx->out = msg->out; - ctx->out_size = msg->out_size; - } + ctx->out = msg->out; + ctx->out_size = msg->out_size; if (ue_info) { ctx->ue_seq = ue_info->seq; @@ -564,30 +567,58 @@ static void ubase_ctrlq_addto_msg_queue(struct ubase_dev *udev, u16 seq, static int ubase_ctrlq_msg_check(struct ubase_dev *udev, struct ubase_ctrlq_msg *msg) { - if (!msg || !msg->in || !msg->in_size) { - ubase_err(udev, "ctrlq input buf is invalid.\n"); - return -EINVAL; - } - - if (msg->is_resp && msg->need_resp) { - ubase_err(udev, "ctrlq input resp type is invalid.\n"); + if ((!msg->in && msg->in_size) || (msg->in && !msg->in_size)) { + ubase_err(udev, "ctrlq msg in param error.\n"); return -EINVAL; } - if (msg->is_resp && !(msg->resp_seq & UBASE_CTRLQ_SEQ_MASK)) { - ubase_err(udev, "ctrlq input resp_seq(%u) is invalid.\n", - msg->resp_seq); + if ((!msg->out && msg->out_size) || (msg->out && !msg->out_size)) { + ubase_err(udev, "ctrlq msg out param error.\n"); return -EINVAL; } if (msg->in_size > UBASE_CTRLQ_MAX_DATA_SIZE) { ubase_err(udev, - "requested ctrlq space(%u) exceeds the maximum(%u).\n", + "ctrlq msg in_size(%u) exceeds the maximum(%u).\n", msg->in_size, UBASE_CTRLQ_MAX_DATA_SIZE); return -EINVAL; } - return 0; + if (ubase_ctrlq_msg_is_sync_req(msg)) + return 0; + + if (ubase_ctrlq_msg_is_async_req(msg)) { + if (msg->out) { + ubase_err(udev, "ctrlq msg out is not NULL in async req.\n"); + return -EINVAL; + } + return 0; + } + + if (ubase_ctrlq_msg_is_notify_req(msg)) { + if (msg->out) { + ubase_err(udev, "ctrlq msg out is not NULL in notify req.\n"); + return -EINVAL; + } + return 0; + } + + if (ubase_ctrlq_msg_is_resp(msg)) { + if (msg->out) { + ubase_err(udev, "ctrlq msg out is not NULL in resp.\n"); + return -EINVAL; + } + if (!(msg->resp_seq & UBASE_CTRLQ_SEQ_MASK)) { + ubase_err(udev, "ctrlq msg resp_seq error, resp_seq=%u.\n", + msg->resp_seq); + return -EINVAL; + } + return 0; + } + + ubase_err(udev, "ctrlq msg param error, is_resp=%u, is_async=%u, need_resp=%u.\n", + msg->is_resp, msg->is_async, msg->need_resp); + return -EINVAL; } static int ubase_ctrlq_check_csq_enough(struct ubase_dev *udev, u16 num) @@ -612,8 +643,6 @@ static int ubase_ctrlq_send_real(struct ubase_dev *udev, struct ubase_ctrlq_msg *msg, struct ubase_ctrlq_ue_info *ue_info) { - bool sync_req = msg->out && msg->out_size && msg->need_resp; - bool no_resp = !msg->is_resp && !msg->need_resp; struct ubase_ctrlq_ring *csq = &udev->ctrlq.csq; struct ubase_ctrlq_base_block head = {0}; u16 seq, num; @@ -627,7 +656,7 @@ static int ubase_ctrlq_send_real(struct ubase_dev *udev, if (ret) goto unlock; - if (!msg->is_resp) { + if (!ubase_ctrlq_msg_is_resp(msg)) { ret = ubase_ctrlq_alloc_seq(udev, msg, &seq); if (ret) { ubase_warn(udev, "no enough seq in ctrlq.\n"); @@ -645,20 +674,22 @@ static int ubase_ctrlq_send_real(struct ubase_dev *udev, ret = ubase_ctrlq_send_msg_to_sq(udev, &head, msg, num); if (ret) { spin_unlock_bh(&csq->lock); - goto free_seq; + if (!ubase_ctrlq_msg_is_resp(msg)) + ubase_ctrlq_free_seq(udev, seq); + return ret; } spin_unlock_bh(&csq->lock); - if (sync_req) + if (ubase_ctrlq_msg_is_sync_req(msg)) ret = ubase_ctrlq_wait_completed(udev, seq, msg); -free_seq: - /* Only the seqs in synchronous requests and no response requests need to be released. */ - /* The seqs are released in periodic tasks of asynchronous requests. */ - if (sync_req || no_resp) + if (ubase_ctrlq_msg_is_sync_req(msg) || + ubase_ctrlq_msg_is_notify_req(msg)) ubase_ctrlq_free_seq(udev, seq); + return ret; + unlock: spin_unlock_bh(&csq->lock); return ret; @@ -809,7 +840,8 @@ static void ubase_ctrlq_notify_completed(struct ubase_dev *udev, ctx = &udev->ctrlq.msg_queue[seq]; ctx->result = head->ret; - memcpy(ctx->out, msg, min(msg_len, ctx->out_size)); + if (ctx->out) + memcpy(ctx->out, msg, min(msg_len, ctx->out_size)); complete(&ctx->done); } diff --git a/drivers/ub/ubase/ubase_ctrlq.h b/drivers/ub/ubase/ubase_ctrlq.h index b868ace06ab1..c3d5f55db87d 100644 --- a/drivers/ub/ubase/ubase_ctrlq.h +++ b/drivers/ub/ubase/ubase_ctrlq.h @@ -87,6 +87,26 @@ struct ubase_ctrlq_reset_ctrl_req { u8 rsv[3]; }; +static inline bool ubase_ctrlq_msg_is_sync_req(struct ubase_ctrlq_msg *msg) +{ + return !msg->is_resp && !msg->is_async && msg->need_resp; +} + +static inline bool ubase_ctrlq_msg_is_async_req(struct ubase_ctrlq_msg *msg) +{ + return !msg->is_resp && msg->is_async && msg->need_resp; +} + +static inline bool ubase_ctrlq_msg_is_notify_req(struct ubase_ctrlq_msg *msg) +{ + return !msg->is_resp && !msg->is_async && !msg->need_resp; +} + +static inline bool ubase_ctrlq_msg_is_resp(struct ubase_ctrlq_msg *msg) +{ + return msg->is_resp && !msg->is_async && !msg->need_resp; +} + int ubase_ctrlq_init(struct ubase_dev *udev); void ubase_ctrlq_uninit(struct ubase_dev *udev); void ubase_ctrlq_disable(struct ubase_dev *udev); diff --git a/drivers/ub/ubase/ubase_dev.c b/drivers/ub/ubase/ubase_dev.c index 76d179093abe..7331afa03c80 100644 --- a/drivers/ub/ubase/ubase_dev.c +++ b/drivers/ub/ubase/ubase_dev.c @@ -459,11 +459,14 @@ static int ubase_handle_ue2ue_ctrlq_req(struct ubase_dev *udev, msg.opcode = head->opcode; msg.need_resp = cmd->need_resp; msg.is_resp = cmd->is_resp; + msg.is_async = cmd->is_async; msg.resp_seq = cmd->seq; msg.in = (u8 *)head + UBASE_CTRLQ_HDR_LEN; msg.in_size = cmd->in_size; msg.out = NULL; msg.out_size = 0; + if (ubase_ctrlq_msg_is_sync_req(&msg)) + msg.is_async = 1; ue_info.bus_ue_id = le16_to_cpu(cmd->head.bus_ue_id); ue_info.seq = cmd->seq; diff --git a/include/ub/ubase/ubase_comm_ctrlq.h b/include/ub/ubase/ubase_comm_ctrlq.h index 7e772dcb0746..da3337573b61 100644 --- a/include/ub/ubase/ubase_comm_ctrlq.h +++ b/include/ub/ubase/ubase_comm_ctrlq.h @@ -61,7 +61,8 @@ struct ubase_ctrlq_msg { u8 opcode; u8 need_resp : 1; u8 is_resp : 1; - u8 resv : 6; + u8 is_async : 1; + u8 resv : 5; u8 resp_ret; /* must set when the is_resp field is true. */ u16 resp_seq; /* must set when the is_resp field is true. */ u16 in_size; -- Gitee From 5bd8ee69879ea99dc0b0c91b770f1ed35198576b Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Thu, 20 Nov 2025 11:03:26 +0800 Subject: [PATCH 098/103] ub: ubase: Fix CTRLQ white list commit aca32b8e11f4d793529e2d06a7453d9dcbcf2f43 openEuler According to the design requirements for CtrlQ interface compatibility, when the Ubase receives a message that it does not support, it needs to return a notsupport response to the peer. Currently, Ubase determines whether a message is supported by checking whether the corresponding callback function has been registered. This leads to an edge case: when the auxiliary drivers has not registered, the corresponding callback function is null, and in this case, Ubase also returns notsupport. This causes the peer to mistakenly believe that we does not support the message, and subsequently, the peer will no longer send this message, which is not in line with the design expectations. Therefore, it is necessary for Ubase to distinguish between the two scenarios: when a message is supported but the callback is not registered, and when a message is not supported at all. So we add a message whitelist in Ubase. Messages not included in the whitelist will return notsupport while those included will return a specific error code 255 indicating "DRV NOT EXIST." Fixes: d7ce08663cc5 ("ub: ubase: Supports for ctrl queue management.") Signed-off-by: Chuan Wu Signed-off-by: Fengyan Mu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/ubase/ubase_ctrlq.c | 202 ++++++++++++++++++++-------- drivers/ub/ubase/ubase_dev.h | 8 +- include/ub/ubase/ubase_comm_ctrlq.h | 23 ++-- 3 files changed, 160 insertions(+), 73 deletions(-) diff --git a/drivers/ub/ubase/ubase_ctrlq.c b/drivers/ub/ubase/ubase_ctrlq.c index 352342ee01dc..9351ed2c70fd 100644 --- a/drivers/ub/ubase/ubase_ctrlq.c +++ b/drivers/ub/ubase/ubase_ctrlq.c @@ -11,19 +11,102 @@ #include "ubase_cmd.h" #include "ubase_ctrlq.h" -static inline void ubase_ctrlq_crq_table_init(struct ubase_dev *udev) +/* UNIC ctrlq msg white list */ +static const struct ubase_ctrlq_event_nb ubase_ctrlq_wlist_unic[] = { + {UBASE_CTRLQ_SER_TYPE_IP_ACL, UBASE_CTRLQ_OPC_NOTIFY_IP, NULL, NULL}, +}; + +/* UDMA ctrlq msg white list */ +static const struct ubase_ctrlq_event_nb ubase_ctrlq_wlist_udma[] = { + {UBASE_CTRLQ_SER_TYPE_TP_ACL, UBASE_CTRLQ_OPC_CHECK_TP_ACTIVE, NULL, NULL}, + {UBASE_CTRLQ_SER_TYPE_DEV_REGISTER, UBASE_CTRLQ_OPC_UPDATE_SEID, NULL, NULL}, + {UBASE_CTRLQ_SER_TYPE_DEV_REGISTER, UBASE_CTRLQ_OPC_NOTIFY_RES_RATIO, NULL, NULL}, +}; + +/* CDMA ctrlq msg white list */ +static const struct ubase_ctrlq_event_nb ubase_ctrlq_wlist_cdma[] = { + {UBASE_CTRLQ_SER_TYPE_DEV_REGISTER, UBASE_CTRLQ_OPC_UPDATE_SEID, NULL, NULL}, +}; + +static int ubase_ctrlq_alloc_crq_tbl_mem(struct ubase_dev *udev) { struct ubase_ctrlq_crq_table *crq_tab = &udev->ctrlq.crq_table; + u16 cnt = 0; + + if (ubase_dev_cdma_supported(udev)) { + cnt = ARRAY_SIZE(ubase_ctrlq_wlist_cdma); + } else if (ubase_dev_urma_supported(udev)) { + if (ubase_dev_unic_supported(udev)) + cnt += ARRAY_SIZE(ubase_ctrlq_wlist_unic); + if (ubase_dev_udma_supported(udev)) + cnt += ARRAY_SIZE(ubase_ctrlq_wlist_udma); + } + + if (!cnt) + return -EINVAL; + + crq_tab->crq_nbs = kcalloc(cnt, sizeof(struct ubase_ctrlq_event_nb), GFP_KERNEL); + if (!crq_tab->crq_nbs) + return -ENOMEM; + + crq_tab->crq_nb_cnt = cnt; + + return 0; +} + +static void ubase_ctrlq_free_crq_tbl_mem(struct ubase_dev *udev) +{ + struct ubase_ctrlq_crq_table *crq_tab = &udev->ctrlq.crq_table; + + kfree(crq_tab->crq_nbs); + crq_tab->crq_nbs = NULL; + crq_tab->crq_nb_cnt = 0; +} + +static void ubase_ctrlq_init_crq_wlist(struct ubase_dev *udev) +{ + struct ubase_ctrlq_crq_table *crq_tab = &udev->ctrlq.crq_table; + u32 offset = 0; + + if (ubase_dev_cdma_supported(udev)) { + memcpy(crq_tab->crq_nbs, ubase_ctrlq_wlist_cdma, + sizeof(ubase_ctrlq_wlist_cdma)); + } else if (ubase_dev_urma_supported(udev)) { + if (ubase_dev_unic_supported(udev)) { + memcpy(crq_tab->crq_nbs, ubase_ctrlq_wlist_unic, + sizeof(ubase_ctrlq_wlist_unic)); + offset = ARRAY_SIZE(ubase_ctrlq_wlist_unic); + } + if (ubase_dev_udma_supported(udev)) { + memcpy(&crq_tab->crq_nbs[offset], ubase_ctrlq_wlist_udma, + sizeof(ubase_ctrlq_wlist_udma)); + } + } +} + +static int ubase_ctrlq_crq_table_init(struct ubase_dev *udev) +{ + struct ubase_ctrlq_crq_table *crq_tab = &udev->ctrlq.crq_table; + int ret; + + ret = ubase_ctrlq_alloc_crq_tbl_mem(udev); + if (ret) + return ret; + + ubase_ctrlq_init_crq_wlist(udev); mutex_init(&crq_tab->lock); - INIT_LIST_HEAD(&crq_tab->crq_nbs.list); + + return 0; } -static inline void ubase_ctrlq_crq_table_uninit(struct ubase_dev *udev) +static void ubase_ctrlq_crq_table_uninit(struct ubase_dev *udev) { struct ubase_ctrlq_crq_table *crq_tab = &udev->ctrlq.crq_table; mutex_destroy(&crq_tab->lock); + + ubase_ctrlq_free_crq_tbl_mem(udev); } static inline u16 ubase_ctrlq_msg_queue_depth(struct ubase_dev *udev) @@ -233,10 +316,15 @@ int ubase_ctrlq_init(struct ubase_dev *udev) if (ret) goto err_msg_queue_init; + ret = ubase_ctrlq_crq_table_init(udev); + if (ret) + goto err_crq_table_init; + udev->ctrlq.csq_next_seq = 1; atomic_set(&udev->ctrlq.req_cnt, 0); - ubase_ctrlq_crq_table_init(udev); +err_crq_table_init: + ubase_ctrlq_msg_queue_uninit(udev); success: set_bit(UBASE_CTRLQ_STATE_ENABLE, &udev->ctrlq.state); return 0; @@ -780,8 +868,7 @@ static void ubase_ctrlq_read_msg_data(struct ubase_dev *udev, u8 num, u8 *msg) static void ubase_ctrlq_send_unsupported_resp(struct ubase_dev *udev, struct ubase_ctrlq_base_block *head, - void *msg_data, u16 msg_data_len, - u16 seq) + u16 resp_seq, u8 resp_ret) { struct ubase_ctrlq_msg msg = {0}; int ret; @@ -789,19 +876,14 @@ static void ubase_ctrlq_send_unsupported_resp(struct ubase_dev *udev, msg.service_ver = head->service_ver; msg.service_type = head->service_type; msg.opcode = head->opcode; - msg.in_size = msg_data_len; - msg.in = msg_data; msg.is_resp = 1; - msg.resp_seq = seq; - msg.resp_ret = EOPNOTSUPP; - - ubase_info(udev, "ctrlq received unsupported req. seq=%u, ser_type=%d, ser_ver=%d, opc=0x%x.", - seq, head->service_type, head->service_ver, head->opcode); + msg.resp_seq = resp_seq; + msg.resp_ret = resp_ret; ret = __ubase_ctrlq_send(udev, &msg, NULL); if (ret) - ubase_warn(udev, "failed to send ctrlq unsupported resp. seq=%u, ser_type=%d, ser_ver=%d, opc=0x%x, ret=%d.", - seq, head->service_type, head->service_ver, head->opcode, ret); + ubase_warn(udev, "failed to send ctrlq unsupport resp, ret=%d.", + ret); } static void ubase_ctrlq_crq_event_callback(struct ubase_dev *udev, @@ -809,27 +891,43 @@ static void ubase_ctrlq_crq_event_callback(struct ubase_dev *udev, void *msg_data, u16 msg_data_len, u16 seq) { +#define EDRVNOEXIST 255 struct ubase_ctrlq_crq_table *crq_tab = &udev->ctrlq.crq_table; - struct ubase_ctrlq_crq_event_nbs *nbs; - int ret = -EOPNOTSUPP; + int ret = -ENOENT; + u32 i; + + ubase_info(udev, + "ctrlq recv notice req: seq=%u, ser_type=%u, ser_ver=%u, opc=0x%x.", + seq, head->service_type, head->service_ver, head->opcode); mutex_lock(&crq_tab->lock); - list_for_each_entry(nbs, &crq_tab->crq_nbs.list, list) { - if (nbs->crq_nb.service_type == head->service_type && - nbs->crq_nb.opcode == head->opcode) { - ret = nbs->crq_nb.crq_handler(nbs->crq_nb.back, - head->service_ver, - msg_data, - msg_data_len, - seq); + for (i = 0; i < crq_tab->crq_nb_cnt; i++) { + if (crq_tab->crq_nbs[i].service_type == head->service_type && + crq_tab->crq_nbs[i].opcode == head->opcode) { + if (!crq_tab->crq_nbs[i].crq_handler) { + ret = -EDRVNOEXIST; + break; + } + ret = crq_tab->crq_nbs[i].crq_handler(crq_tab->crq_nbs[i].back, + head->service_ver, + msg_data, + msg_data_len, + seq); break; } } mutex_unlock(&crq_tab->lock); - if (ret == -EOPNOTSUPP) - ubase_ctrlq_send_unsupported_resp(udev, head, msg_data, - msg_data_len, seq); + if (ret == -ENOENT) { + ubase_info(udev, "this notice is not supported."); + ubase_ctrlq_send_unsupported_resp(udev, head, seq, EOPNOTSUPP); + } else if (ret == -EOPNOTSUPP) { + ubase_info(udev, "the notice processor return not support."); + ubase_ctrlq_send_unsupported_resp(udev, head, seq, EOPNOTSUPP); + } else if (ret == -EDRVNOEXIST) { + ubase_info(udev, "the notice processor is unregistered."); + ubase_ctrlq_send_unsupported_resp(udev, head, seq, EDRVNOEXIST); + } } static void ubase_ctrlq_notify_completed(struct ubase_dev *udev, @@ -1064,10 +1162,10 @@ void ubase_ctrlq_clean_service_task(struct ubase_delay_work *ubase_work) int ubase_ctrlq_register_crq_event(struct auxiliary_device *aux_dev, struct ubase_ctrlq_event_nb *nb) { - struct ubase_ctrlq_crq_event_nbs *nbs, *tmp, *new_nbs; struct ubase_ctrlq_crq_table *crq_tab; struct ubase_dev *udev; - int ret; + int ret = -ENOENT; + u32 i; if (!aux_dev || !nb || !nb->crq_handler) return -EINVAL; @@ -1075,31 +1173,21 @@ int ubase_ctrlq_register_crq_event(struct auxiliary_device *aux_dev, udev = __ubase_get_udev_by_adev(aux_dev); crq_tab = &udev->ctrlq.crq_table; mutex_lock(&crq_tab->lock); - list_for_each_entry_safe(nbs, tmp, &crq_tab->crq_nbs.list, list) { - if (nbs->crq_nb.service_type == nb->service_type && - nbs->crq_nb.opcode == nb->opcode) { - ret = -EEXIST; - goto err_crq_register; + for (i = 0; i < crq_tab->crq_nb_cnt; i++) { + if (crq_tab->crq_nbs[i].service_type == nb->service_type && + crq_tab->crq_nbs[i].opcode == nb->opcode) { + if (crq_tab->crq_nbs[i].crq_handler) { + ret = -EEXIST; + break; + } + crq_tab->crq_nbs[i].back = nb->back; + crq_tab->crq_nbs[i].crq_handler = nb->crq_handler; + ret = 0; + break; } } - new_nbs = kzalloc(sizeof(*new_nbs), GFP_KERNEL); - if (!new_nbs) { - ret = -ENOMEM; - goto err_crq_register; - } - - new_nbs->crq_nb = *nb; - list_add_tail(&new_nbs->list, &crq_tab->crq_nbs.list); - mutex_unlock(&crq_tab->lock); - - return 0; - -err_crq_register: mutex_unlock(&crq_tab->lock); - ubase_err(udev, - "failed to register ctrlq crq event, opcode = 0x%x, service_type = 0x%x, ret = %d.\n", - nb->opcode, nb->service_type, ret); return ret; } @@ -1108,9 +1196,9 @@ EXPORT_SYMBOL(ubase_ctrlq_register_crq_event); void ubase_ctrlq_unregister_crq_event(struct auxiliary_device *aux_dev, u8 service_type, u8 opcode) { - struct ubase_ctrlq_crq_event_nbs *nbs, *tmp; struct ubase_ctrlq_crq_table *crq_tab; struct ubase_dev *udev; + u32 i; if (!aux_dev) return; @@ -1118,11 +1206,11 @@ void ubase_ctrlq_unregister_crq_event(struct auxiliary_device *aux_dev, udev = __ubase_get_udev_by_adev(aux_dev); crq_tab = &udev->ctrlq.crq_table; mutex_lock(&crq_tab->lock); - list_for_each_entry_safe(nbs, tmp, &crq_tab->crq_nbs.list, list) { - if (nbs->crq_nb.service_type == service_type && - nbs->crq_nb.opcode == opcode) { - list_del(&nbs->list); - kfree(nbs); + for (i = 0; i < crq_tab->crq_nb_cnt; i++) { + if (crq_tab->crq_nbs[i].service_type == service_type && + crq_tab->crq_nbs[i].opcode == opcode) { + crq_tab->crq_nbs[i].back = NULL; + crq_tab->crq_nbs[i].crq_handler = NULL; break; } } diff --git a/drivers/ub/ubase/ubase_dev.h b/drivers/ub/ubase/ubase_dev.h index c8ccd5bd107a..8d21ff16ef19 100644 --- a/drivers/ub/ubase/ubase_dev.h +++ b/drivers/ub/ubase/ubase_dev.h @@ -178,15 +178,11 @@ struct ubase_ctrlq_msg_ctx { struct completion done; }; -struct ubase_ctrlq_crq_event_nbs { - struct list_head list; - struct ubase_ctrlq_event_nb crq_nb; -}; - struct ubase_ctrlq_crq_table { struct mutex lock; unsigned long last_crq_scheduled; - struct ubase_ctrlq_crq_event_nbs crq_nbs; + u16 crq_nb_cnt; + struct ubase_ctrlq_event_nb *crq_nbs; }; struct ubase_ctrlq { diff --git a/include/ub/ubase/ubase_comm_ctrlq.h b/include/ub/ubase/ubase_comm_ctrlq.h index da3337573b61..b1ee65524052 100644 --- a/include/ub/ubase/ubase_comm_ctrlq.h +++ b/include/ub/ubase/ubase_comm_ctrlq.h @@ -28,16 +28,17 @@ enum ubase_ctrlq_ser_ver { }; enum ubase_ctrlq_ser_type { - UBASE_CTRLQ_SER_TYPE_TP_ACL = 0x01, - UBASE_CTRLQ_SER_TYPE_DEV_REGISTER = 0x02, - UBASE_CTRLQ_SER_TYPE_IP_ACL = 0x03, - UBASE_CTRLQ_SER_TYPE_QOS = 0x04, + UBASE_CTRLQ_SER_TYPE_TP_ACL = 0x01, + UBASE_CTRLQ_SER_TYPE_DEV_REGISTER = 0x02, + UBASE_CTRLQ_SER_TYPE_IP_ACL = 0x03, + UBASE_CTRLQ_SER_TYPE_QOS = 0x04, }; -enum ubase_ctrlq_opc_type { +enum ubase_ctrlq_opc_type_tp { UBASE_CTRLQ_OPC_CREATE_TP = 0x11, UBASE_CTRLQ_OPC_DESTROY_TP = 0x12, UBASE_CTRLQ_OPC_TP_FLUSH_DONE = 0x14, + UBASE_CTRLQ_OPC_CHECK_TP_ACTIVE = 0x15, }; enum ubase_ctrlq_opc_type_qos { @@ -45,14 +46,16 @@ enum ubase_ctrlq_opc_type_qos { UBASE_CTRLQ_OPC_QUERY_SL = 0x02, }; -enum ubase_ctrlq_opc_ip { - UBASE_CTRLQ_OPC_NOTIFY_IP = 0x01, - UBASE_CTRLQ_OPC_QUERY_IP = 0x02, +enum ubase_ctrlq_opc_type_ip { + UBASE_CTRLQ_OPC_NOTIFY_IP = 0x01, + UBASE_CTRLQ_OPC_QUERY_IP = 0x02, }; enum ubase_ctrlq_opc_type_dev_register { - UBASE_CTRLQ_OPC_CTRLQ_CTRL = 0x14, - UBASE_CTRLQ_OPC_UE_RESET_CTRL = 0x15, + UBASE_CTRLQ_OPC_UPDATE_SEID = 0x02, + UBASE_CTRLQ_OPC_NOTIFY_RES_RATIO = 0x13, + UBASE_CTRLQ_OPC_CTRLQ_CTRL = 0x14, + UBASE_CTRLQ_OPC_UE_RESET_CTRL = 0x15, }; struct ubase_ctrlq_msg { -- Gitee From ab244ec24ac8fd4e0e4753efd17bdd440489ecc4 Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Thu, 13 Nov 2025 11:20:06 +0800 Subject: [PATCH 099/103] net: unic: Fix configure coal parameters without deactivate commit 300514e725420aa5309724a6f8e5f43845602ac3 openEuler When activating/deactivating, it is necessary to open/close the protocol stack with link. When configuring parameters, it is necessary to disable the network interface before making changes. Previously, flag was used to intercept and ensure that the two did not run concurrently. After analysis, the UNIC_ACTIVATE_FLAG check in the current code is redundant and can be removed. Fixes: e0ccc63cc72e ("net: unic: support querying and configuring coalesce parameters.") Signed-off-by: Zhenyu Wan Signed-off-by: Fengyan Mu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/net/ub/unic/unic_ethtool.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/net/ub/unic/unic_ethtool.c b/drivers/net/ub/unic/unic_ethtool.c index 960477451df5..f2cfa3df1126 100644 --- a/drivers/net/ub/unic/unic_ethtool.c +++ b/drivers/net/ub/unic/unic_ethtool.c @@ -276,12 +276,6 @@ static int unic_set_coalesce(struct net_device *netdev, struct unic_coalesce old_tx_coal, old_rx_coal; int ret, ret1; - if (test_bit(UNIC_STATE_DEACTIVATE, &unic_dev->state)) { - unic_err(unic_dev, - "failed to set coalesce, due to dev deacitve.\n"); - return -EBUSY; - } - if (unic_resetting(netdev)) return -EBUSY; @@ -298,7 +292,6 @@ static int unic_set_coalesce(struct net_device *netdev, tx_coal->int_ql = cmd->tx_max_coalesced_frames; rx_coal->int_ql = cmd->rx_max_coalesced_frames; - unic_net_stop_no_link_change(netdev); unic_uninit_channels(unic_dev); ret = unic_init_channels(unic_dev, unic_dev->channels.num); @@ -307,18 +300,12 @@ static int unic_set_coalesce(struct net_device *netdev, memcpy(tx_coal, &old_tx_coal, sizeof(struct unic_coalesce)); memcpy(rx_coal, &old_rx_coal, sizeof(struct unic_coalesce)); ret1 = unic_init_channels(unic_dev, unic_dev->channels.num); - if (ret1) { + if (ret1) unic_err(unic_dev, "failed to recover old channels, ret = %d.\n", ret1); - return ret; - } } - ret1 = unic_net_open_no_link_change(netdev); - if (ret1) - unic_err(unic_dev, "failed to set net open, ret = %d.\n", ret1); - return ret; } -- Gitee From 1570158d0886d19d9788f45e40ebb8706f8f3ec8 Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Thu, 13 Nov 2025 17:52:07 +0800 Subject: [PATCH 100/103] ub: ubase: Fix link status timestamp information commit f348a2d07557f2bd87d672f1c006d68436a4d179 openEuler In the current version, the timestamp recorded in the link status record changes with the system time because the TIME is obtained through the ktime_get_real_seconds function when printing the link status record. This patch fixes the issue by changing the value of TIME to the historical moment recorded in the stats array. Fixes: 58daddb6f308 ("net: unic: support subscribes to the RX stream stop and recovery interface.") Signed-off-by: Xuanyu Pu Signed-off-by: Fengyan Mu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/net/ub/unic/debugfs/unic_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ub/unic/debugfs/unic_debugfs.c b/drivers/net/ub/unic/debugfs/unic_debugfs.c index 0a6dbdaffedc..f58ed6f7567a 100644 --- a/drivers/net/ub/unic/debugfs/unic_debugfs.c +++ b/drivers/net/ub/unic/debugfs/unic_debugfs.c @@ -222,7 +222,7 @@ static int unic_dbg_query_link_record(struct seq_file *s, void *data) total--; idx = total % LINK_STAT_MAX_IDX; seq_printf(s, "\t%-2d\t", cnt); - ubase_dbg_format_time(ktime_get_real_seconds(), s); + ubase_dbg_format_time(record->stats[idx].link_tv_sec, s); seq_printf(s, "\t%s\n", record->stats[idx].link_status ? "LINK UP" : "LINK DOWN"); cnt++; -- Gitee From fd494d8d4ae9b53611c8f1efbe337267582961f2 Mon Sep 17 00:00:00 2001 From: Xiongchuan Zhou Date: Thu, 13 Nov 2025 15:08:53 +0800 Subject: [PATCH 101/103] net: unic: Fix lose vport_ctx and vport_buf information query in debugfs commit 0bc3e46d0f2d581c68f2825235a8ab10f92c71a9 openEuler Added vport_ctx and vport_buf queries in debugfs to facilitate viewing the related configuration information of pf. Fixes: 4420dfeed31d ("net: unic: Support to query and clear historical NIC link status information") Signed-off-by: Xiongchuan Zhou Signed-off-by: Fengyan Mu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/net/ub/unic/debugfs/unic_debugfs.c | 73 ++++++++++++++++++++++ drivers/net/ub/unic/debugfs/unic_debugfs.h | 1 + drivers/net/ub/unic/unic_cmd.h | 8 +++ drivers/net/ub/unic/unic_hw.c | 23 +++++++ drivers/net/ub/unic/unic_hw.h | 2 + include/ub/ubase/ubase_comm_cmd.h | 1 + 6 files changed, 108 insertions(+) diff --git a/drivers/net/ub/unic/debugfs/unic_debugfs.c b/drivers/net/ub/unic/debugfs/unic_debugfs.c index f58ed6f7567a..4c7bf3bb83fc 100644 --- a/drivers/net/ub/unic/debugfs/unic_debugfs.c +++ b/drivers/net/ub/unic/debugfs/unic_debugfs.c @@ -39,6 +39,61 @@ static int unic_dbg_dump_dev_info(struct seq_file *s, void *data) return 0; } +static int unic_dbg_dump_vport_buf(struct seq_file *s, void *data) +{ + struct unic_dev *unic_dev = dev_get_drvdata(s->private); + + seq_printf(s, "vport buffer num: %u\n", unic_dev->caps.vport_buf_num); + seq_printf(s, "vport buffer size: %u\n", unic_dev->caps.vport_buf_size); + return 0; +} + +static void unic_dbg_fill_vport_ctx_content(struct unic_vport_ctx_cmd *resp, + struct seq_file *s) +{ + u32 i, j; + + for (i = 0; i < UNIC_VORT_CTX_DATA_NUM; i += UNIC_VORT_CTX_DATA_ALIGN) { + seq_printf(s, "%08X: ", i * UNIC_VORT_CTX_DATA_ALIGN); + for (j = 0; j < UNIC_VORT_CTX_DATA_ALIGN; j++) { + if ((i + j) == UNIC_VORT_CTX_DATA_NUM) + break; + seq_printf(s, "%08X ", resp->data[i + j]); + } + seq_puts(s, "\n"); + } +} + +static int unic_dbg_query_vport_ctx(struct seq_file *s) +{ + struct unic_dev *unic_dev = dev_get_drvdata(s->private); + struct unic_vport_ctx_cmd resp; + u16 offset = 0; + int ret; + + do { + memset(&resp, 0, sizeof(resp)); + ret = unic_query_vport_ctx(unic_dev, offset, &resp); + if (ret) + return ret; + offset = resp.offset; + + unic_dbg_fill_vport_ctx_content(&resp, s); + } while (resp.offset); + + return 0; +} + +static int unic_dbg_dump_vport_ctx(struct seq_file *s, void *data) +{ + struct unic_dev *unic_dev = dev_get_drvdata(s->private); + + if (__unic_resetting(unic_dev)) + return -EBUSY; + + return unic_dbg_query_vport_ctx(s); +} + static const struct unic_dbg_cap_bit_info { const char *format; bool (*get_bit)(struct unic_dev *dev); @@ -265,6 +320,10 @@ static struct ubase_dbg_dentry_info unic_dbg_dentry[] = { .name = "context", .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, .support = unic_dbg_dentry_support, + }, { + .name = "vport", + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, + .support = unic_dbg_dentry_support, }, { .name = "qos", .property = UBASE_SUP_UNIC | UBASE_SUP_UBL, @@ -328,6 +387,20 @@ static struct ubase_dbg_cmd_info unic_dbg_cmd[] = { .support = unic_dbg_dentry_support, .init = ubase_dbg_seq_file_init, .read_func = unic_dbg_dump_dev_info, + }, { + .name = "vport_buf", + .dentry_index = UNIC_DBG_DENTRY_VPORT, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL_ETH, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_vport_buf, + }, { + .name = "vport_ctx", + .dentry_index = UNIC_DBG_DENTRY_VPORT, + .property = UBASE_SUP_UNIC | UBASE_SUP_UBL_ETH, + .support = unic_dbg_dentry_support, + .init = ubase_dbg_seq_file_init, + .read_func = unic_dbg_dump_vport_ctx, }, { .name = "caps_info", .dentry_index = UNIC_DBG_DENTRY_ROOT, diff --git a/drivers/net/ub/unic/debugfs/unic_debugfs.h b/drivers/net/ub/unic/debugfs/unic_debugfs.h index 73a75b091b4b..853597b90f45 100644 --- a/drivers/net/ub/unic/debugfs/unic_debugfs.h +++ b/drivers/net/ub/unic/debugfs/unic_debugfs.h @@ -15,6 +15,7 @@ enum unic_dbg_dentry_type { UNIC_DBG_DENTRY_IP = 0, UNIC_DBG_DENTRY_CONTEXT, + UNIC_DBG_DENTRY_VPORT, UNIC_DBG_DENTRY_QOS, /* must be the last entry. */ UNIC_DBG_DENTRY_ROOT diff --git a/drivers/net/ub/unic/unic_cmd.h b/drivers/net/ub/unic/unic_cmd.h index 125802234e6b..ac571815be6a 100644 --- a/drivers/net/ub/unic/unic_cmd.h +++ b/drivers/net/ub/unic/unic_cmd.h @@ -109,6 +109,14 @@ struct unic_cfg_vport_buf_cmd { __le32 buf_addr[UNIC_MAX_VPORT_BUF_NUM * U32S_PER_U64]; }; +#define UNIC_VORT_CTX_DATA_NUM 13 +#define UNIC_VORT_CTX_DATA_ALIGN 4 +struct unic_vport_ctx_cmd { + u8 resv[2]; + __le16 offset; + __le32 data[UNIC_VORT_CTX_DATA_NUM]; +}; + struct unic_cfg_fec_cmd { __le32 fec_mode; u8 rsv[20]; diff --git a/drivers/net/ub/unic/unic_hw.c b/drivers/net/ub/unic/unic_hw.c index be606bfb6495..565ac56fb638 100644 --- a/drivers/net/ub/unic/unic_hw.c +++ b/drivers/net/ub/unic/unic_hw.c @@ -674,6 +674,29 @@ int unic_cfg_vport_buf(struct unic_dev *unic_dev, bool init) return ret; } +int unic_query_vport_ctx(struct unic_dev *unic_dev, u16 offset, + struct unic_vport_ctx_cmd *resp) +{ + struct unic_vport_ctx_cmd req; + struct ubase_cmd_buf in, out; + int ret; + + memset(&req, 0, sizeof(req)); + req.offset = cpu_to_le16(offset); + + ubase_fill_inout_buf(&in, UBASE_OPC_VPORT_CTX, true, + sizeof(req), &req); + ubase_fill_inout_buf(&out, UBASE_OPC_VPORT_CTX, true, + sizeof(*resp), resp); + + ret = ubase_cmd_send_inout(unic_dev->comdev.adev, &in, &out); + if (ret) + unic_err(unic_dev, + "failed to query vport ctx, offset = %u, ret = %d.\n", + offset, ret); + return ret; +} + int unic_set_fec_mode(struct unic_dev *unic_dev, u32 fec_mode) { struct unic_cfg_fec_cmd req = {0}; diff --git a/drivers/net/ub/unic/unic_hw.h b/drivers/net/ub/unic/unic_hw.h index cfd46b6eadf4..ba64d398e44b 100644 --- a/drivers/net/ub/unic/unic_hw.h +++ b/drivers/net/ub/unic/unic_hw.h @@ -95,6 +95,8 @@ int unic_set_promisc_mode(struct unic_dev *unic_dev, struct unic_promisc_en *promisc_en); int unic_cfg_vport_buf(struct unic_dev *unic_dev, bool init); +int unic_query_vport_ctx(struct unic_dev *unic_dev, u16 offset, + struct unic_vport_ctx_cmd *resp); int unic_set_fec_mode(struct unic_dev *unic_dev, u32 fec_mode); int unic_update_fec_stats(struct unic_dev *unic_dev); int unic_set_rss_tc_mode(struct unic_dev *unic_dev, u8 tc_vaild); diff --git a/include/ub/ubase/ubase_comm_cmd.h b/include/ub/ubase/ubase_comm_cmd.h index 492b5e8513ea..b0f97fb6cba7 100644 --- a/include/ub/ubase/ubase_comm_cmd.h +++ b/include/ub/ubase/ubase_comm_cmd.h @@ -102,6 +102,7 @@ enum ubase_opcode_type { UBASE_OPC_NOTIFY_UE_RESET = 0xF006, UBASE_OPC_QUERY_UE_RST_RDY = 0xF007, UBASE_OPC_RESET_DONE = 0xF008, + UBASE_OPC_VPORT_CTX = 0xF009, UBASE_OPC_DESTROY_CTX_RESOURCE = 0xF00D, UBASE_OPC_UE2UE_UBASE = 0xF00E, UBASE_OPC_ACTIVATE_REQ = 0xF00F, -- Gitee From ba56a0c7da8911e63a596a95ab5aeac64abc4291 Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Thu, 20 Nov 2025 11:29:44 +0800 Subject: [PATCH 102/103] ub: ubase: flush the work queue. commit b056b8147b7551de6c6a1652032f55d0b5f51a20 openEuler Fixed an Error issue when the ctrlq crq work queue accesses the ctrlq memory during the ELR reset. Wait until the work queue is complete in the suspend phase to ensure that no work queue is executed during the reset. Fixes: 727362c0978c ("ub: ubase: Support for ELR and entity reset.") Signed-off-by: ShiLong Signed-off-by: Jianqiang Li Signed-off-by: Fengyan Mu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/ubase/ubase_dev.c | 8 ++++++++ drivers/ub/ubase/ubase_dev.h | 2 ++ drivers/ub/ubase/ubase_reset.c | 1 + 3 files changed, 11 insertions(+) diff --git a/drivers/ub/ubase/ubase_dev.c b/drivers/ub/ubase/ubase_dev.c index 7331afa03c80..9ea0d14a4d39 100644 --- a/drivers/ub/ubase/ubase_dev.c +++ b/drivers/ub/ubase/ubase_dev.c @@ -1317,6 +1317,14 @@ int ubase_deactivate_handler(struct ubase_dev *udev, u32 bus_ue_id) return ubase_send_activate_dev_req(udev, false, (u16)bus_ue_id); } +void ubase_flush_workqueue(struct ubase_dev *udev) +{ + flush_workqueue(udev->ubase_wq); + flush_workqueue(udev->ubase_async_wq); + flush_workqueue(udev->ubase_period_wq); + flush_workqueue(udev->ubase_arq_wq); +} + int ubase_activate_dev(struct auxiliary_device *adev) { struct ubase_dev *udev; diff --git a/drivers/ub/ubase/ubase_dev.h b/drivers/ub/ubase/ubase_dev.h index 8d21ff16ef19..45605409de6b 100644 --- a/drivers/ub/ubase/ubase_dev.h +++ b/drivers/ub/ubase/ubase_dev.h @@ -451,4 +451,6 @@ void ubase_virt_handler(struct ubase_dev *udev, u16 bus_ue_id, bool is_en); int ubase_activate_handler(struct ubase_dev *udev, u32 bus_ue_id); int ubase_deactivate_handler(struct ubase_dev *udev, u32 bus_ue_id); +void ubase_flush_workqueue(struct ubase_dev *udev); + #endif diff --git a/drivers/ub/ubase/ubase_reset.c b/drivers/ub/ubase/ubase_reset.c index bb1c281c02d3..7da51b021026 100644 --- a/drivers/ub/ubase/ubase_reset.c +++ b/drivers/ub/ubase/ubase_reset.c @@ -229,6 +229,7 @@ void ubase_suspend(struct ubase_dev *udev) ubase_ctrlq_disable_remote(udev); ubase_ctrlq_disable(udev); ubase_irq_table_free(udev); + ubase_flush_workqueue(udev); } void ubase_resume(struct ubase_dev *udev) -- Gitee From 99b1a6d0b34fd45527caa06d782b1c348ec61954 Mon Sep 17 00:00:00 2001 From: Xiongchuan Zhou Date: Fri, 14 Nov 2025 15:55:34 +0800 Subject: [PATCH 103/103] ub: ubase: Fix the lose of HIMAC reset. commit 6006cbfe442fd607d4042a4d6d82f8239d93aae4 openEuler Added support for HIMAC reset, including state detection, reset command sending, and debug information output. The modifications include: Added HIMAC reset handling logic to trigger reset operations when HIMAC anomalies are detected. Included HIMAC reset count in debug information for tracking and analysis. Defined a new command code UBASE_OPC_HIMAC_RESET for sending HIMAC reset commands. These changes enable comprehensive support for HIMAC reset, covering state management, command execution, and debug output. Fixes: 727362c0978c ("ub: ubase: Support for ELR and entity reset.") Signed-off-by: Xu Wang Signed-off-by: Xiongchuan Zhou Signed-off-by: Fengyan Mu Signed-off-by: zhaolichang <943677312@qq.com> --- drivers/ub/ubase/debugfs/ubase_debugfs.c | 1 + drivers/ub/ubase/ubase_err_handle.c | 20 ++++++++++++++++++++ include/ub/ubase/ubase_comm_cmd.h | 1 + 3 files changed, 22 insertions(+) diff --git a/drivers/ub/ubase/debugfs/ubase_debugfs.c b/drivers/ub/ubase/debugfs/ubase_debugfs.c index bf49fc3fdc93..21fe4d1fa9b6 100644 --- a/drivers/ub/ubase/debugfs/ubase_debugfs.c +++ b/drivers/ub/ubase/debugfs/ubase_debugfs.c @@ -24,6 +24,7 @@ static int ubase_dbg_dump_rst_info(struct seq_file *s, void *data) seq_printf(s, "ELR reset count: %u\n", udev->reset_stat.elr_reset_cnt); seq_printf(s, "port reset count: %u\n", udev->reset_stat.port_reset_cnt); + seq_printf(s, "himac reset count: %u\n", udev->reset_stat.himac_reset_cnt); seq_printf(s, "reset done count: %u\n", udev->reset_stat.reset_done_cnt); seq_printf(s, "HW reset done count: %u\n", udev->reset_stat.hw_reset_done_cnt); seq_printf(s, "reset fail count: %u\n", udev->reset_stat.reset_fail_cnt); diff --git a/drivers/ub/ubase/ubase_err_handle.c b/drivers/ub/ubase/ubase_err_handle.c index d91ab0f80b6b..179e59acec0a 100644 --- a/drivers/ub/ubase/ubase_err_handle.c +++ b/drivers/ub/ubase/ubase_err_handle.c @@ -9,6 +9,19 @@ #include "ubase_reset.h" #include "ubase_err_handle.h" +static void ubase_notify_himac_reset(struct ubase_dev *udev) +{ + struct ubase_cmd_buf in; + int ret; + + __ubase_fill_inout_buf(&in, UBASE_OPC_HIMAC_RESET, false, 0, NULL); + + ret = __ubase_cmd_send_in(udev, &in); + if (ret) + ubase_err(udev, + "failed to send himac reset cmd, ret = %d.\n", ret); +} + void ubase_errhandle_service_task(struct ubase_delay_work *ubase_work) { struct ubase_dev *udev; @@ -23,6 +36,13 @@ void ubase_errhandle_service_task(struct ubase_delay_work *ubase_work) return; } + if (test_and_clear_bit(UBASE_STATE_HIMAC_RESETTING_B, &udev->state_bits)) { + ubase_err(udev, "ras occurred, ubase need to reset himac.\n"); + ubase_notify_himac_reset(udev); + udev->reset_stat.himac_reset_cnt++; + return; + } + if (test_and_clear_bit(UBASE_STATE_PORT_RESETTING_B, &udev->state_bits)) { ubase_err(udev, "ras occurred, ubase need to reset port.\n"); ubase_port_reset(udev); diff --git a/include/ub/ubase/ubase_comm_cmd.h b/include/ub/ubase/ubase_comm_cmd.h index b0f97fb6cba7..7ae969c897b9 100644 --- a/include/ub/ubase/ubase_comm_cmd.h +++ b/include/ub/ubase/ubase_comm_cmd.h @@ -87,6 +87,7 @@ enum ubase_opcode_type { UBASE_OPC_QUERY_PORT_INFO = 0x6200, UBASE_OPC_QUERY_CHIP_INFO = 0x6201, UBASE_OPC_QUERY_FEC_STATS = 0x6202, + UBASE_OPC_HIMAC_RESET = 0x6302, /* Mailbox commands */ UBASE_OPC_POST_MB = 0x7000, -- Gitee