* 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_server.h"
#include "hdc_core.h"
STATIC void drv_hdc_preset_session_init(struct hdc_server_head *pHead, int session_num)
{
#ifdef CFG_FEATURE_PRESET_SESSION
int i;
for (i = 0; i < session_num; ++i) {
pHead->session[i].alloc = false;
pHead->session[i].session.magic = HDC_MAGIC_WORD;
pHead->session[i].session.sockfd = -1;
pHead->session[i].session.bind_fd = HDC_SESSION_FD_INVALID;
}
#else
(void)pHead;
(void)session_num;
#endif
}
STATIC hdcError_t drv_hdc_pcie_server_create(signed int devid, signed int serviceType, HDC_SERVER *pServer)
{
struct hdc_server_head *pHead = NULL;
mmProcess fd;
signed int ret;
unsigned int grpId;
unsigned int session_size = 0;
int session_num = drv_hdc_get_max_session_num_by_type(serviceType);
#ifdef CFG_FEATURE_PRESET_SESSION
session_size = (unsigned int)session_num * (unsigned int)sizeof(struct hdc_server_session);
#endif
pHead = malloc(sizeof(struct hdc_server_head) + session_size);
if (pHead == NULL) {
HDC_LOG_ERR("Call malloc failed.\n");
return DRV_ERROR_OUT_OF_MEMORY;
}
pHead->serviceType = serviceType;
if (g_hdcConfig.h2d_type == HDC_TRANS_USE_PCIE) {
ret = hdc_pcie_set_service_level(g_hdcConfig.pcie_handle, serviceType);
if (ret != DRV_ERROR_NONE) {
free(pHead);
pHead = NULL;
HDC_LOG_ERR("HDC init, set service level failed. (errno=%d)\n", ret);
if (ret == (-HDCDRV_DEVICE_NOT_READY)) {
return DRV_ERROR_DEVICE_NOT_READY;
}
return DRV_ERROR_IOCRL_FAIL;
}
}
fd = hdc_pcie_create_bind_fd();
if (fd == (mmProcess)EN_ERROR) {
free(pHead);
pHead = NULL;
HDC_LOG_ERR("Server create open pcie device failed. (strerror=\"%s\")\n", strerror(errno));
return DRV_ERROR_INVALID_HANDLE;
}
if (g_hdcConfig.h2d_type == HDC_TRANS_USE_UB) {
ret = hdc_ub_server_create(fd, devid, serviceType, &grpId, pHead);
} else if (g_hdcConfig.h2d_type == HDC_TRANS_USE_PCIE) {
ret = hdc_pcie_server_create(fd, devid, serviceType);
} else {
HDC_LOG_ERR("Variable h2d_type is invalid. (h2d_type=%#x)\n", g_hdcConfig.h2d_type);
ret = DRV_ERROR_INVALID_HANDLE;
}
if (ret != DRV_ERROR_NONE) {
free(pHead);
pHead = NULL;
hdc_pcie_close_bind_fd(fd);
fd = HDC_SESSION_FD_INVALID;
if (ret == (-HDCDRV_DEVICE_NOT_READY)) {
return DRV_ERROR_DEVICE_NOT_READY;
} else if (ret == (-HDCDRV_SERVICE_LISTENING)) {
HDC_LOG_WARN("Server has already been created. (listen_device=%d, serviceType=%d) \n", devid, serviceType);
return DRV_ERROR_SERVER_HAS_BEEN_CREATED;
} else {
HDC_LOG_ERR("Create server failed. (listen_device=%d; ret=%d) \n", devid, ret);
return DRV_ERROR_SERVER_CREATE_FAIL;
}
}
pHead->bind_fd = fd;
pHead->listenFd = devid;
drv_hdc_preset_session_init(pHead, session_num);
*pServer = (HDC_SERVER)pHead;
return DRV_ERROR_NONE;
}
#ifdef CFG_FEATURE_PRESET_SESSION
STATIC void drv_hdc_server_alloc_session(struct hdc_server_head *pServ, struct hdc_server_session **pp_serv_session)
{
int session_num = drv_hdc_get_max_session_num_by_type(pServ->serviceType);
struct hdc_server_session *pSession = NULL;
int i = 0;
*pp_serv_session = NULL;
(void)mmMutexLock(&pServ->mutex);
pSession = pServ->session;
for (i = 0; i < session_num; ++i) {
if (!pSession[i].alloc) {
pSession[i].alloc = true;
break;
}
}
(void)mmMutexUnLock(&pServ->mutex);
if (i == session_num) {
HDC_LOG_ERR("no free server session.\n");
return;
}
*pp_serv_session = &pSession[i];
return;
}
STATIC void drv_hdc_server_free_session(struct hdc_server_head *pServ, struct hdc_server_session *p_serv_session)
{
(void)mmMutexLock(&pServ->mutex);
p_serv_session->alloc = false;
p_serv_session->session.sockfd = -1;
(void)mmMutexUnLock(&pServ->mutex);
}
#endif
STATIC hdcError_t drv_hdc_pcie_session_accept(HDC_SERVER server, HDC_SESSION *pSession)
{
struct hdc_server_head *pServ = NULL;
struct hdc_server_session *p_serv_session = NULL;
signed int ret, deviceId, serviceType;
struct hdc_session *session = NULL;
pServ = (struct hdc_server_head *)server;
deviceId = pServ->deviceId;
serviceType = pServ->serviceType;
#ifdef CFG_FEATURE_PRESET_SESSION
drv_hdc_server_alloc_session(pServ, &p_serv_session);
#else
p_serv_session = (struct hdc_server_session *)drv_hdc_zalloc(sizeof(struct hdc_server_session));
#endif
if (p_serv_session == NULL) {
HDC_LOG_ERR("Call malloc failed.\n");
return DRV_ERROR_OUT_OF_MEMORY;
}
session = &p_serv_session->session;
session->bind_fd = HDC_SESSION_FD_INVALID;
if (g_hdcConfig.h2d_type == HDC_TRANS_USE_UB) {
ret = hdc_ub_accept(pServ, deviceId, serviceType, &p_serv_session->session);
} else if (g_hdcConfig.h2d_type == HDC_TRANS_USE_PCIE) {
ret = hdc_pcie_accept(g_hdcConfig.pcie_handle, deviceId, serviceType, &p_serv_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 != DRV_ERROR_NONE) {
#ifdef CFG_FEATURE_PRESET_SESSION
drv_hdc_server_free_session(pServ, p_serv_session);
#else
free(p_serv_session);
p_serv_session = NULL;
#endif
if (ret == -HDCDRV_PEER_REBOOT) {
HDC_LOG_INFO("peer reset. (dev_id=%d; server=%d; ret=%d)\n",
pServ->deviceId, pServ->serviceType, ret);
return DRV_ERROR_DEV_PROCESS_HANG;
}
if (ret == -HDCDRV_DEVICE_RESET) {
HDC_LOG_INFO("Server is destroyed or wakeup wait. (dev_id=%d; server=%d; ret=%d)\n",
pServ->deviceId, pServ->serviceType, ret);
return DRV_ERROR_DEVICE_NOT_READY;
}
if (ret == -HDCDRV_DEVICE_NOT_READY) {
HDC_LOG_RUN_INFO_LIMIT("Dev not ready or has been freed. (dev_id=%d; server=%d; ret=%d)\n",
pServ->deviceId, pServ->serviceType, ret);
} else {
HDC_LOG_ERR("Accept failed. (dev_id=%d; server=%d; ret=%d)\n", pServ->deviceId, pServ->serviceType, ret);
}
return DRV_ERROR_SOCKET_ACCEPT;
}
*pSession = p_serv_session;
return DRV_ERROR_NONE;
}
STATIC hdcError_t drv_hdc_server_create_para_check(signed int devid, signed int serviceType, const HDC_SERVER *pServer)
{
if ((devid >= hdc_get_max_device_num()) || (devid < 0)) {
HDC_LOG_ERR("Input parameter is error. (dev_id=%d)\n", devid);
return DRV_ERROR_INVALID_DEVICE;
}
if (pServer == NULL) {
HDC_LOG_ERR("Input parameter is error.\n");
return DRV_ERROR_INVALID_VALUE;
}
if ((serviceType < 0) || (serviceType >= HDC_SERVICE_TYPE_MAX)) {
HDC_LOG_ERR("Input parameter is error. (service_type=%d)\n", serviceType);
return DRV_ERROR_INVALID_VALUE;
}
return DRV_ERROR_NONE;
}
Function Name : drvHdcServerCreate
Function Description : Create and initialize HDC Server
Input Parameters : signed int devid only support [0, 64)
signed int serviceType select server type
Output Parameters : HDC_SERVER *server Created HDC server
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 drvHdcServerCreate(signed int devid, signed int serviceType, HDC_SERVER *pServer)
{
struct hdc_server_head *pHead = NULL;
hdcError_t ret;
ret = drv_hdc_server_create_para_check(devid, serviceType, pServer);
if (ret != DRV_ERROR_NONE) {
return ret;
}
if (g_hdcConfig.trans_type == HDC_TRANS_USE_PCIE) {
ret = drv_hdc_pcie_server_create(devid, serviceType, (HDC_SERVER *)(&pHead));
if (ret != DRV_ERROR_NONE) {
return ret;
}
HDC_LOG_INFO("Create server success. (listen_device=%d)\n", devid);
} else {
ret = drv_hdc_socket_server_create(devid, serviceType, (PPC_SERVER *)(&pHead));
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Ppc server create failed. (errno=%d)\n", ret);
return DRV_ERROR_SERVER_CREATE_FAIL;
}
HDC_LOG_INFO("Create ppc server success. (service_type=%d) \n", serviceType);
}
pHead->serviceType = serviceType;
pHead->magic = HDC_MAGIC_WORD;
pHead->session_num = 0;
pHead->deviceId = devid;
(void)mmMutexInit(&pHead->mutex);
*pServer = (HDC_SERVER)pHead;
return DRV_ERROR_NONE;
}
Function Name : drvHdcServerDestroy
Function Description : Release HDC Server
Input Parameters : HDC_SERVER server HDC server 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 drvHdcServerDestroy(HDC_SERVER server)
{
signed int ret;
struct hdc_server_head *pServ = NULL;
unsigned int session_num;
mmSockHandle listenFd;
int retry_time = 0;
if (server == NULL) {
HDC_LOG_ERR("Input parameter server is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
}
pServ = (struct hdc_server_head *)server;
if ((pServ->deviceId >= hdc_get_max_device_num()) || (pServ->deviceId < 0)) {
HDC_LOG_ERR("Input parameter deviceId is error. (deviceId=%d)\n", pServ->deviceId);
return DRV_ERROR_INVALID_DEVICE;
}
if (pServ->magic != HDC_MAGIC_WORD) {
HDC_LOG_ERR("Input parameter magic is error. (magic=%#x)\n", pServ->magic);
return DRV_ERROR_INVALID_VALUE;
}
(void)mmMutexLock(&pServ->mutex);
session_num = pServ->session_num;
if (session_num > 0) {
(void)mmMutexUnLock(&pServ->mutex);
HDC_LOG_WARN("Destroy server not success, there have session alive. (session_num=%d)\n", session_num);
return DRV_ERROR_SERVER_BUSY;
}
(void)mmMutexUnLock(&pServ->mutex);
if (g_hdcConfig.trans_type == HDC_TRANS_USE_PCIE) {
if (g_hdcConfig.h2d_type == HDC_TRANS_USE_UB) {
ret = hdc_ub_server_destroy(pServ, pServ->deviceId, pServ->serviceType);
} else if (g_hdcConfig.h2d_type == HDC_TRANS_USE_PCIE) {
ret = hdc_pcie_server_destroy(pServ->bind_fd, pServ->deviceId, pServ->serviceType);
} 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("Destroy pcie server not success. (dev_id=%d; errno=%d)\n", pServ->deviceId, ret);
}
if (g_hdcConfig.h2d_type == HDC_TRANS_USE_UB) {
hdc_link_event_pre_uninit(pServ->deviceId, true);
}
hdc_pcie_close_bind_fd(pServ->bind_fd);
pServ->bind_fd = HDC_SESSION_FD_INVALID;
} else {
listenFd = pServ->listenFd;
pServ->listenFd = -1;
wmb();
(void)shutdown(listenFd, SHUT_RDWR);
(void)mm_close_socket(listenFd);
while ((pServ->accept_wait == HDC_ACCEPT_WAITING) && (retry_time < HDC_SOCKET_MAX_RETRY_TIMES)) {
usleep(HDC_SERVER_DESTORY_WAIT_TIME_US);
retry_time++;
}
if (retry_time == HDC_SOCKET_MAX_RETRY_TIMES) {
HDC_LOG_ERR("Accept exit timeout. listenFd = %d\n", listenFd);
}
}
HDC_LOG_INFO("Destroy server success. (deviceId=%d; service_Type=%d)\n", pServ->deviceId, pServ->serviceType);
(void)mmMutexDestroy(&pServ->mutex);
pServ->magic = 0;
free(pServ);
pServ = NULL;
return DRV_ERROR_NONE;
}
hdcError_t drv_hdc_get_server_dev_id(HDC_SERVER server, signed int *devid)
{
struct hdc_server_head *pServ = NULL;
if ((server == NULL) || (devid == NULL)) {
HDC_LOG_ERR("Input parameter server or devid is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
}
pServ = (struct hdc_server_head *)server;
if ((pServ->deviceId >= hdc_get_max_device_num()) || (pServ->deviceId < 0)) {
HDC_LOG_ERR("Input parameter deviceId is error. (deviceId=%d)\n", pServ->deviceId);
return DRV_ERROR_INVALID_DEVICE;
}
if (pServ->magic != HDC_MAGIC_WORD) {
HDC_LOG_ERR("Input parameter magic is error. (magic=%#x)\n", pServ->magic);
return DRV_ERROR_INVALID_VALUE;
}
*devid = pServ->deviceId;
return DRV_ERROR_NONE;
}
Function Name : drvHdcSessionAccept
Function Description : Open HDC Session for communication between Host and Device
Input Parameters : HDC_SERVER server HDC server to which the newly created session belongs
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 drvHdcSessionAccept(HDC_SERVER server, HDC_SESSION *session)
{
struct hdc_server_head *pServ = NULL;
struct hdc_server_session *p_serv_session = NULL;
signed int ret = DRV_ERROR_NONE;
if ((server == NULL) || (session == NULL)) {
HDC_LOG_ERR("Input parameter server or session is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
}
pServ = (struct hdc_server_head *)server;
if ((pServ->deviceId >= hdc_get_max_device_num()) || (pServ->deviceId < 0)) {
HDC_LOG_ERR("Input parameter deviceId is error. (deviceId=%d)\n", pServ->deviceId);
return DRV_ERROR_INVALID_DEVICE;
}
if (pServ->magic != HDC_MAGIC_WORD) {
HDC_LOG_ERR("Input parameter magic is error. (magic=%#x)\n", pServ->magic);
return DRV_ERROR_INVALID_VALUE;
}
if (g_hdcConfig.trans_type == HDC_TRANS_USE_PCIE) {
ret = drv_hdc_pcie_session_accept((HDC_SERVER)pServ, (HDC_SESSION *)(&p_serv_session));
if (ret != DRV_ERROR_NONE) {
return ret;
}
} else {
ret = drv_hdc_socket_session_accept((PPC_SERVER)pServ, (PPC_SESSION *)(&p_serv_session));
if (ret != DRV_ERROR_NONE) {
if (ret == DRV_ERROR_SOCKET_CLOSE) {
HDC_LOG_WARN("PPC server session accept exited. (errno=%d)\n", ret);
} else {
HDC_LOG_ERR("PPC server session accept failed. (errno=%d)\n", ret);
}
return DRV_ERROR_SOCKET_ACCEPT;
}
}
p_serv_session->session.magic = HDC_MAGIC_WORD;
p_serv_session->deviceId = (unsigned int)pServ->deviceId;
p_serv_session->session.type = HDC_SESSION_SERVER;
p_serv_session->server = pServ;
(void)mmMutexLock(&pServ->mutex);
pServ->session_num++;
(void)mmMutexUnLock(&pServ->mutex);
*session = (HDC_SESSION)p_serv_session;
HDC_LOG_DEBUG("Add server session. (sockfd=%d)\n", p_serv_session->session.sockfd);
return DRV_ERROR_NONE;
}
Function Name : drv_hdc_server_session_close
Description : Close HDC Session
Input Parameters : HDC_SESSION session The session to be closed
Output Parameters : None
Return Value : DRV_ERROR_NONE
DRV_ERROR_INVALID_VALUE
Called Functions :
Calling Functions :
Modification History:
1.Date : January 15, 2018
Modification : Function newly created
*****************************************************************************/
hdcError_t drv_hdc_server_session_close(HDC_SESSION session, int close_state, int flag)
{
struct hdc_server_head *pServ = NULL;
struct hdc_server_session *p_serv_session = NULL;
signed int ret;
p_serv_session = (struct hdc_server_session *)session;
if (p_serv_session->deviceId >= (unsigned int)hdc_get_max_device_num()) {
HDC_LOG_ERR("Input parameter deviceId is error. (deviceId=%#x)\n", p_serv_session->deviceId);
return DRV_ERROR_INVALID_VALUE;
}
HDC_LOG_INFO("Close server session. (sockfd=%d)\n", p_serv_session->session.sockfd);
if (g_hdcConfig.trans_type == HDC_TRANS_USE_PCIE) {
#ifdef CFG_FEATURE_PRESET_SESSION
if (!p_serv_session->alloc) {
HDC_LOG_ERR("Parameter alloc is error. (alloc=%d)\n", (signed int)p_serv_session->alloc);
return DRV_ERROR_INVALID_VALUE;
}
#endif
if (g_hdcConfig.h2d_type == HDC_TRANS_USE_UB) {
ret = hdc_ub_session_close(p_serv_session->deviceId, &p_serv_session->session, close_state, flag);
} else if (g_hdcConfig.h2d_type == HDC_TRANS_USE_PCIE) {
ret = hdc_pcie_close(g_hdcConfig.pcie_handle, p_serv_session->deviceId, &p_serv_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 pcie session not success. (device=%d; sessiondID=%d; errno=%d)\n",
p_serv_session->deviceId, p_serv_session->session.sockfd, ret);
}
if (g_hdcConfig.h2d_type != HDC_TRANS_USE_UB) {
hdc_pcie_close_bind_fd(p_serv_session->session.bind_fd);
p_serv_session->session.bind_fd = HDC_SESSION_FD_INVALID;
}
} else {
(void)shutdown(p_serv_session->session.sockfd, SHUT_RDWR);
(void)mm_close_socket(p_serv_session->session.sockfd);
}
pServ = p_serv_session->server;
(void)mmMutexLock(&pServ->mutex);
pServ->session_num--;
(void)mmMutexUnLock(&pServ->mutex);
#ifdef CFG_FEATURE_PRESET_SESSION
if (g_hdcConfig.trans_type == HDC_TRANS_USE_PCIE) {
drv_hdc_server_free_session(pServ, p_serv_session);
return DRV_ERROR_NONE;
}
#endif
p_serv_session->session.magic = 0;
free(p_serv_session);
p_serv_session = NULL;
return DRV_ERROR_NONE;
}