1 /*
2 * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 /* ****************************************************************************
20 1 头文件包含
21 **************************************************************************** */
22 #include "frw_event_sched.h"
23 #include "oam_ext_if.h"
24 #include "frw_event.h"
25
26 #ifdef __cplusplus
27 #if __cplusplus
28 extern "C" {
29 #endif
30 #endif
31
32 /* ****************************************************************************
33 2 宏定义
34 **************************************************************************** */
35 /* ****************************************************************************
36 3 函数原型声明
37 **************************************************************************** */
38 /* ****************************************************************************
39 4 全局变量定义
40 **************************************************************************** */
41 /* ****************************************************************************
42 5 函数实现
43 **************************************************************************** */
44 /* ****************************************************************************
45 功能描述 : 重置调度队列上各个事件队列的权重计数器
46 输入参数 : pst_sched_queue: 调度队列指针
47 **************************************************************************** */
frw_event_sched_reset_weight(frw_event_sched_queue_stru * sched_queue)48 hi_void frw_event_sched_reset_weight(frw_event_sched_queue_stru *sched_queue)
49 {
50 hi_list *list = HI_NULL;
51 frw_event_queue_stru *event_queue = HI_NULL;
52
53 /* 遍历整个调度链表 */
54 hi_list_for_each(list, &sched_queue->head) {
55 /* 获取调度链表中的一个事件队列 */
56 event_queue = hi_list_entry(list, frw_event_queue_stru, list);
57 /* 只是重置恢复状态VAP的权重值 */
58 if (event_queue->vap_state == FRW_VAP_STATE_RESUME) {
59 /* 重置事件队列的权重计数器 */
60 event_queue->weight_cnt = event_queue->weight;
61 /* 更新调度队列上的总权重计数器 */
62 sched_queue->total_weight_cnt += event_queue->weight;
63 }
64 }
65 }
66
67 /* ****************************************************************************
68 功能描述 : 事件调度入口函数
69
70 修改历史 :
71 1.日 期 : 2012年10月17日
72 作 者 : HiSilicon
73 修改内容 : 新生成函数
74
75 **************************************************************************** */
frw_event_schedule(frw_event_sched_queue_stru * sched_queue)76 hi_void *frw_event_schedule(frw_event_sched_queue_stru *sched_queue)
77 {
78 hi_void *event = HI_NULL;
79 frw_event_sched_queue_stru *queue = HI_NULL;
80
81 /* 遍历全部调度类 */
82 queue = &sched_queue[FRW_SCHED_POLICY_HI];
83
84 /* 如果高优先级调度队列为空,则取下一个调度队列 */
85 if (!hi_is_list_empty(&queue->head)) {
86 /* 从调度类中挑选下一个待处理的事件 */
87 event = frw_event_sched_pick_next_event_queue_wrr(queue);
88 if (event != HI_NULL) {
89 return event;
90 }
91 }
92
93 queue = &sched_queue[FRW_SCHED_POLICY_NORMAL];
94
95 /* 如果普通优先级调度队列为空,则取下一个调度队列 */
96 if (!hi_is_list_empty(&queue->head)) {
97 /* 从调度类中挑选下一个待处理的事件 */
98 event = frw_event_sched_pick_next_event_queue_wrr(queue);
99 if (event != HI_NULL) {
100 return event;
101 }
102 }
103
104 return HI_NULL;
105 }
106 /* ****************************************************************************
107 功能描述 : 从调度队列删除一个事件队列
108 输入参数 : pst_sched_queue: 调度队列指针
109 pst_event_queue: 事件队列指针
110
111 修改历史 :
112 1.日 期 : 2015年3月31日
113 作 者 : HiSilicon
114 修改内容 : 新生成函数
115
116 *****************************************************************************/
frw_event_sched_deactivate_queue_no_lock(frw_event_sched_queue_stru * sched_queue,frw_event_queue_stru * event_queue)117 hi_void frw_event_sched_deactivate_queue_no_lock(frw_event_sched_queue_stru *sched_queue,
118 frw_event_queue_stru *event_queue)
119 {
120 if (event_queue->queue.element_cnt != 0) {
121 return;
122 }
123
124 /* 更新调度队列上的总权重计数器 */
125 sched_queue->total_weight_cnt -= event_queue->weight_cnt;
126 /* 将事件队列的权重计数器清零 */
127 event_queue->weight_cnt = 0;
128 /* 将事件队列从调度链表上删除 */
129 hi_list_delete(&event_queue->list);
130 /* 将事件队列置为不活跃状态 */
131 event_queue->state = FRW_EVENT_QUEUE_STATE_INACTIVE;
132 }
133
134 /* ****************************************************************************
135 功能描述 : 向调度队列添加一个新的事件队列
136 输入参数 : past_sched_queue: 调度队列指针
137 pst_event_queue : 事件队列指针
138
139 修改历史 :
140 1.日 期 : 2012年11月5日
141 作 者 : HiSilicon
142 修改内容 : 新生成函数
143
144 2.日 期 : 2015年4月23日
145 作 者 : HiSilicon
146 修改内容 : 封装为不加锁接口,保持接口对称性,供加锁接口调用
147 *****************************************************************************/
frw_event_sched_activate_queue_no_lock(frw_event_sched_queue_stru * sched_queue,frw_event_queue_stru * event_queue)148 hi_u32 frw_event_sched_activate_queue_no_lock(frw_event_sched_queue_stru *sched_queue,
149 frw_event_queue_stru *event_queue)
150 {
151 /* 如果事件队列已经在可执行队列上(处于激活状态),则直接返回成功 */
152 if (event_queue->state == FRW_EVENT_QUEUE_STATE_ACTIVE) {
153 return HI_SUCCESS;
154 }
155
156 /* 置为事件队列的权重计数器 */
157 event_queue->weight_cnt = event_queue->weight;
158 /* 更新调度队列上的总权重计数器 */
159 sched_queue->total_weight_cnt += event_queue->weight_cnt;
160
161 /* 将事件队列加入调度链表的末尾 */
162 hi_list_tail_insert(&event_queue->list, &sched_queue->head);
163
164 /* 将事件队列置为激活状态 */
165 event_queue->state = FRW_EVENT_QUEUE_STATE_ACTIVE;
166
167 return HI_SUCCESS;
168 }
169
170 /* ****************************************************************************
171 功能描述 : 调度器初始化
172 输入参数 : pst_sched_queue: 调度队列指针
173
174 修改历史 :
175 1.日 期 : 2012年11月5日
176 作 者 : HiSilicon
177 修改内容 : 新生成函数
178 **************************************************************************** */
frw_event_sched_init(frw_event_sched_queue_stru * sched_queue)179 hi_u32 frw_event_sched_init(frw_event_sched_queue_stru *sched_queue)
180 {
181 /* 初始化锁 */
182 /* 初始化调度队列总权重计数器 */
183 sched_queue->total_weight_cnt = 0;
184
185 /* 初始化调度链表头 */
186 hi_list_init(&sched_queue->head);
187 oal_spin_lock_init(&sched_queue->st_lock);
188
189 return HI_SUCCESS;
190 }
191
192 /* ****************************************************************************
193 功能描述 : 设置事件队列参数
194 输入参数 : pst_prio_queue: 事件队列指针
195 us_weight : 队列权重
196 en_policy : 队列调度策略
197 en_state : 事件队列状态
198 *****************************************************************************/
frw_event_queue_set(frw_event_queue_stru * event_queue,hi_u8 weight,frw_sched_policy_enum_uint8 policy,frw_event_queue_state_enum_uint8 state)199 hi_void frw_event_queue_set(frw_event_queue_stru *event_queue, hi_u8 weight,
200 frw_sched_policy_enum_uint8 policy, frw_event_queue_state_enum_uint8 state)
201 {
202 event_queue->weight = weight;
203 event_queue->weight_cnt = 0;
204 event_queue->policy = policy;
205 event_queue->state = state;
206 event_queue->vap_state = FRW_VAP_STATE_RESUME;
207 }
208
209 /* ****************************************************************************
210 功能描述 : 队列初始化, uc_max_events必须是2的整数次幂
211 输入参数 : pst_queue : 队列指针
212 uc_max_events: 最大元素个数
213 **************************************************************************** */
oal_queue_init(oal_queue_stru * queue,hi_u8 max_events)214 hi_u32 oal_queue_init(oal_queue_stru *queue, hi_u8 max_events)
215 {
216 hi_u32 *pul_buf = HI_NULL;
217
218 if (max_events == 0) {
219 return HI_SUCCESS;
220 } else {
221 if (oal_unlikely(oal_is_not_pow_of_2(max_events))) {
222 return HI_ERR_CODE_CONFIG_UNSUPPORT;
223 }
224
225 pul_buf = (hi_u32 *)oal_mem_alloc(OAL_MEM_POOL_ID_LOCAL, (hi_u16)(max_events * sizeof(hi_u32)));
226 if (oal_unlikely(pul_buf == HI_NULL)) {
227 return HI_ERR_CODE_ALLOC_MEM_FAIL;
228 }
229 /* 安全编程规则6.6例外(3)从堆中分配内存后,赋予初值 */
230 memset_s(pul_buf, max_events * sizeof(hi_u32), 0, max_events * sizeof(hi_u32));
231 oal_queue_set(queue, pul_buf, max_events);
232
233 return HI_SUCCESS;
234 }
235 }
236
237 /* ****************************************************************************
238 功能描述 : 事件队列初始化
239 输入参数 : pst_event_queue: 事件队列指针
240 us_weight : 队列权重
241 en_policy : 队列调度策略
242 en_state : 事件队列状态
243 us_max_events : 最大事件个数
244
245 修改历史 :
246 1.日 期 : 2012年10月17日
247 作 者 : HiSilicon
248 修改内容 : 新生成函数
249
250 *****************************************************************************/
frw_event_queue_init(frw_event_queue_stru * event_queue,hi_u8 weight,frw_sched_policy_enum_uint8 policy,frw_event_queue_state_enum_uint8 state,hi_u8 max_events)251 hi_u32 frw_event_queue_init(frw_event_queue_stru *event_queue, hi_u8 weight,
252 frw_sched_policy_enum_uint8 policy,
253 frw_event_queue_state_enum_uint8 state, hi_u8 max_events)
254 {
255 hi_u32 ret;
256
257 /* 初始化锁 */
258 oal_spin_lock_init(&event_queue->st_lock);
259 ret = oal_queue_init(&event_queue->queue, max_events);
260 if (oal_unlikely(ret != HI_SUCCESS)) {
261 oam_warning_log1(0, OAM_SF_FRW, "{frw_event_queue_init:: OAL_QUEUE_INIT return != HI_SUCCESS! %d}", ret);
262 frw_event_queue_set(event_queue, 0, FRW_SCHED_POLICY_BUTT, FRW_EVENT_QUEUE_STATE_INACTIVE);
263
264 return ret;
265 }
266
267 frw_event_queue_set(event_queue, weight, policy, state);
268
269 return HI_SUCCESS;
270 }
271
272 /* ****************************************************************************
273 功能描述 : 销毁事件队列
274 输入参数 : pst_event_queue: 事件队列指针
275
276 修改历史 :
277 1.日 期 : 2012年10月18日
278 作 者 : HiSilicon
279 修改内容 : 新生成函数
280
281 **************************************************************************** */
frw_event_queue_destroy(frw_event_queue_stru * event_queue)282 hi_void frw_event_queue_destroy(frw_event_queue_stru *event_queue)
283 {
284 oal_queue_destroy(&event_queue->queue);
285
286 frw_event_queue_set(event_queue, 0, FRW_SCHED_POLICY_BUTT, FRW_EVENT_QUEUE_STATE_INACTIVE);
287 }
288
289 /* ****************************************************************************
290 功能描述 : 从调度类中挑选下一个待处理的事件
291
292 修改历史 :
293 1.日 期 : 2012年10月17日
294 作 者 : HiSilicon
295 修改内容 : 新生成函数
296
297 **************************************************************************** */
frw_event_sched_pick_next_event_queue_wrr(frw_event_sched_queue_stru * sched_queue)298 hi_void *frw_event_sched_pick_next_event_queue_wrr(frw_event_sched_queue_stru *sched_queue)
299 {
300 hi_list *list = HI_NULL;
301 frw_event_queue_stru *event_queue = HI_NULL;
302 hi_void *event = HI_NULL;
303 unsigned long flag;
304 unsigned long irq_flag;
305
306 oal_spin_lock_irq_save(&sched_queue->st_lock, &flag);
307
308 /* 遍历整个调度链表 */
309 hi_list_for_each(list, &sched_queue->head) {
310 event_queue = hi_list_entry(list, frw_event_queue_stru, list);
311 oal_spin_lock_irq_save(&event_queue->st_lock, &irq_flag);
312 /* 如果事件队列的vap_state为暂停,则跳过,继续挑选下一个事件队列 */
313 if (event_queue->vap_state == FRW_VAP_STATE_PAUSE) {
314 oal_spin_unlock_irq_restore(&event_queue->st_lock, &irq_flag);
315 continue;
316 }
317
318 /* 如果事件队列的权重计数器为0,则挑选下一个事件队列 */
319 if (event_queue->weight_cnt == 0) {
320 oal_spin_unlock_irq_restore(&event_queue->st_lock, &irq_flag);
321 continue;
322 }
323
324 /* 更新事件队列权重计数器 */
325 event_queue->weight_cnt--;
326 /* 更新调度队列的总权重计数器 */
327 sched_queue->total_weight_cnt--;
328 /* 从事件队列中取出一个事件 */
329 event = (frw_event_mem_stru *)oal_queue_dequeue(&event_queue->queue);
330
331 /* 如果事件队列变空,需要将其从调度队列上删除,并将事件队列状态置为不活跃(不可被调度) */
332 frw_event_sched_deactivate_queue_no_lock(sched_queue, event_queue);
333 /* } */
334 oal_spin_unlock_irq_restore(&event_queue->st_lock, &irq_flag);
335 break;
336 }
337
338 /* 如果调度队列的总权重计数器为0,则需要重置调度队列上各个事件队列的权重计数器 */
339 if (sched_queue->total_weight_cnt == 0) {
340 frw_event_sched_reset_weight(sched_queue);
341 }
342
343 oal_spin_unlock_irq_restore(&sched_queue->st_lock, &flag);
344 return event;
345 }
346
347 /* ****************************************************************************
348 功能描述 : 从调度队列删除一个事件队列
349 输入参数 : pst_sched_queue: 调度队列指针
350 pst_event_queue: 事件队列指针
351
352 修改历史 :
353 1.日 期 : 2012年11月12日
354 作 者 : HiSilicon
355 修改内容 : 新生成函数
356
357 **************************************************************************** */
frw_event_sched_deactivate_queue(frw_event_sched_queue_stru * sched_queue,frw_event_queue_stru * event_queue)358 hi_void frw_event_sched_deactivate_queue(frw_event_sched_queue_stru *sched_queue, frw_event_queue_stru *event_queue)
359 {
360 unsigned long flag;
361
362 /* 关中断,加锁 */
363 oal_spin_lock_irq_save(&sched_queue->st_lock, &flag);
364
365 frw_event_sched_deactivate_queue_no_lock(sched_queue, event_queue);
366
367 /* 解锁,开中断 */
368 oal_spin_unlock_irq_restore(&sched_queue->st_lock, &flag);
369 }
370
371 #ifdef __cplusplus
372 #if __cplusplus
373 }
374 #endif
375 #endif
376