* 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 <unistd.h>
#include <sys/epoll.h>
#include <errno.h>
#include "ascend_hal.h"
#include "hdc_cmn.h"
#include "hdcdrv_cmd_ioctl.h"
#include "hdc_epoll.h"
STATIC struct hdc_epoll_ops *drv_hdc_epoll_get_ops(const struct hdcConfig *conf)
{
struct hdc_epoll_ops *epoll_ops = NULL;
switch (conf->trans_type) {
case HDC_TRANS_USE_PCIE:
#ifdef CFG_FEATURE_SUPPORT_UB
if (conf->h2d_type == HDC_TRANS_USE_UB) {
epoll_ops = drv_get_hdc_ub_epoll_ops();
} else if (conf->h2d_type == HDC_TRANS_USE_PCIE) {
epoll_ops = drv_get_hdc_pcie_epoll_ops();
} else {
HDC_LOG_ERR("Variable h2d_type is invalid. (h2d_type=%#x)\n", conf->h2d_type);
}
#else
epoll_ops = drv_get_hdc_pcie_epoll_ops();
#endif
break;
case HDC_TRANS_USE_SOCKET:
epoll_ops = drv_get_hdc_sock_epoll_ops();
break;
default:
HDC_LOG_ERR("Invalid trans type.%u\n", conf->trans_type);
break;
}
return epoll_ops;
}
drvError_t drvHdcEpollCreate(signed int size, HDC_EPOLL *epoll)
{
signed int ret;
struct hdc_epoll_head *epoll_head = NULL;
struct hdc_epoll_ops *epoll_ops = NULL;
if ((size <= 0) || (size > HDCDRV_EPOLL_FD_EVENT_NUM)) {
HDC_LOG_ERR("Input parameter size is error. (size=%d)\n", size);
return DRV_ERROR_INVALID_VALUE;
}
if (epoll == NULL) {
HDC_LOG_ERR("Input parameter epoll is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
}
epoll_ops = drv_hdc_epoll_get_ops(&g_hdcConfig);
if ((epoll_ops == NULL) || (epoll_ops->hdc_epoll_create == NULL)) {
HDC_LOG_ERR("get epoll object failed.\n");
ret = DRV_ERROR_MALLOC_FAIL;
goto err;
}
epoll_head = (struct hdc_epoll_head *)malloc(sizeof(struct hdc_epoll_head));
if (epoll_head == NULL) {
HDC_LOG_ERR("Call malloc failed.\n");
return DRV_ERROR_MALLOC_FAIL;
}
epoll_head->magic = HDC_MAGIC_WORD;
epoll_head->size = size;
ret = epoll_ops->hdc_epoll_create(epoll_head, size);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Epoll create error. (ret=%d)\n", ret);
goto err;
}
*epoll = (HDC_EPOLL)epoll_head;
return DRV_ERROR_NONE;
err:
free(epoll_head);
epoll_head = NULL;
return (drvError_t)ret;
}
drvError_t drvHdcEpollClose(HDC_EPOLL epoll)
{
signed int ret;
struct hdc_epoll_head *epoll_head = (struct hdc_epoll_head *)epoll;
struct hdc_epoll_ops *epoll_ops = drv_hdc_epoll_get_ops(&g_hdcConfig);
if (epoll_head == NULL) {
HDC_LOG_ERR("Input parameter epoll_head is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
}
if (epoll_head->magic != HDC_MAGIC_WORD) {
HDC_LOG_ERR("Not HDC handle. (magic=0x%x)\n", epoll_head->magic);
return DRV_ERROR_INVALID_VALUE;
}
if ((epoll_ops == NULL) || (epoll_ops->hdc_epoll_close == NULL)) {
HDC_LOG_ERR("get epoll ops object failed.\n");
return DRV_ERROR_INVALID_VALUE;
}
ret = epoll_ops->hdc_epoll_close(epoll_head);
if (ret != 0) {
HDC_LOG_ERR("Epoll free fd failed. (epfd=%d; ret=%d)\n", epoll_head->epfd, ret);
return DRV_ERROR_INNER_ERR;
}
free(epoll_head);
epoll_head = NULL;
return DRV_ERROR_NONE;
}
STATIC drvError_t drv_hdc_epoll_ctl_para_check(HDC_EPOLL epoll, signed int op, const void *target,
const struct drvHdcEvent *event)
{
struct hdc_epoll_head *epoll_head = (struct hdc_epoll_head *)epoll;
signed int epfd;
unsigned int event_mask = (HDC_EPOLL_DATA_IN | HDC_EPOLL_FAST_DATA_IN |
HDC_EPOLL_CONN_IN | HDC_EPOLL_SESSION_CLOSE);
if ((epoll_head == NULL) || (target == NULL) || (event == NULL)) {
HDC_LOG_ERR("Input parameter is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
}
if (epoll_head->magic != HDC_MAGIC_WORD) {
HDC_LOG_ERR("Not HDC handle. (magic=0x%x)\n", epoll_head->magic);
return DRV_ERROR_INVALID_VALUE;
}
epfd = (signed int)epoll_head->epfd;
if ((event->events & (HDC_EPOLL_DATA_IN | HDC_EPOLL_FAST_DATA_IN | HDC_EPOLL_SESSION_CLOSE)) &&
(event->events & HDC_EPOLL_CONN_IN)) {
HDC_LOG_ERR("Epoll conflict event. (epfd=%d; event=0x%x)\n", epfd, event->events);
return DRV_ERROR_INVALID_VALUE;
}
if ((event->events & ~event_mask) != 0) {
HDC_LOG_ERR("Input parameter events is error. (epfd=%d; event=0x%x)\n", epfd, event->events);
return DRV_ERROR_INVALID_VALUE;
}
if ((event->events & event_mask) == 0) {
HDC_LOG_ERR("Input parameter is error. (epfd=%d; event=0x%x)\n", epfd, event->events);
return DRV_ERROR_INVALID_VALUE;
}
if ((op != HDC_EPOLL_CTL_ADD) && (op != HDC_EPOLL_CTL_DEL)) {
HDC_LOG_ERR("Input parameter op is error. (epfd=%d; op=%d)\n", epfd, op);
return DRV_ERROR_INVALID_VALUE;
}
return DRV_ERROR_NONE;
}
drvError_t drvHdcEpollCtl(HDC_EPOLL epoll, signed int op, void *target, struct drvHdcEvent *event)
{
signed int ret;
struct hdc_epoll_head *epoll_head = (struct hdc_epoll_head *)epoll;
struct hdc_epoll_ops *epoll_ops = drv_hdc_epoll_get_ops(&g_hdcConfig);
if ((epoll_ops == NULL) || (epoll_ops->hdc_epoll_ctl == NULL)) {
HDC_LOG_ERR("get epoll ops object failed.\n");
return DRV_ERROR_INVALID_HANDLE;
}
ret = drv_hdc_epoll_ctl_para_check(epoll, op, target, event);
if (ret != DRV_ERROR_NONE) {
return (drvError_t)ret;
}
ret = epoll_ops->hdc_epoll_ctl(epoll_head, op, target, event);
if (ret != 0) {
HDC_LOG_ERR("Call epoll_ctl failed. (epfd=%d; op=%d; ret=%d; strerror=\"%s\"; errno=%d)\n",
epoll_head->epfd, op, ret, strerror(errno), errno);
if (ret == (-HDCDRV_SESSION_HAS_CLOSED)) {
return DRV_ERROR_SOCKET_CLOSE;
} else if (ret == (-HDCDRV_NO_PERMISSION)) {
return DRV_ERROR_OPER_NOT_PERMITTED;
} else if ((ret == (-HDCDRV_ERR)) || (ret == (-HDCDRV_PARA_ERR))) {
return DRV_ERROR_INVALID_VALUE;
} else if (ret == (-HDCDRV_DEVICE_NOT_READY)) {
return DRV_ERROR_DEVICE_NOT_READY;
}
return (drvError_t)ret;
}
return DRV_ERROR_NONE;
}
STATIC drvError_t drv_hdc_epoll_wait_para_check(HDC_EPOLL epoll, const struct drvHdcEvent *events, signed int maxevents,
signed int timeout, const signed int *eventnum)
{
struct hdc_epoll_head *epoll_head = (struct hdc_epoll_head *)epoll;
if ((epoll_head == NULL) || (events == NULL) || (eventnum == NULL)) {
HDC_LOG_ERR("Input parameter is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
}
if ((maxevents <= 0) || (maxevents > HDCDRV_EPOLL_FD_EVENT_NUM)) {
HDC_LOG_ERR("Input parameter maxevents is error. (maxevents=%d)\n", maxevents);
return DRV_ERROR_INVALID_VALUE;
}
if (epoll_head->magic != HDC_MAGIC_WORD) {
HDC_LOG_ERR("Not HDC handle. (magic=0x%x)\n", epoll_head->magic);
return DRV_ERROR_INVALID_VALUE;
}
if (epoll_head->size < maxevents) {
HDC_LOG_ERR("maxevents out of range. (epfd=%d; maxevents=%d; range=%d)\n",
(signed int)epoll_head->epfd, maxevents, epoll_head->size);
return DRV_ERROR_INVALID_VALUE;
}
if (timeout <= 0) {
HDC_LOG_ERR("Input parameter timeout is error. (epfd=%d; timeout=%d)\n", (signed int)epoll_head->epfd, timeout);
return DRV_ERROR_INVALID_VALUE;
}
return DRV_ERROR_NONE;
}
drvError_t drvHdcEpollWait(HDC_EPOLL epoll, struct drvHdcEvent *events, signed int maxevents, signed int timeout,
signed int *eventnum)
{
signed int ret;
struct hdc_epoll_head *epoll_head = (struct hdc_epoll_head *)epoll;
struct hdc_epoll_ops *epoll_ops = drv_hdc_epoll_get_ops(&g_hdcConfig);
if ((epoll_ops == NULL) || (epoll_ops->hdc_epoll_wait == NULL)) {
HDC_LOG_ERR("get epoll ops object failed.\n");
return DRV_ERROR_INVALID_VALUE;
}
ret = drv_hdc_epoll_wait_para_check(epoll, events, maxevents, timeout, eventnum);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Parameter check failed.\n");
return ret;
}
return epoll_ops->hdc_epoll_wait(epoll_head, events, maxevents, timeout, eventnum);
}