1 /*
2  * Copyright (C) 2021 Intel Corporation.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <list.h>
8 #include <asm/per_cpu.h>
9 #include <schedule.h>
10 
11 struct sched_prio_data {
12 	/* keep list as the first item */
13 	struct list_head list;
14 	int priority;
15 };
16 
sched_prio_init(struct sched_control * ctl)17 static int sched_prio_init(struct sched_control *ctl)
18 {
19 	struct sched_prio_control *prio_ctl = &per_cpu(sched_prio_ctl, ctl->pcpu_id);
20 
21 	ASSERT(ctl->pcpu_id == get_pcpu_id(), "Init scheduler on wrong CPU!");
22 
23 	ctl->priv = prio_ctl;
24 	INIT_LIST_HEAD(&prio_ctl->prio_queue);
25 
26 	return 0;
27 }
28 
sched_prio_init_data(struct thread_object * obj,struct sched_params * params)29 static void sched_prio_init_data(struct thread_object *obj, struct sched_params *params)
30 {
31 	struct sched_prio_data *data;
32 
33 	data = (struct sched_prio_data *)obj->data;
34 	INIT_LIST_HEAD(&data->list);
35 	data->priority = params->prio;
36 }
37 
sched_prio_pick_next(struct sched_control * ctl)38 static struct thread_object *sched_prio_pick_next(struct sched_control *ctl)
39 {
40 	struct sched_prio_control *prio_ctl = (struct sched_prio_control *)ctl->priv;
41 	struct thread_object *next = NULL;
42 
43 	if (!list_empty(&prio_ctl->prio_queue)) {
44 		next = get_first_item(&prio_ctl->prio_queue, struct thread_object, data);
45 	} else {
46 		next = &get_cpu_var(idle);
47 	}
48 
49 	return next;
50 }
51 
prio_queue_add(struct thread_object * obj)52 static void prio_queue_add(struct thread_object *obj)
53 {
54 	struct sched_prio_control *prio_ctl =
55 		(struct sched_prio_control *)obj->sched_ctl->priv;
56 	struct sched_prio_data *data = (struct sched_prio_data *)obj->data;
57 	struct sched_prio_data *iter_data;
58 	struct list_head *pos;
59 
60 	if (list_empty(&prio_ctl->prio_queue)) {
61 		list_add(&data->list, &prio_ctl->prio_queue);
62 	} else {
63 		list_for_each(pos, &prio_ctl->prio_queue) {
64 			iter_data = container_of(pos, struct sched_prio_data, list);
65 			if (iter_data->priority < data->priority) {
66 				list_add_node(&data->list, pos->prev, pos);
67 				break;
68 			}
69 		}
70 		if (list_empty(&data->list)) {
71 			list_add_tail(&data->list, &prio_ctl->prio_queue);
72 		}
73 	}
74 }
75 
prio_queue_remove(struct thread_object * obj)76 static void prio_queue_remove(struct thread_object *obj)
77 {
78 	struct sched_prio_data *data = (struct sched_prio_data *)obj->data;
79 
80 	list_del_init(&data->list);
81 }
82 
sched_prio_sleep(struct thread_object * obj)83 static void sched_prio_sleep(struct thread_object *obj)
84 {
85 	prio_queue_remove(obj);
86 }
87 
sched_prio_wake(struct thread_object * obj)88 static void sched_prio_wake(struct thread_object *obj)
89 {
90 	prio_queue_add(obj);
91 }
92 
93 struct acrn_scheduler sched_prio = {
94 	.name		= "sched_prio",
95 	.init		= sched_prio_init,
96 	.init_data	= sched_prio_init_data,
97 	.pick_next	= sched_prio_pick_next,
98 	.sleep		= sched_prio_sleep,
99 	.wake		= sched_prio_wake,
100 };
101