// SPDX-License-Identifier: GPL-2.0 /* Huawei Hifc PCI Express Linux driver * Copyright(c) 2017 Huawei Technologies Co., Ltd * */ #include #include #include #include #include #include "hifc_knl_adp.h" #include "hifc_hw.h" #include "hifc_hwdev.h" #include "hifc_hwif.h" #include "hifc_api_cmd.h" #include "hifc_mgmt.h" #include "hifc_cfg.h" #include "hifc_cqm_object.h" #include "hifc_cqm_main.h" #define GET_MAX(a, b) (((a) > (b)) ? (a) : (b)) #define GET_MIN(a, b) (((a) < (b)) ? (a) : (b)) static void cqm_capability_init_check_ppf(void *ex_handle, u32 *total_function_num) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; struct service_cap *service_capability = &handle->cfg_mgmt->svc_cap; struct cqm_handle_s *cqm_handle = (struct cqm_handle_s *) (handle->cqm_hdl); if (cqm_handle->func_attribute.func_type == CQM_PPF) { *total_function_num = service_capability->host_total_function; cqm_handle->func_capability.timer_enable = service_capability->timer_en; cqm_info(handle->dev_hdl, "Cap init: total function num 0x%x\n", *total_function_num); cqm_info(handle->dev_hdl, "Cap init: timer_enable %d (1: enable; 0: disable)\n", cqm_handle->func_capability.timer_enable); } } void cqm_test_mode_init(struct cqm_handle_s *cqm_handle, struct service_cap *service_capability) { cqm_handle->func_capability.xid_alloc_mode = service_capability->test_xid_alloc_mode; cqm_handle->func_capability.gpa_check_enable = service_capability->test_gpa_check_enable; } static s32 cqm_service_capability_init_for_each( struct cqm_handle_s *cqm_handle, struct service_cap *service_capability) { struct hifc_hwdev *handle = (struct hifc_hwdev *)cqm_handle->ex_handle; cqm_info(handle->dev_hdl, "Cap init: fc is valid\n"); cqm_handle->func_capability.hash_number += service_capability->fc_cap.dev_fc_cap.max_parent_qpc_num; cqm_handle->func_capability.hash_basic_size = CQM_HASH_BUCKET_SIZE_64; cqm_handle->func_capability.qpc_number += service_capability->fc_cap.dev_fc_cap.max_parent_qpc_num; cqm_handle->func_capability.qpc_basic_size = GET_MAX(service_capability->fc_cap.parent_qpc_size, cqm_handle->func_capability.qpc_basic_size); cqm_handle->func_capability.qpc_alloc_static = true; cqm_handle->func_capability.scqc_number += service_capability->fc_cap.dev_fc_cap.scq_num; cqm_handle->func_capability.scqc_basic_size = GET_MAX(service_capability->fc_cap.scqc_size, cqm_handle->func_capability.scqc_basic_size); cqm_handle->func_capability.srqc_number += service_capability->fc_cap.dev_fc_cap.srq_num; cqm_handle->func_capability.srqc_basic_size = GET_MAX(service_capability->fc_cap.srqc_size, cqm_handle->func_capability.srqc_basic_size); cqm_handle->func_capability.lun_number = CQM_LUN_FC_NUM; cqm_handle->func_capability.lun_basic_size = CQM_LUN_SIZE_8; cqm_handle->func_capability.taskmap_number = CQM_TASKMAP_FC_NUM; cqm_handle->func_capability.taskmap_basic_size = PAGE_SIZE; cqm_handle->func_capability.childc_number += service_capability->fc_cap.dev_fc_cap.max_child_qpc_num; cqm_handle->func_capability.childc_basic_size = GET_MAX(service_capability->fc_cap.child_qpc_size, cqm_handle->func_capability.childc_basic_size); cqm_handle->func_capability.pagesize_reorder = CQM_FC_PAGESIZE_ORDER; return CQM_SUCCESS; } s32 cqm_service_capability_init(struct cqm_handle_s *cqm_handle, struct service_cap *service_capability) { cqm_handle->service.has_register = false; cqm_handle->service.buf_order = 0; if (cqm_service_capability_init_for_each( cqm_handle, service_capability) == CQM_FAIL) return CQM_FAIL; return CQM_SUCCESS; } /** * cqm_capability_init - Initialize capability of cqm function and service, * need to read information from the configuration management module * @ex_handle: handle of hwdev */ s32 cqm_capability_init(void *ex_handle) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; struct service_cap *service_capability = &handle->cfg_mgmt->svc_cap; struct cqm_handle_s *cqm_handle = (struct cqm_handle_s *) (handle->cqm_hdl); u32 total_function_num = 0; int err = 0; cqm_capability_init_check_ppf(ex_handle, &total_function_num); cqm_handle->func_capability.flow_table_based_conn_number = service_capability->max_connect_num; cqm_handle->func_capability.flow_table_based_conn_cache_number = service_capability->max_stick2cache_num; cqm_info(handle->dev_hdl, "Cap init: cfg max_conn_num 0x%x, max_cache_conn_num 0x%x\n", cqm_handle->func_capability.flow_table_based_conn_number, cqm_handle->func_capability.flow_table_based_conn_cache_number); cqm_handle->func_capability.qpc_reserved = 0; cqm_handle->func_capability.mpt_reserved = 0; cqm_handle->func_capability.qpc_alloc_static = false; cqm_handle->func_capability.scqc_alloc_static = false; cqm_handle->func_capability.l3i_number = CQM_L3I_COMM_NUM; cqm_handle->func_capability.l3i_basic_size = CQM_L3I_SIZE_8; cqm_handle->func_capability.timer_number = CQM_TIMER_ALIGN_SCALE_NUM * total_function_num; cqm_handle->func_capability.timer_basic_size = CQM_TIMER_SIZE_32; if (cqm_service_capability_init(cqm_handle, service_capability) == CQM_FAIL) { cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_service_capability_init)); err = CQM_FAIL; goto out; } cqm_test_mode_init(cqm_handle, service_capability); cqm_info(handle->dev_hdl, "Cap init: pagesize_reorder %d\n", cqm_handle->func_capability.pagesize_reorder); cqm_info(handle->dev_hdl, "Cap init: xid_alloc_mode %d, gpa_check_enable %d\n", cqm_handle->func_capability.xid_alloc_mode, cqm_handle->func_capability.gpa_check_enable); cqm_info(handle->dev_hdl, "Cap init: qpc_alloc_mode %d, scqc_alloc_mode %d\n", cqm_handle->func_capability.qpc_alloc_static, cqm_handle->func_capability.scqc_alloc_static); cqm_info(handle->dev_hdl, "Cap init: hash_number 0x%x\n", cqm_handle->func_capability.hash_number); cqm_info(handle->dev_hdl, "Cap init: qpc_number 0x%x, qpc_reserved 0x%x\n", cqm_handle->func_capability.qpc_number, cqm_handle->func_capability.qpc_reserved); cqm_info(handle->dev_hdl, "Cap init: scqc_number 0x%x scqc_reserved 0x%x\n", cqm_handle->func_capability.scqc_number, cqm_handle->func_capability.scq_reserved); cqm_info(handle->dev_hdl, "Cap init: srqc_number 0x%x\n", cqm_handle->func_capability.srqc_number); cqm_info(handle->dev_hdl, "Cap init: mpt_number 0x%x, mpt_reserved 0x%x\n", cqm_handle->func_capability.mpt_number, cqm_handle->func_capability.mpt_reserved); cqm_info(handle->dev_hdl, "Cap init: gid_number 0x%x, lun_number 0x%x\n", cqm_handle->func_capability.gid_number, cqm_handle->func_capability.lun_number); cqm_info(handle->dev_hdl, "Cap init: taskmap_number 0x%x, l3i_number 0x%x\n", cqm_handle->func_capability.taskmap_number, cqm_handle->func_capability.l3i_number); cqm_info(handle->dev_hdl, "Cap init: timer_number 0x%x\n", cqm_handle->func_capability.timer_number); cqm_info(handle->dev_hdl, "Cap init: xid2cid_number 0x%x, reorder_number 0x%x\n", cqm_handle->func_capability.xid2cid_number, cqm_handle->func_capability.reorder_number); return CQM_SUCCESS; out: if (cqm_handle->func_attribute.func_type == CQM_PPF) cqm_handle->func_capability.timer_enable = 0; return err; } /** * cqm_init - Initialize cqm * @ex_handle: handle of hwdev */ s32 cqm_init(void *ex_handle) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; struct cqm_handle_s *cqm_handle = NULL; s32 ret = CQM_FAIL; CQM_PTR_CHECK_RET(ex_handle, return CQM_FAIL, CQM_PTR_NULL(ex_handle)); cqm_handle = (struct cqm_handle_s *)kmalloc(sizeof(struct cqm_handle_s), GFP_KERNEL | __GFP_ZERO); CQM_PTR_CHECK_RET(cqm_handle, return CQM_FAIL, CQM_ALLOC_FAIL(cqm_handle)); /* Clear memory to prevent other systems' memory from being cleared */ memset(cqm_handle, 0, sizeof(struct cqm_handle_s)); cqm_handle->ex_handle = handle; cqm_handle->dev = (struct pci_dev *)(handle->pcidev_hdl); handle->cqm_hdl = (void *)cqm_handle; /* Clear statistics */ memset(&handle->hw_stats.cqm_stats, 0, sizeof(struct hifc_cqm_stats)); /* Read information of vf or pf */ cqm_handle->func_attribute = handle->hwif->attr; cqm_info(handle->dev_hdl, "Func init: function type %d\n", cqm_handle->func_attribute.func_type); /* Read ability from configuration management module */ ret = cqm_capability_init(ex_handle); if (ret == CQM_FAIL) { cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_capability_init)); goto err1; } /* Initialize entries of memory table such as BAT/CLA/bitmap */ if (cqm_mem_init(ex_handle) != CQM_SUCCESS) { cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_mem_init)); goto err1; } /* Initialize event callback */ if (cqm_event_init(ex_handle) != CQM_SUCCESS) { cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_event_init)); goto err2; } /* Initialize doorbell */ if (cqm_db_init(ex_handle) != CQM_SUCCESS) { cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_db_init)); goto err3; } /* The timer bitmap is set directly from the beginning through CQM, * no longer set/clear the bitmap through ifconfig up/down */ if (hifc_func_tmr_bitmap_set(ex_handle, 1) != CQM_SUCCESS) { cqm_err(handle->dev_hdl, "Timer start: enable timer bitmap failed\n"); goto err5; } return CQM_SUCCESS; err5: cqm_db_uninit(ex_handle); err3: cqm_event_uninit(ex_handle); err2: cqm_mem_uninit(ex_handle); err1: handle->cqm_hdl = NULL; kfree(cqm_handle); return CQM_FAIL; } /** * cqm_uninit - Deinitialize the cqm, and is called once removing a function * @ex_handle: handle of hwdev */ void cqm_uninit(void *ex_handle) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; struct cqm_handle_s *cqm_handle = NULL; s32 ret = CQM_FAIL; CQM_PTR_CHECK_NO_RET(ex_handle, CQM_PTR_NULL(ex_handle), return); cqm_handle = (struct cqm_handle_s *)(handle->cqm_hdl); CQM_PTR_CHECK_NO_RET(cqm_handle, CQM_PTR_NULL(cqm_handle), return); /* The timer bitmap is set directly from the beginning through CQM, * no longer set/clear the bitmap through ifconfig up/down */ cqm_info(handle->dev_hdl, "Timer stop: disable timer\n"); if (hifc_func_tmr_bitmap_set(ex_handle, 0) != CQM_SUCCESS) cqm_err(handle->dev_hdl, "Timer stop: disable timer bitmap failed\n"); /* Stopping timer, release the resource * after a delay of one or two milliseconds */ if ((cqm_handle->func_attribute.func_type == CQM_PPF) && (cqm_handle->func_capability.timer_enable == CQM_TIMER_ENABLE)) { cqm_info(handle->dev_hdl, "Timer stop: hifc ppf timer stop\n"); ret = hifc_ppf_tmr_stop(handle); if (ret != CQM_SUCCESS) { cqm_info(handle->dev_hdl, "Timer stop: hifc ppf timer stop, ret=%d\n", ret); /* The timer fails to stop * and does not affect resource release */ } usleep_range(900, 1000); } /* Release hardware doorbell */ cqm_db_uninit(ex_handle); /* Cancel the callback of chipif */ cqm_event_uninit(ex_handle); /* Release all table items * and require the service to release all objects */ cqm_mem_uninit(ex_handle); /* Release cqm_handle */ handle->cqm_hdl = NULL; kfree(cqm_handle); } /** * cqm_mem_init - Initialize related memory of cqm, * including all levels of entries * @ex_handle: handle of hwdev */ s32 cqm_mem_init(void *ex_handle) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; struct cqm_handle_s *cqm_handle = NULL; cqm_handle = (struct cqm_handle_s *)(handle->cqm_hdl); if (cqm_bat_init(cqm_handle) != CQM_SUCCESS) { cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_bat_init)); return CQM_FAIL; } if (cqm_cla_init(cqm_handle) != CQM_SUCCESS) { cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_cla_init)); goto err1; } if (cqm_bitmap_init(cqm_handle) != CQM_SUCCESS) { cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_bitmap_init)); goto err2; } if (cqm_object_table_init(cqm_handle) != CQM_SUCCESS) { cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_object_table_init)); goto err3; } return CQM_SUCCESS; err3: cqm_bitmap_uninit(cqm_handle); err2: cqm_cla_uninit(cqm_handle); err1: cqm_bat_uninit(cqm_handle); return CQM_FAIL; } /** * cqm_mem_uninit - Deinitialize related memory of cqm, * including all levels of entries * @ex_handle: handle of hwdev */ void cqm_mem_uninit(void *ex_handle) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; struct cqm_handle_s *cqm_handle = NULL; cqm_handle = (struct cqm_handle_s *)(handle->cqm_hdl); cqm_object_table_uninit(cqm_handle); cqm_bitmap_uninit(cqm_handle); cqm_cla_uninit(cqm_handle); cqm_bat_uninit(cqm_handle); } /** * cqm_event_init - Initialize the event callback of cqm * @ex_handle: handle of hwdev */ s32 cqm_event_init(void *ex_handle) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; /* Register ceq and aeq callbacks with chipif */ if (hifc_aeq_register_swe_cb(ex_handle, HIFC_STATEFULL_EVENT, cqm_aeq_callback) != CHIPIF_SUCCESS) { cqm_err(handle->dev_hdl, "Event: fail to register aeq callback\n"); return CQM_FAIL; } return CQM_SUCCESS; } /** * cqm_event_uninit - Deinitialize the event callback of cqm * @ex_handle: handle of hwdev */ void cqm_event_uninit(void *ex_handle) { (void)hifc_aeq_unregister_swe_cb(ex_handle, HIFC_STATEFULL_EVENT); } /** * cqm_db_addr_alloc - Apply for a page of hardware doorbell and dwqe, * with the same index, all obtained are physical addresses * each function has up to 1K * @ex_handle: handle of hwdev * @db_addr: the address of doorbell * @dwqe_addr: the address of dwqe */ s32 cqm_db_addr_alloc(void *ex_handle, void __iomem **db_addr, void __iomem **dwqe_addr) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; CQM_PTR_CHECK_RET(ex_handle, return CQM_FAIL, CQM_PTR_NULL(ex_handle)); CQM_PTR_CHECK_RET(db_addr, return CQM_FAIL, CQM_PTR_NULL(db_addr)); CQM_PTR_CHECK_RET(dwqe_addr, return CQM_FAIL, CQM_PTR_NULL(dwqe_addr)); atomic_inc(&handle->hw_stats.cqm_stats.cqm_db_addr_alloc_cnt); return hifc_alloc_db_addr(ex_handle, db_addr, dwqe_addr); } /** * cqm_db_init - Initialize doorbell of cqm * @ex_handle: handle of hwdev */ s32 cqm_db_init(void *ex_handle) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; struct cqm_handle_s *cqm_handle = NULL; struct cqm_service_s *service = NULL; cqm_handle = (struct cqm_handle_s *)(handle->cqm_hdl); /* Assign hardware doorbell for service */ service = &cqm_handle->service; if (cqm_db_addr_alloc(ex_handle, &service->hardware_db_vaddr, &service->dwqe_vaddr) != CQM_SUCCESS) { cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_db_addr_alloc)); return CQM_FAIL; } return CQM_SUCCESS; } /** * cqm_db_addr_free - Release a page of hardware doorbell and dwqe * @ex_handle: handle of hwdev * @db_addr: the address of doorbell * @dwqe_addr: the address of dwqe */ void cqm_db_addr_free(void *ex_handle, void __iomem *db_addr, void __iomem *dwqe_addr) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; CQM_PTR_CHECK_NO_RET(ex_handle, CQM_PTR_NULL(ex_handle), return); atomic_inc(&handle->hw_stats.cqm_stats.cqm_db_addr_free_cnt); hifc_free_db_addr(ex_handle, db_addr, dwqe_addr); } /** * cqm_db_uninit - Deinitialize doorbell of cqm * @ex_handle: handle of hwdev */ void cqm_db_uninit(void *ex_handle) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; struct cqm_handle_s *cqm_handle = NULL; struct cqm_service_s *service = NULL; cqm_handle = (struct cqm_handle_s *)(handle->cqm_hdl); /* Release hardware doorbell */ service = &cqm_handle->service; cqm_db_addr_free(ex_handle, service->hardware_db_vaddr, service->dwqe_vaddr); } /** * cqm_aeq_callback - cqm module callback processing of aeq * @ex_handle: handle of hwdev * @event: the input type of event * @data: the input data */ u8 cqm_aeq_callback(void *ex_handle, u8 event, u64 data) { #define CQM_AEQ_BASE_T_FC 48 #define CQM_AEQ_BASE_T_FCOE 56 struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; struct cqm_handle_s *cqm_handle = NULL; struct cqm_service_s *service = NULL; struct service_register_template_s *service_template = NULL; u8 event_level = FAULT_LEVEL_MAX; CQM_PTR_CHECK_RET(ex_handle, return event_level, CQM_PTR_NULL(ex_handle)); atomic_inc(&handle->hw_stats.cqm_stats.cqm_aeq_callback_cnt[event]); cqm_handle = (struct cqm_handle_s *)(handle->cqm_hdl); CQM_PTR_CHECK_RET(cqm_handle, return event_level, CQM_PTR_NULL(cqm_handle)); if (event >= (u8)CQM_AEQ_BASE_T_FC && (event < (u8)CQM_AEQ_BASE_T_FCOE)) { service = &cqm_handle->service; service_template = &service->service_template; if (!service_template->aeq_callback) { cqm_err(handle->dev_hdl, "Event: service aeq_callback unregistered\n"); } else { service_template->aeq_callback( service_template->service_handle, event, data); } return event_level; } cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(event)); return CQM_FAIL; } /** * cqm_service_register - Service driver registers callback template with cqm * @ex_handle: handle of hwdev * @service_template: the template of service registration */ s32 cqm_service_register(void *ex_handle, struct service_register_template_s *service_template) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; struct cqm_handle_s *cqm_handle = NULL; struct cqm_service_s *service = NULL; CQM_PTR_CHECK_RET(ex_handle, return CQM_FAIL, CQM_PTR_NULL(ex_handle)); cqm_handle = (struct cqm_handle_s *)(handle->cqm_hdl); CQM_PTR_CHECK_RET(cqm_handle, return CQM_FAIL, CQM_PTR_NULL(cqm_handle)); CQM_PTR_CHECK_RET(service_template, return CQM_FAIL, CQM_PTR_NULL(service_template)); service = &cqm_handle->service; if (service->has_register == true) { cqm_err(handle->dev_hdl, "Service register: service has registered\n"); return CQM_FAIL; } service->has_register = true; (void)memcpy((void *)(&service->service_template), (void *)service_template, sizeof(struct service_register_template_s)); return CQM_SUCCESS; } /** * cqm_service_unregister - Service-driven cancellation to CQM * @ex_handle: handle of hwdev * @service_type: the type of service module */ void cqm_service_unregister(void *ex_handle) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; struct cqm_handle_s *cqm_handle = NULL; struct cqm_service_s *service = NULL; CQM_PTR_CHECK_NO_RET(ex_handle, CQM_PTR_NULL(ex_handle), return); cqm_handle = (struct cqm_handle_s *)(handle->cqm_hdl); CQM_PTR_CHECK_NO_RET(cqm_handle, CQM_PTR_NULL(cqm_handle), return); service = &cqm_handle->service; service->has_register = false; memset(&service->service_template, 0, sizeof(struct service_register_template_s)); } /** * cqm_cmd_alloc - Apply for a cmd buffer, the buffer size is fixed at 2K, * the buffer content is not cleared, but the service needs to be cleared * @ex_handle: handle of hwdev */ struct cqm_cmd_buf_s *cqm_cmd_alloc(void *ex_handle) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; CQM_PTR_CHECK_RET(ex_handle, return NULL, CQM_PTR_NULL(ex_handle)); atomic_inc(&handle->hw_stats.cqm_stats.cqm_cmd_alloc_cnt); return (struct cqm_cmd_buf_s *)hifc_alloc_cmd_buf(ex_handle); } /** * cqm_cmd_free - Free a cmd buffer * @ex_handle: handle of hwdev * @cmd_buf: the cmd buffer which needs freeing memory for */ void cqm_cmd_free(void *ex_handle, struct cqm_cmd_buf_s *cmd_buf) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; CQM_PTR_CHECK_NO_RET(ex_handle, CQM_PTR_NULL(ex_handle), return); CQM_PTR_CHECK_NO_RET(cmd_buf, CQM_PTR_NULL(cmd_buf), return); CQM_PTR_CHECK_NO_RET(cmd_buf->buf, CQM_PTR_NULL(buf), return); atomic_inc(&handle->hw_stats.cqm_stats.cqm_cmd_free_cnt); hifc_free_cmd_buf(ex_handle, (struct hifc_cmd_buf *)cmd_buf); } /** * cqm_send_cmd_box - Send a cmd in box mode, * the interface will hang the completed amount, causing sleep * @ex_handle: handle of hwdev * @ack_type: the type of ack * @mod: the mode of cqm send * @cmd: the input cmd * @buf_in: the input buffer of cqm_cmd * @buf_out: the output buffer of cqm_cmd * @timeout: exceeding the time limit will cause sleep */ s32 cqm_send_cmd_box(void *ex_handle, u8 ack_type, u8 mod, u8 cmd, struct cqm_cmd_buf_s *buf_in, struct cqm_cmd_buf_s *buf_out, u32 timeout) { struct hifc_hwdev *handle = (struct hifc_hwdev *)ex_handle; CQM_PTR_CHECK_RET(ex_handle, return CQM_FAIL, CQM_PTR_NULL(ex_handle)); CQM_PTR_CHECK_RET(buf_in, return CQM_FAIL, CQM_PTR_NULL(buf_in)); CQM_PTR_CHECK_RET(buf_in->buf, return CQM_FAIL, CQM_PTR_NULL(buf)); atomic_inc(&handle->hw_stats.cqm_stats.cqm_send_cmd_box_cnt); return hifc_cmdq_detail_resp(ex_handle, ack_type, mod, cmd, (struct hifc_cmd_buf *)buf_in, (struct hifc_cmd_buf *)buf_out, timeout); } /** * cqm_ring_hardware_db - Knock hardware doorbell * @ex_handle: handle of hwdev * @service_type: each kernel mode will be allocated a page of hardware doorbell * @db_count: PI exceeding 64b in doorbell[7:0] * @db: doorbell content, organized by the business, * if there is a small-end conversion, the business needs to be completed */ s32 cqm_ring_hardware_db(void *ex_handle, u32 service_type, u8 db_count, u64 db) { struct hifc_hwdev *handle; struct cqm_handle_s *cqm_handle; struct cqm_service_s *service; handle = (struct hifc_hwdev *)ex_handle; cqm_handle = (struct cqm_handle_s *)(handle->cqm_hdl); service = &cqm_handle->service; /* Write all before the doorbell */ wmb(); *((u64 *)service->hardware_db_vaddr + db_count) = db; return CQM_SUCCESS; }