1 /*
2  * osal_thread.c
3  *
4  * osal driver
5  *
6  * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  */
18 
19 #include "osal_thread.h"
20 #include <linux/errno.h>
21 #include <linux/export.h>
22 #include <linux/kernel.h>
23 #include <linux/kthread.h>
24 #include <linux/string.h>
25 #include <linux/types.h>
26 #include <uapi/linux/sched.h>
27 #include <uapi/linux/sched/types.h>
28 #include "hdf_log.h"
29 #include "osal_mem.h"
30 #include "securec.h"
31 
32 #define HDF_LOG_TAG osal_thread
33 #define OSAL_INVALID_CPU_ID UINT_MAX
34 
35 struct thread_wrapper {
36 	OsalThreadEntry thread_entry;
37 	void *entry_para;
38 	struct task_struct *task;
39 	uint32_t cpu_id;
40 };
41 
42 enum {
43 	OSAL_PRIORITY_MIDDLE  = 50,
44 	OSAL_PRIORITY_HIGH    = 90,
45 	OSAL_PRIORITY_HIGHEST = 99,
46 };
47 
osal_thread_entry(void * para)48 static int osal_thread_entry(void *para)
49 {
50 	int ret = -1;
51 
52 	struct thread_wrapper *wrapper = (struct thread_wrapper *)para;
53 	if (wrapper == NULL || wrapper->thread_entry == NULL) {
54 		HDF_LOGE("%s invalid param", __func__);
55 	} else {
56 		ret = wrapper->thread_entry(wrapper->entry_para);
57 	}
58 
59 	do_exit(ret);
60 	return ret;
61 }
62 
OsalThreadCreate(struct OsalThread * thread,OsalThreadEntry thread_entry,void * entry_para)63 int32_t OsalThreadCreate(struct OsalThread *thread, OsalThreadEntry thread_entry, void *entry_para)
64 {
65 	struct thread_wrapper *wrapper = NULL;
66 
67 	if (thread == NULL || thread_entry == NULL) {
68 		HDF_LOGE("%s invalid param", __func__);
69 		return HDF_ERR_INVALID_PARAM;
70 	}
71 
72 	thread->realThread = NULL;
73 	wrapper = (struct thread_wrapper *)OsalMemCalloc(sizeof(*wrapper));
74 	if (wrapper == NULL) {
75 		HDF_LOGE("%s malloc fail", __func__);
76 		return HDF_ERR_MALLOC_FAIL;
77 	}
78 
79 	wrapper->entry_para = entry_para;
80 	wrapper->thread_entry = thread_entry;
81 	wrapper->cpu_id = OSAL_INVALID_CPU_ID;
82 	thread->realThread = wrapper;
83 
84 	return HDF_SUCCESS;
85 }
86 EXPORT_SYMBOL(OsalThreadCreate);
87 
OsalThreadBind(struct OsalThread * thread,unsigned int cpu_id)88 int32_t OsalThreadBind(struct OsalThread *thread, unsigned int cpu_id)
89 {
90 	struct thread_wrapper *wrapper = NULL;
91 
92 	if (thread == NULL || thread->realThread == NULL) {
93 		HDF_LOGE("%s invalid parameter %d\n", __func__, __LINE__);
94 		return HDF_ERR_INVALID_PARAM;
95 	}
96 	wrapper = (struct thread_wrapper *)thread->realThread;
97 	wrapper->cpu_id = cpu_id;
98 	return HDF_SUCCESS;
99 }
100 EXPORT_SYMBOL(OsalThreadBind);
101 
OsalThreadStart(struct OsalThread * thread,const struct OsalThreadParam * param)102 int32_t OsalThreadStart(struct OsalThread *thread, const struct OsalThreadParam *param)
103 {
104 	int32_t ret;
105 	struct sched_param sched_para;
106 	int32_t policy = SCHED_FIFO;
107 	struct task_struct *task = NULL;
108 	struct thread_wrapper *wrapper = NULL;
109 
110 	if (thread == NULL || thread->realThread == NULL || param == NULL || param->name == NULL) {
111 		HDF_LOGE("%s invalid parameter\n", __func__);
112 		return HDF_ERR_INVALID_PARAM;
113 	}
114 
115 	(void)memset_s(&sched_para, sizeof(sched_para), 0, sizeof(sched_para));
116 
117 	if (param->priority == OSAL_THREAD_PRI_HIGHEST)
118 		sched_para.sched_priority = OSAL_PRIORITY_HIGHEST;
119 	else if (param->priority == OSAL_THREAD_PRI_HIGH)
120 		sched_para.sched_priority = OSAL_PRIORITY_HIGH;
121 	else if (param->priority == OSAL_THREAD_PRI_DEFAULT)
122 		sched_para.sched_priority = OSAL_PRIORITY_MIDDLE;
123 	else
124 		policy = SCHED_NORMAL;
125 
126 	wrapper = (struct thread_wrapper *)thread->realThread;
127 	task = kthread_create(osal_thread_entry, wrapper, param->name);
128 	if (IS_ERR(task)) {
129 		ret = PTR_ERR(task);
130 		HDF_LOGE("%s kthread_create fail %d", __func__, ret);
131 		return HDF_FAILURE;
132 	}
133 	if (wrapper->cpu_id != OSAL_INVALID_CPU_ID) {
134 		kthread_bind(task, wrapper->cpu_id);
135 	}
136 	wake_up_process(task);
137 	if (policy == SCHED_FIFO) {
138 		if (sched_setscheduler(task, policy, &sched_para)) {
139 			HDF_LOGE("%s sched_setscheduler fail", __func__);
140 			kthread_stop(task);
141 			return HDF_FAILURE;
142 		}
143 	}
144 
145 	wrapper->task = task;
146 
147 	return HDF_SUCCESS;
148 }
149 
150 EXPORT_SYMBOL(OsalThreadStart);
151 
OsalThreadSuspend(struct OsalThread * thread)152 int32_t OsalThreadSuspend(struct OsalThread *thread)
153 {
154 	(void)thread;
155 	return HDF_ERR_NOT_SUPPORT;
156 }
157 EXPORT_SYMBOL(OsalThreadSuspend);
158 
OsalThreadDestroy(struct OsalThread * thread)159 int32_t OsalThreadDestroy(struct OsalThread *thread)
160 {
161 	if (thread == NULL || thread->realThread == NULL) {
162 		HDF_LOGE("%s invalid parameter\n", __func__);
163 		return HDF_ERR_INVALID_PARAM;
164 	}
165 
166 	OsalMemFree(thread->realThread);
167 	thread->realThread = NULL;
168 
169 	return HDF_SUCCESS;
170 }
171 EXPORT_SYMBOL(OsalThreadDestroy);
172 
OsalThreadResume(struct OsalThread * thread)173 int32_t OsalThreadResume(struct OsalThread *thread)
174 {
175 	(void)thread;
176 	return HDF_ERR_NOT_SUPPORT;
177 }
178 EXPORT_SYMBOL(OsalThreadResume);
179 
180