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