* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include "mmpa_api.h"
#include "ascend_hal.h"
#include "hdc_cmn.h"
#include "hdcdrv_cmd_ioctl.h"
#include "hdc_pcie_drv.h"
#include "hdc_ub_drv.h"
#include "hdc_client.h"
#include "hdc_adapt.h"
#include "hdc_core.h"
STATIC hdcError_t drv_hdc_client_create_para_checker(const HDC_CLIENT *pClient, signed int maxSessionNum,
signed int serviceType, signed int flag)
{
signed int max_session_num_by_type;
if (pClient == NULL) {
HDC_LOG_ERR("Input parameter pClient is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
}
max_session_num_by_type = drv_hdc_get_max_session_num_by_type(serviceType);
if ((maxSessionNum <= 0) || (maxSessionNum > max_session_num_by_type)) {
HDC_LOG_ERR("Input parameter maxSessionNum is error. (maxSessionNum=%d)\n", maxSessionNum);
return DRV_ERROR_INVALID_VALUE;
}
if ((serviceType >= HDC_SERVICE_TYPE_MAX) || (serviceType < 0)) {
HDC_LOG_ERR("Input parameter serviceType is error. (serviceType=%d)\n", serviceType);
return DRV_ERROR_INVALID_VALUE;
}
if ((flag < 0) || (flag > HDC_SESSION_CONN_TIMEOUT)) {
HDC_LOG_ERR("Input parameter flag is error. (flag=%d).\n", flag);
return DRV_ERROR_INVALID_VALUE;
}
return DRV_ERROR_NONE;
}
Function Name : drvHdcClientCreate
Function Description : Create an HDC client and initialize it based on the maximum number of sessions and service type
Input Parameters : int maxSessionNum The maximum number of sessions currently required by Client
int serviceType select service type
int flag Reserved parameters, [bit0 - bit7] session connect timeout, other fixed to 0
Output Parameters : HDC_CLIENT *client Created HDC Client pointer
Return Value : DRV_ERROR_NONE
DRV_ERROR_INVALID_VALUE
Caller Function :
Called Function :
Modification History :
1.Date : January 15, 2018
Modification : New generated function
*****************************************************************************/
hdcError_t drvHdcClientCreate(HDC_CLIENT *client, signed int maxSessionNum, signed int serviceType, signed int flag)
{
struct hdc_client_session *pSession = NULL;
struct hdc_client_head *pHead = NULL;
size_t size;
signed int cnt;
if (drv_hdc_client_create_para_checker(client, maxSessionNum, serviceType, flag) != DRV_ERROR_NONE) {
return DRV_ERROR_INVALID_VALUE;
}
size = sizeof(struct hdc_client_session) * (size_t)maxSessionNum + sizeof(struct hdc_client_head);
pHead = (struct hdc_client_head *)drv_hdc_zalloc(size);
if (pHead == NULL) {
HDC_LOG_ERR("Call malloc failed.\n");
return DRV_ERROR_OUT_OF_MEMORY;
}
pHead->serviceType = serviceType;
pHead->magic = HDC_MAGIC_WORD;
pHead->flag = (unsigned int)((flag == 0) ? HDC_SESSION_CONN_TIMEOUT : flag);
pHead->maxSessionNum = (unsigned int)maxSessionNum;
(void)mmMutexInit(&pHead->mutex);
pSession = pHead->session;
for (cnt = 0; cnt < maxSessionNum; cnt++) {
pSession[cnt].session.magic = HDC_MAGIC_WORD;
pSession[cnt].session.sockfd = -1;
pSession[cnt].session.bind_fd = HDC_SESSION_FD_INVALID;
pSession[cnt].alloc = false;
pSession[cnt].node = -1;
pSession[cnt].devid = -1;
}
*client = (HDC_CLIENT)pHead;
HDC_LOG_DEBUG("Create client success.\n");
return DRV_ERROR_NONE;
}
Function Name : drvHdcClientDestroy
Function Description : Release HDC Client
Input Parameters : HDC_CLIENT client HDC Client to be released
Output Parameters : None
Return Value : DRV_ERROR_NONE
DRV_ERROR_INVALID_VALUE
DRV_ERROR_CLIENT_BUSY
Caller Function :
Called Function :
Modification History :
1.Date : January 15, 2018
Modification : New generated function
*****************************************************************************/
hdcError_t drvHdcClientDestroy(HDC_CLIENT client)
{
struct hdc_client_head *pHead = NULL;
struct hdc_client_session *pSession = NULL;
bool alive = false;
unsigned int maxSessionNum;
unsigned int cnt;
signed int ret;
if (client == NULL) {
HDC_LOG_ERR("Input parameter client is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
}
pHead = (struct hdc_client_head *)client;
if (pHead->magic != HDC_MAGIC_WORD) {
HDC_LOG_ERR("Variable pHead_magic is invalid. (pHead_magic=%#x)\n", pHead->magic);
return DRV_ERROR_INVALID_VALUE;
}
if ((pHead->maxSessionNum <= 0) || (pHead->maxSessionNum > HDCDRV_SUPPORT_MAX_SESSION)) {
HDC_LOG_ERR("Input parameter maxSessionNum is error. (maxSessionNum=%u)\n", pHead->maxSessionNum);
return DRV_ERROR_INVALID_VALUE;
}
maxSessionNum = pHead->maxSessionNum;
pSession = pHead->session;
(void)mmMutexLock(&pHead->mutex);
for (cnt = 0; cnt < maxSessionNum; cnt++) {
if (pSession[cnt].session.sockfd != -1) {
alive = true;
HDC_LOG_WARN("Session still alive. (session=%u)\n", pSession[cnt].session.sockfd);
}
}
if (alive) {
(void)mmMutexUnLock(&pHead->mutex);
HDC_LOG_WARN("Must close session before destroy client, serviceType %d.\n", pHead->serviceType);
return DRV_ERROR_CLIENT_BUSY;
}
(void)mmMutexUnLock(&pHead->mutex);
if (g_hdcConfig.trans_type == HDC_TRANS_USE_PCIE) {
if ((ret = hdc_pcie_client_destroy(g_hdcConfig.pcie_handle, 0, pHead->serviceType)) != 0) {
HDC_LOG_WARN("Destroy pcie client not success. (errno=%d)\n", ret);
}
}
(void)mmMutexDestroy(&pHead->mutex);
pHead->magic = 0;
free(client);
pHead = NULL;
HDC_LOG_DEBUG("Destroy client.\n");
return DRV_ERROR_NONE;
}
Function Name : drv_hdc_client_alloc_session
Function Description : Find an available Session
Input Parameters : struct hdc_client_head
Output Parameters : struct hdc_client_session **ppSession
Return Value :
Caller Function :
Called Function :
Modification History :
1.Date : January 16, 2018
Modification : New generated function
*****************************************************************************/
STATIC bool drv_hdc_client_alloc_session(struct hdc_client_head *pHead, struct hdc_client_session **ppSession)
{
struct hdc_client_session *pSession = NULL;
unsigned int maxSessionNum;
unsigned int cnt;
maxSessionNum = (unsigned int)drv_hdc_get_max_session_num_by_type(pHead->serviceType);
if ((pHead->maxSessionNum <= 0) || (pHead->maxSessionNum > maxSessionNum)) {
HDC_LOG_ERR("Input parameter maxSessionNum is error. (maxSessionNum=%u)\n", pHead->maxSessionNum);
return false;
}
(void)mmMutexLock(&pHead->mutex);
pSession = pHead->session;
maxSessionNum = pHead->maxSessionNum;
for (cnt = 0; cnt < maxSessionNum; cnt++) {
if (!(pSession[cnt].alloc)) {
pSession[cnt].alloc = true;
pSession[cnt].session.sockfd = -1;
pSession[cnt].session.bind_fd = HDC_SESSION_FD_INVALID;
#ifdef CFG_FEATURE_SUPPORT_UB
pSession[cnt].session.close_eventfd = -1;
pSession[cnt].session.epoll_head = NULL;
#endif
break;
}
}
if (cnt == maxSessionNum) {
(void)mmMutexUnLock(&pHead->mutex);
HDC_LOG_ERR("No free session.\n");
return false;
}
*ppSession = &pSession[cnt];
(void)mmMutexUnLock(&pHead->mutex);
HDC_LOG_DEBUG("Client alloc session success.\n");
return true;
}
Function Name : drv_hdc_client_free_session
Function Description : Release Client-side Session
Input Parameters : struct hdc_client_session *pSession
Output Parameters : None
Return Value :
Caller Function :
Called Function :
Modification History :
1.Date : January 17, 2018
Modification : New generated function
*****************************************************************************/
STATIC void drv_hdc_client_free_session(struct hdc_client_head *pHead, struct hdc_client_session *pSession)
{
(void)mmMutexLock(&pHead->mutex);
pSession->alloc = false;
pSession->session.sockfd = -1;
(void)mmMutexUnLock(&pHead->mutex);
HDC_LOG_DEBUG("Client free session.\n");
return;
}
STATIC hdcError_t drv_hdc_connect_para_check(signed int peer_node, signed int peer_devid,
const struct hdc_client_head *pHead, const HDC_SESSION *pSession)
{
if (peer_node != 0) {
HDC_LOG_ERR("Input parameter peer_node is error.\n");
return DRV_ERROR_INVALID_VALUE;
}
if (pHead == NULL) {
HDC_LOG_ERR("Input parameter pHead is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
}
if (pSession == NULL) {
HDC_LOG_ERR("Input parameter pSession is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
}
if ((peer_devid >= hdc_get_max_device_num()) || (peer_devid < 0)) {
HDC_LOG_ERR("Input parameter peer_devid is error. (dev_id=%d)\n", peer_devid);
return DRV_ERROR_INVALID_DEVICE;
}
if (pHead->magic != HDC_MAGIC_WORD) {
HDC_LOG_ERR("Input parameter magic is error. (pHead_magic=%#x)\n", pHead->magic);
return DRV_ERROR_INVALID_VALUE;
}
return DRV_ERROR_NONE;
}
hdcError_t halHdcSessionConnectEx(int peer_node, int peer_devid, int peer_pid, HDC_CLIENT client,
HDC_SESSION *pSession)
{
struct hdc_client_head *pHead = (struct hdc_client_head *)client;
struct hdc_client_session *p_client_session = NULL;
struct hdc_client_session *p_client_session_ppc = NULL;
bool result = false;
hdcError_t err_code;
signed int ret;
err_code = drv_hdc_connect_para_check(peer_node, peer_devid, pHead, pSession);
if (err_code != DRV_ERROR_NONE) {
return err_code;
}
result = drv_hdc_client_alloc_session(pHead, &p_client_session);
if ((!result) || (p_client_session == NULL)) {
HDC_LOG_ERR("No available session.\n");
return DRV_ERROR_OVER_LIMIT;
}
if (g_hdcConfig.trans_type == HDC_TRANS_USE_PCIE) {
if (g_hdcConfig.h2d_type == HDC_TRANS_USE_UB) {
ret = hdc_ub_connect(peer_devid, pHead, peer_pid, &p_client_session->session);
} else if (g_hdcConfig.h2d_type == HDC_TRANS_USE_PCIE) {
ret = hdc_pcie_connect(g_hdcConfig.pcie_handle, peer_devid, pHead->serviceType, pHead->flag, peer_pid,
&p_client_session->session);
} else {
HDC_LOG_ERR("Variable h2d_type is invalid. (h2d_type=%#x)\n", g_hdcConfig.h2d_type);
ret = DRV_ERROR_INVALID_HANDLE;
}
if (ret != 0) {
drv_hdc_client_free_session(pHead, p_client_session);
if (ret == -HDCDRV_PEER_REBOOT) {
return DRV_ERROR_DEV_PROCESS_HANG;
}
if (ret == (-HDCDRV_REMOTE_SERVICE_NO_LISTENING)) {
return DRV_ERROR_REMOTE_NOT_LISTEN;
}
if (ret == (-HDCDRV_NO_SESSION)) {
return DRV_ERROR_REMOTE_NO_SESSION;
}
if (ret == (-HDCDRV_DEVICE_NOT_READY)) {
return DRV_ERROR_DEVICE_NOT_READY;
}
if (ret == (-HDCDRV_SESSION_CHAN_INVALID)) {
return DRV_ERROR_SOCKET_CONNECT;
}
if (ret == (-HDCDRV_CONNECT_TIMEOUT)) {
return DRV_ERROR_WAIT_TIMEOUT;
}
if (ret == (-HDCDRV_SESSION_HAS_CLOSED)) {
return DRV_ERROR_SOCKET_CLOSE;
}
if (ret == (-HDCDRV_SEND_CTRL_MSG_FAIL)) {
return DRV_ERROR_NO_DEVICE;
}
return (hdcError_t)ret;
}
} else {
err_code = drv_hdc_socket_session_connect(peer_devid, pHead->serviceType, (HDC_SESSION *)(&p_client_session_ppc));
if (err_code != DRV_ERROR_NONE) {
drv_hdc_client_free_session(pHead, p_client_session);
HDC_LOG_WARN("PPC client session connect not success. (err_code=%d)\n", (signed int)err_code);
return DRV_ERROR_SOCKET_CONNECT;
}
p_client_session->session.magic = p_client_session_ppc->session.magic;
p_client_session->session.sockfd = p_client_session_ppc->session.sockfd;
free(p_client_session_ppc);
p_client_session_ppc = NULL;
}
p_client_session->session.type = HDC_SESSION_CLINET;
p_client_session->node = peer_node;
p_client_session->devid = peer_devid;
p_client_session->client = pHead;
*pSession = (HDC_SESSION)p_client_session;
return DRV_ERROR_NONE;
}
Function Name : drvHdcSessionConnect
Function Description : Create HDC Session for Host and Device communication
Input Parameters : signed int peer_node The node number of the node where the Device is located. Currently
only 1 node is supported. Remote nodes are not supported. You need
to pass a fixed value of 0
signed int peer_devid Device's uniform ID in the host (number in each node)
HDC_CLIENT client HDC Client handle corresponding to the newly created Session
Output Parameters : HDC_SESSION *session Created session
Return Value : DRV_ERROR_NONE
DRV_ERROR_INVALID_VALUE
Caller Function :
Called Function :
Modification History :
1.Date : January 15, 2018
Modification : New generated function
*****************************************************************************/
hdcError_t drvHdcSessionConnect(int peer_node, int peer_devid, HDC_CLIENT client, HDC_SESSION *session)
{
return halHdcSessionConnectEx(peer_node, peer_devid, HDCDRV_INVALID_PEER_PID, client, session);
}
Function Name : drv_hdc_client_session_close
Function Description : Release HDC Session
Input Parameters : HDC_SESSION session The session to be released
Output Parameters : None
Return Value : DRV_ERROR_NONE
DRV_ERROR_INVALID_VALUE
Caller Function :
Called Function :
Modification History :
1.Date : January 15, 2018
Modification : New generated function
*****************************************************************************/
hdcError_t drv_hdc_client_session_close(HDC_SESSION session, int close_state, int flag)
{
struct hdc_client_session *p_client_session = NULL;
struct hdc_client_head *pHead = NULL;
signed int ret;
p_client_session = (struct hdc_client_session *)session;
if (!(p_client_session->alloc)) {
HDC_LOG_ERR("Parameter alloc is error. (alloc=%d)\n", (signed int)p_client_session->alloc);
return DRV_ERROR_INVALID_VALUE;
}
if (p_client_session->client == NULL) {
HDC_LOG_ERR("Parameter client is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
}
HDC_LOG_INFO("Destroy client session. (sock=%d)\n", p_client_session->session.sockfd);
if (g_hdcConfig.trans_type == HDC_TRANS_USE_PCIE) {
if (g_hdcConfig.h2d_type == HDC_TRANS_USE_UB) {
ret = hdc_ub_session_close((unsigned int)p_client_session->devid, &p_client_session->session, close_state, flag);
} else if (g_hdcConfig.h2d_type == HDC_TRANS_USE_PCIE) {
ret = hdc_pcie_close(g_hdcConfig.pcie_handle, (unsigned int)p_client_session->devid, &p_client_session->session);
} else {
HDC_LOG_ERR("Variable h2d_type is invalid. (h2d_type=%#x)\n", g_hdcConfig.h2d_type);
ret = DRV_ERROR_INVALID_HANDLE;
}
if (ret != 0) {
HDC_LOG_WARN("Close device not success. (device=%d; errno=%d)\n", (signed int)(p_client_session->devid), ret);
}
if (g_hdcConfig.h2d_type == HDC_TRANS_USE_UB) {
hdc_link_event_pre_uninit(p_client_session->devid, false);
}
hdc_pcie_close_bind_fd(p_client_session->session.bind_fd);
p_client_session->session.bind_fd = HDC_SESSION_FD_INVALID;
} else {
(void)shutdown(p_client_session->session.sockfd, SHUT_RDWR);
(void)mm_close_socket(p_client_session->session.sockfd);
}
pHead = p_client_session->client;
drv_hdc_client_free_session(pHead, p_client_session);
return DRV_ERROR_NONE;
}