acrn-hypervisor/hypervisor/common/sched_iorr.c
Geoffroy Van Cutsem 8b16be9185 Remove "All rights reserved" string headers
Many of the license and Intel copyright headers include the "All rights
reserved" string. It is not relevant in the context of the BSD-3-Clause
license that the code is released under. This patch removes those strings
throughout the code (hypervisor, devicemodel and misc).

Tracked-On: #7254
Signed-off-by: Geoffroy Van Cutsem <geoffroy.vancutsem@intel.com>
2022-04-06 13:21:02 +08:00

205 lines
5.3 KiB
C

/*
* Copyright (C) 2019 Intel Corporation.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <list.h>
#include <asm/per_cpu.h>
#include <schedule.h>
#include <ticks.h>
#define CONFIG_SLICE_MS 10UL
struct sched_iorr_data {
/* keep list as the first item */
struct list_head list;
uint64_t slice_cycles;
uint64_t last_cycles;
int64_t left_cycles;
};
/*
* @pre obj != NULL
* @pre obj->data != NULL
*/
bool is_inqueue(struct thread_object *obj)
{
struct sched_iorr_data *data = (struct sched_iorr_data *)obj->data;
return !list_empty(&data->list);
}
/*
* @pre obj != NULL
* @pre obj->data != NULL
* @pre obj->sched_ctl != NULL
* @pre obj->sched_ctl->priv != NULL
*/
void runqueue_add_head(struct thread_object *obj)
{
struct sched_iorr_control *iorr_ctl = (struct sched_iorr_control *)obj->sched_ctl->priv;
struct sched_iorr_data *data = (struct sched_iorr_data *)obj->data;
if (!is_inqueue(obj)) {
list_add(&data->list, &iorr_ctl->runqueue);
}
}
/*
* @pre obj != NULL
* @pre obj->data != NULL
* @pre obj->sched_ctl != NULL
* @pre obj->sched_ctl->priv != NULL
*/
void runqueue_add_tail(struct thread_object *obj)
{
struct sched_iorr_control *iorr_ctl = (struct sched_iorr_control *)obj->sched_ctl->priv;
struct sched_iorr_data *data = (struct sched_iorr_data *)obj->data;
if (!is_inqueue(obj)) {
list_add_tail(&data->list, &iorr_ctl->runqueue);
}
}
/*
* @pre obj != NULL
* @pre obj->data != NULL
*/
void runqueue_remove(struct thread_object *obj)
{
struct sched_iorr_data *data = (struct sched_iorr_data *)obj->data;
list_del_init(&data->list);
}
static void sched_tick_handler(void *param)
{
struct sched_control *ctl = (struct sched_control *)param;
struct sched_iorr_control *iorr_ctl = (struct sched_iorr_control *)ctl->priv;
struct sched_iorr_data *data;
struct thread_object *current;
uint16_t pcpu_id = get_pcpu_id();
uint64_t now = cpu_ticks();
uint64_t rflags;
obtain_schedule_lock(pcpu_id, &rflags);
current = ctl->curr_obj;
/* If no vCPU start scheduling, ignore this tick */
if (current != NULL ) {
if (!(is_idle_thread(current) && list_empty(&iorr_ctl->runqueue))) {
data = (struct sched_iorr_data *)current->data;
/* consume the left_cycles of current thread_object if it is not idle */
if (!is_idle_thread(current)) {
data->left_cycles -= now - data->last_cycles;
data->last_cycles = now;
}
/* make reschedule request if current ran out of its cycles */
if (is_idle_thread(current) || data->left_cycles <= 0) {
make_reschedule_request(pcpu_id, DEL_MODE_IPI);
}
}
}
release_schedule_lock(pcpu_id, rflags);
}
/*
* @pre ctl->pcpu_id == get_pcpu_id()
*/
int sched_iorr_init(struct sched_control *ctl)
{
struct sched_iorr_control *iorr_ctl = &per_cpu(sched_iorr_ctl, ctl->pcpu_id);
uint64_t tick_period = TICKS_PER_MS;
int ret = 0;
ASSERT(get_pcpu_id() == ctl->pcpu_id, "Init scheduler on wrong CPU!");
ctl->priv = iorr_ctl;
INIT_LIST_HEAD(&iorr_ctl->runqueue);
/* The tick_timer is periodically */
initialize_timer(&iorr_ctl->tick_timer, sched_tick_handler, ctl,
cpu_ticks() + tick_period, tick_period);
if (add_timer(&iorr_ctl->tick_timer) < 0) {
pr_err("Failed to add schedule tick timer!");
ret = -1;
}
return ret;
}
void sched_iorr_deinit(struct sched_control *ctl)
{
struct sched_iorr_control *iorr_ctl = (struct sched_iorr_control *)ctl->priv;
del_timer(&iorr_ctl->tick_timer);
}
void sched_iorr_init_data(struct thread_object *obj)
{
struct sched_iorr_data *data;
data = (struct sched_iorr_data *)obj->data;
INIT_LIST_HEAD(&data->list);
data->left_cycles = data->slice_cycles = CONFIG_SLICE_MS * TICKS_PER_MS;
}
static struct thread_object *sched_iorr_pick_next(struct sched_control *ctl)
{
struct sched_iorr_control *iorr_ctl = (struct sched_iorr_control *)ctl->priv;
struct thread_object *next = NULL;
struct thread_object *current = NULL;
struct sched_iorr_data *data;
uint64_t now = cpu_ticks();
current = ctl->curr_obj;
data = (struct sched_iorr_data *)current->data;
/* Ignore the idle object, inactive objects */
if (!is_idle_thread(current) && is_inqueue(current)) {
data->left_cycles -= now - data->last_cycles;
if (data->left_cycles <= 0) {
/* replenish thread_object with slice_cycles */
data->left_cycles += data->slice_cycles;
}
/* move the thread_object to tail */
runqueue_remove(current);
runqueue_add_tail(current);
}
/*
* Pick the next runnable sched object
* 1) get the first item in runqueue firstly
* 2) if object picked has no time_cycles, replenish it pick this one
* 3) At least take one idle sched object if we have no runnable one after step 1) and 2)
*/
if (!list_empty(&iorr_ctl->runqueue)) {
next = get_first_item(&iorr_ctl->runqueue, struct thread_object, data);
data = (struct sched_iorr_data *)next->data;
data->last_cycles = now;
while (data->left_cycles <= 0) {
data->left_cycles += data->slice_cycles;
}
} else {
next = &get_cpu_var(idle);
}
return next;
}
static void sched_iorr_sleep(struct thread_object *obj)
{
runqueue_remove(obj);
}
static void sched_iorr_wake(struct thread_object *obj)
{
runqueue_add_head(obj);
}
struct acrn_scheduler sched_iorr = {
.name = "sched_iorr",
.init = sched_iorr_init,
.init_data = sched_iorr_init_data,
.pick_next = sched_iorr_pick_next,
.sleep = sched_iorr_sleep,
.wake = sched_iorr_wake,
.deinit = sched_iorr_deinit,
};