* osal_thread.c
*
* osal driver
*
* Copyright (c) 2020-2021 Huawei Device Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "osal_thread.h"
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/string.h>
#include <linux/types.h>
#include <uapi/linux/sched.h>
#include <uapi/linux/sched/types.h>
#include "hdf_log.h"
#include "osal_mem.h"
#include "securec.h"
#define HDF_LOG_TAG osal_thread
#define OSAL_INVALID_CPU_ID UINT_MAX
struct thread_wrapper {
OsalThreadEntry thread_entry;
void *entry_para;
struct task_struct *task;
uint32_t cpu_id;
};
enum {
OSAL_PRIORITY_MIDDLE = 50,
OSAL_PRIORITY_HIGH = 90,
OSAL_PRIORITY_HIGHEST = 99,
};
static int osal_thread_entry(void *para)
{
int ret = -1;
struct thread_wrapper *wrapper = (struct thread_wrapper *)para;
if (wrapper == NULL || wrapper->thread_entry == NULL) {
HDF_LOGE("%s invalid param", __func__);
} else {
ret = wrapper->thread_entry(wrapper->entry_para);
}
do_exit(ret);
return ret;
}
int32_t OsalThreadCreate(struct OsalThread *thread, OsalThreadEntry thread_entry, void *entry_para)
{
struct thread_wrapper *wrapper = NULL;
if (thread == NULL || thread_entry == NULL) {
HDF_LOGE("%s invalid param", __func__);
return HDF_ERR_INVALID_PARAM;
}
thread->realThread = NULL;
wrapper = (struct thread_wrapper *)OsalMemCalloc(sizeof(*wrapper));
if (wrapper == NULL) {
HDF_LOGE("%s malloc fail", __func__);
return HDF_ERR_MALLOC_FAIL;
}
wrapper->entry_para = entry_para;
wrapper->thread_entry = thread_entry;
wrapper->cpu_id = OSAL_INVALID_CPU_ID;
thread->realThread = wrapper;
return HDF_SUCCESS;
}
EXPORT_SYMBOL(OsalThreadCreate);
int32_t OsalThreadBind(struct OsalThread *thread, unsigned int cpu_id)
{
struct thread_wrapper *wrapper = NULL;
if (thread == NULL || thread->realThread == NULL) {
HDF_LOGE("%s invalid parameter %d\n", __func__, __LINE__);
return HDF_ERR_INVALID_PARAM;
}
wrapper = (struct thread_wrapper *)thread->realThread;
wrapper->cpu_id = cpu_id;
return HDF_SUCCESS;
}
EXPORT_SYMBOL(OsalThreadBind);
int32_t OsalThreadStart(struct OsalThread *thread, const struct OsalThreadParam *param)
{
int32_t ret;
struct sched_param sched_para;
int32_t policy = SCHED_FIFO;
struct task_struct *task = NULL;
struct thread_wrapper *wrapper = NULL;
if (thread == NULL || thread->realThread == NULL || param == NULL || param->name == NULL) {
HDF_LOGE("%s invalid parameter\n", __func__);
return HDF_ERR_INVALID_PARAM;
}
(void)memset_s(&sched_para, sizeof(sched_para), 0, sizeof(sched_para));
if (param->priority == OSAL_THREAD_PRI_HIGHEST)
sched_para.sched_priority = OSAL_PRIORITY_HIGHEST;
else if (param->priority == OSAL_THREAD_PRI_HIGH)
sched_para.sched_priority = OSAL_PRIORITY_HIGH;
else if (param->priority == OSAL_THREAD_PRI_DEFAULT)
sched_para.sched_priority = OSAL_PRIORITY_MIDDLE;
else
policy = SCHED_NORMAL;
wrapper = (struct thread_wrapper *)thread->realThread;
task = kthread_create(osal_thread_entry, wrapper, param->name);
if (IS_ERR(task)) {
ret = PTR_ERR(task);
HDF_LOGE("%s kthread_create fail %d", __func__, ret);
return HDF_FAILURE;
}
if (wrapper->cpu_id != OSAL_INVALID_CPU_ID) {
kthread_bind(task, wrapper->cpu_id);
}
wake_up_process(task);
if (policy == SCHED_FIFO) {
if (sched_setscheduler(task, policy, &sched_para)) {
HDF_LOGE("%s sched_setscheduler fail", __func__);
kthread_stop(task);
return HDF_FAILURE;
}
}
wrapper->task = task;
return HDF_SUCCESS;
}
EXPORT_SYMBOL(OsalThreadStart);
int32_t OsalThreadSuspend(struct OsalThread *thread)
{
return HDF_ERR_NOT_SUPPORT;
}
EXPORT_SYMBOL(OsalThreadSuspend);
int32_t OsalThreadDestroy(struct OsalThread *thread)
{
if (thread == NULL || thread->realThread == NULL) {
HDF_LOGE("%s invalid parameter\n", __func__);
return HDF_ERR_INVALID_PARAM;
}
OsalMemFree(thread->realThread);
thread->realThread = NULL;
return HDF_SUCCESS;
}
EXPORT_SYMBOL(OsalThreadDestroy);
int32_t OsalThreadResume(struct OsalThread *thread)
{
return HDF_ERR_NOT_SUPPORT;
}
EXPORT_SYMBOL(OsalThreadResume);