debuggers.hg

annotate xen/common/sched_bvt.c @ 3658:0ef6e8e6e85d

bitkeeper revision 1.1159.212.71 (4200f0afX_JumfbEHQex6TdFENULMQ)

Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno-xenod/BK/xen-unstable.bk
into labyrinth.cl.cam.ac.uk:/auto/groups/xeno/users/iap10/xeno-clone/xen-unstable.bk
author iap10@labyrinth.cl.cam.ac.uk
date Wed Feb 02 15:24:31 2005 +0000 (2005-02-02)
parents c6f1bab39d4f 10a0f6b0a996
children bbe8541361dd 4294cfa9fad3
rev   line source
mwilli2@1232 1 /* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
mwilli2@1232 2 ****************************************************************************
mwilli2@1232 3 * (C) 2002-2003 - Rolf Neugebauer - Intel Research Cambridge
mwilli2@1232 4 * (C) 2002-2003 University of Cambridge
mwilli2@1232 5 * (C) 2004 - Mark Williamson - Intel Research Cambridge
mwilli2@1232 6 ****************************************************************************
mwilli2@1232 7 *
mwilli2@1232 8 * File: common/schedule.c
mwilli2@1232 9 * Author: Rolf Neugebauer & Keir Fraser
mwilli2@1232 10 * Updated for generic API by Mark Williamson
mwilli2@1232 11 *
mwilli2@1232 12 * Description: CPU scheduling
mwilli2@1232 13 * implements A Borrowed Virtual Time scheduler.
mwilli2@1232 14 * (see Duda & Cheriton SOSP'99)
mwilli2@1232 15 */
mwilli2@1232 16
kaf24@1248 17 #include <xen/config.h>
kaf24@1248 18 #include <xen/init.h>
kaf24@1248 19 #include <xen/lib.h>
kaf24@1248 20 #include <xen/sched.h>
kaf24@1248 21 #include <xen/delay.h>
kaf24@1248 22 #include <xen/event.h>
kaf24@1248 23 #include <xen/time.h>
kaf24@1248 24 #include <xen/ac_timer.h>
kaf24@1248 25 #include <xen/perfc.h>
kaf24@1248 26 #include <xen/sched-if.h>
kaf24@1248 27 #include <xen/slab.h>
kaf24@1916 28 #include <xen/softirq.h>
mwilli2@1232 29
mwilli2@1232 30 /* all per-domain BVT-specific scheduling info is stored here */
cl349@2957 31 struct bvt_edom_info
cl349@2957 32 {
cl349@2957 33 struct list_head run_list; /* runqueue list pointers */
cl349@2957 34 u32 avt; /* actual virtual time */
cl349@2957 35 u32 evt; /* effective virtual time */
cl349@2957 36 struct exec_domain *exec_domain;
cl349@2957 37 struct bvt_dom_info *inf;
cl349@2957 38 };
cl349@2957 39
mwilli2@1232 40 struct bvt_dom_info
mwilli2@1232 41 {
gm281@1937 42 struct domain *domain; /* domain this info belongs to */
gm281@2096 43 u32 mcu_advance; /* inverse of weight */
gm281@1937 44 int warpback; /* warp? */
gm281@2096 45 int warp; /* warp set and within the warp
kaf24@2633 46 limits*/
gm281@2096 47 s32 warp_value; /* virtual time warp */
gm281@2096 48 s_time_t warpl; /* warp limit */
gm281@2096 49 struct ac_timer warp_timer; /* deals with warpl */
gm281@2096 50 s_time_t warpu; /* unwarp time requirement */
gm281@2096 51 struct ac_timer unwarp_timer; /* deals with warpu */
cl349@2957 52
cl349@2957 53 struct bvt_edom_info ed_inf[MAX_VIRT_CPUS];
mwilli2@1232 54 };
mwilli2@1232 55
mwilli2@1232 56 struct bvt_cpu_info
mwilli2@1232 57 {
kaf24@2633 58 struct list_head runqueue;
kaf24@2633 59 unsigned long svt;
mwilli2@1232 60 };
mwilli2@1232 61
kaf24@1234 62 #define BVT_INFO(p) ((struct bvt_dom_info *)(p)->sched_priv)
cl349@2957 63 #define EBVT_INFO(p) ((struct bvt_edom_info *)(p)->ed_sched_priv)
kaf24@1234 64 #define CPU_INFO(cpu) ((struct bvt_cpu_info *)(schedule_data[cpu]).sched_priv)
cl349@2957 65 #define RUNLIST(p) ((struct list_head *)&(EBVT_INFO(p)->run_list))
gm281@2017 66 #define RUNQUEUE(cpu) ((struct list_head *)&(CPU_INFO(cpu)->runqueue))
kaf24@1234 67 #define CPU_SVT(cpu) (CPU_INFO(cpu)->svt)
mwilli2@1232 68
mwilli2@1232 69 #define MCU (s32)MICROSECS(100) /* Minimum unit */
mwilli2@1232 70 #define MCU_ADVANCE 10 /* default weight */
mwilli2@1232 71 #define TIME_SLOP (s32)MICROSECS(50) /* allow time to slip a bit */
mwilli2@1232 72 static s32 ctx_allow = (s32)MILLISECS(5); /* context switch allowance */
mwilli2@1232 73
cl349@2957 74 static inline void __add_to_runqueue_head(struct exec_domain *d)
gm281@2017 75 {
gm281@2017 76 list_add(RUNLIST(d), RUNQUEUE(d->processor));
gm281@2017 77 }
gm281@2017 78
cl349@2957 79 static inline void __add_to_runqueue_tail(struct exec_domain *d)
gm281@2017 80 {
gm281@2017 81 list_add_tail(RUNLIST(d), RUNQUEUE(d->processor));
gm281@2017 82 }
gm281@2017 83
cl349@2957 84 static inline void __del_from_runqueue(struct exec_domain *d)
gm281@2017 85 {
gm281@2017 86 struct list_head *runlist = RUNLIST(d);
gm281@2017 87 list_del(runlist);
gm281@2017 88 runlist->next = NULL;
gm281@2017 89 }
gm281@2017 90
cl349@2957 91 static inline int __task_on_runqueue(struct exec_domain *d)
gm281@2017 92 {
gm281@2017 93 return (RUNLIST(d))->next != NULL;
gm281@2017 94 }
gm281@2017 95
gm281@2096 96
gm281@2096 97 /* Warp/unwarp timer functions */
gm281@2096 98 static void warp_timer_fn(unsigned long pointer)
gm281@2096 99 {
gm281@2096 100 struct bvt_dom_info *inf = (struct bvt_dom_info *)pointer;
cl349@2957 101 unsigned int cpu = inf->domain->exec_domain[0]->processor;
gm281@2129 102
kaf24@2633 103 spin_lock_irq(&schedule_data[cpu].schedule_lock);
kaf24@2633 104
gm281@2096 105 inf->warp = 0;
kaf24@2633 106
gm281@2096 107 /* unwarp equal to zero => stop warping */
kaf24@2633 108 if ( inf->warpu == 0 )
gm281@2096 109 {
gm281@2096 110 inf->warpback = 0;
kaf24@2633 111 cpu_raise_softirq(cpu, SCHEDULE_SOFTIRQ);
gm281@2096 112 }
gm281@2096 113
gm281@2096 114 /* set unwarp timer */
gm281@2096 115 inf->unwarp_timer.expires = NOW() + inf->warpu;
gm281@2096 116 add_ac_timer(&inf->unwarp_timer);
gm281@2096 117
kaf24@2633 118 spin_unlock_irq(&schedule_data[cpu].schedule_lock);
gm281@2096 119 }
gm281@2096 120
gm281@2096 121 static void unwarp_timer_fn(unsigned long pointer)
gm281@2096 122 {
kaf24@2633 123 struct bvt_dom_info *inf = (struct bvt_dom_info *)pointer;
cl349@2957 124 unsigned int cpu = inf->domain->exec_domain[0]->processor;
gm281@2096 125
kaf24@2633 126 spin_lock_irq(&schedule_data[cpu].schedule_lock);
kaf24@2633 127
kaf24@2633 128 if ( inf->warpback )
gm281@2096 129 {
gm281@2096 130 inf->warp = 1;
kaf24@2633 131 cpu_raise_softirq(cpu, SCHEDULE_SOFTIRQ);
gm281@2096 132 }
kaf24@2633 133
kaf24@2633 134 spin_unlock_irq(&schedule_data[cpu].schedule_lock);
gm281@2096 135 }
gm281@2096 136
cl349@2957 137 static inline u32 calc_avt(struct exec_domain *d, s_time_t now)
gm281@2063 138 {
gm281@2063 139 u32 ranfor, mcus;
cl349@2957 140 struct bvt_dom_info *inf = BVT_INFO(d->domain);
cl349@2957 141 struct bvt_edom_info *einf = EBVT_INFO(d);
gm281@2063 142
gm281@2063 143 ranfor = (u32)(now - d->lastschd);
gm281@2063 144 mcus = (ranfor + MCU - 1)/MCU;
gm281@2063 145
cl349@2957 146 return einf->avt + mcus * inf->mcu_advance;
gm281@2063 147 }
gm281@2063 148
gm281@2017 149 /*
mwilli2@1232 150 * Calculate the effective virtual time for a domain. Take into account
mwilli2@1232 151 * warping limits
mwilli2@1232 152 */
cl349@2957 153 static inline u32 calc_evt(struct exec_domain *d, u32 avt)
mwilli2@1232 154 {
cl349@2957 155 struct bvt_dom_info *inf = BVT_INFO(d->domain);
kaf24@2633 156 /* TODO The warp routines need to be rewritten GM */
gm281@2063 157
gm281@2096 158 if ( inf->warp )
gm281@2096 159 return avt - inf->warp_value;
mwilli2@1232 160 else
gm281@2063 161 return avt;
mwilli2@1232 162 }
mwilli2@1232 163
mwilli2@1232 164 /**
mwilli2@1232 165 * bvt_alloc_task - allocate BVT private structures for a task
mwilli2@1232 166 * @p: task to allocate private structures for
mwilli2@1232 167 *
mwilli2@1232 168 * Returns non-zero on failure.
mwilli2@1232 169 */
cl349@2957 170 int bvt_alloc_task(struct exec_domain *ed)
mwilli2@1232 171 {
cl349@2957 172 struct domain *d = ed->domain;
cl349@2957 173 if ( (d->sched_priv == NULL) ) {
iap10@3652 174 if ( (d->sched_priv = xmalloc(struct bvt_dom_info)) == NULL )
cl349@2957 175 return -1;
cl349@2957 176 memset(d->sched_priv, 0, sizeof(struct bvt_dom_info));
cl349@2957 177 }
cl349@2957 178 ed->ed_sched_priv = &BVT_INFO(d)->ed_inf[ed->eid];
cl349@2957 179 BVT_INFO(d)->ed_inf[ed->eid].inf = BVT_INFO(d);
cl349@2964 180 BVT_INFO(d)->ed_inf[ed->eid].exec_domain = ed;
mwilli2@1232 181 return 0;
mwilli2@1232 182 }
mwilli2@1232 183
mwilli2@1232 184 /*
mwilli2@1232 185 * Add and remove a domain
mwilli2@1232 186 */
cl349@2957 187 void bvt_add_task(struct exec_domain *d)
mwilli2@1232 188 {
cl349@2957 189 struct bvt_dom_info *inf = BVT_INFO(d->domain);
cl349@2957 190 struct bvt_edom_info *einf = EBVT_INFO(d);
mwilli2@1232 191 ASSERT(inf != NULL);
kaf24@2633 192 ASSERT(d != NULL);
mwilli2@1232 193
cl349@2964 194 if (d->eid == 0) {
cl349@2964 195 inf->mcu_advance = MCU_ADVANCE;
cl349@2964 196 inf->domain = d->domain;
cl349@2964 197 inf->warpback = 0;
cl349@2964 198 /* Set some default values here. */
cl349@2964 199 inf->warp = 0;
cl349@2964 200 inf->warp_value = 0;
cl349@2964 201 inf->warpl = MILLISECS(2000);
cl349@2964 202 inf->warpu = MILLISECS(1000);
cl349@2964 203 /* initialise the timers */
cl349@2964 204 init_ac_timer(&inf->warp_timer);
cl349@2964 205 inf->warp_timer.cpu = d->processor;
cl349@2964 206 inf->warp_timer.data = (unsigned long)inf;
cl349@2964 207 inf->warp_timer.function = &warp_timer_fn;
cl349@2964 208 init_ac_timer(&inf->unwarp_timer);
cl349@2964 209 inf->unwarp_timer.cpu = d->processor;
cl349@2964 210 inf->unwarp_timer.data = (unsigned long)inf;
cl349@2964 211 inf->unwarp_timer.function = &unwarp_timer_fn;
cl349@2964 212 }
cl349@2964 213
cl349@2957 214 einf->exec_domain = d;
cl349@2964 215
cl349@2957 216 if ( d->domain->id == IDLE_DOMAIN_ID )
mwilli2@1232 217 {
cl349@2957 218 einf->avt = einf->evt = ~0U;
mwilli2@1232 219 }
mwilli2@1232 220 else
mwilli2@1232 221 {
mwilli2@1232 222 /* Set avt and evt to system virtual time. */
cl349@2957 223 einf->avt = CPU_SVT(d->processor);
cl349@2957 224 einf->evt = CPU_SVT(d->processor);
kaf24@2633 225 }
mwilli2@1232 226 }
mwilli2@1232 227
cl349@2957 228 int bvt_init_idle_task(struct exec_domain *p)
gm281@1937 229 {
kaf24@2633 230 if ( bvt_alloc_task(p) < 0 )
kaf24@2633 231 return -1;
gm281@1937 232
kaf24@2217 233 bvt_add_task(p);
gm281@1937 234
cl349@2957 235 set_bit(EDF_RUNNING, &p->ed_flags);
gm281@2017 236 if ( !__task_on_runqueue(p) )
gm281@2017 237 __add_to_runqueue_head(p);
gm281@2007 238
gm281@1937 239 return 0;
gm281@1937 240 }
gm281@1937 241
cl349@2957 242 void bvt_wake(struct exec_domain *d)
gm281@2007 243 {
cl349@2957 244 struct bvt_edom_info *einf = EBVT_INFO(d);
cl349@2957 245 struct exec_domain *curr;
gm281@2063 246 s_time_t now, r_time;
gm281@2007 247 int cpu = d->processor;
gm281@2063 248 u32 curr_evt;
gm281@2007 249
gm281@2017 250 if ( unlikely(__task_on_runqueue(d)) )
gm281@2007 251 return;
gm281@2007 252
gm281@2017 253 __add_to_runqueue_head(d);
gm281@2007 254
gm281@2007 255 now = NOW();
gm281@2007 256
gm281@2035 257 /* Set the BVT parameters. AVT should always be updated
kaf24@2633 258 if CPU migration ocurred.*/
cl349@2957 259 if ( einf->avt < CPU_SVT(cpu) ||
cl349@2957 260 unlikely(test_bit(EDF_MIGRATED, &d->ed_flags)) )
cl349@2957 261 einf->avt = CPU_SVT(cpu);
gm281@2007 262
gm281@2007 263 /* Deal with warping here. */
cl349@2957 264 einf->evt = calc_evt(d, einf->avt);
gm281@2007 265
gm281@2007 266 curr = schedule_data[cpu].curr;
gm281@2063 267 curr_evt = calc_evt(curr, calc_avt(curr, now));
gm281@2063 268 /* Calculate the time the current domain would run assuming
gm281@2063 269 the second smallest evt is of the newly woken domain */
gm281@2063 270 r_time = curr->lastschd +
cl349@2957 271 ((einf->evt - curr_evt) / BVT_INFO(curr->domain)->mcu_advance) +
kaf24@2633 272 ctx_allow;
gm281@2007 273
cl349@2957 274 if ( is_idle_task(curr->domain) || (einf->evt <= curr_evt) )
gm281@2007 275 cpu_raise_softirq(cpu, SCHEDULE_SOFTIRQ);
gm281@2063 276 else if ( schedule_data[cpu].s_timer.expires > r_time )
gm281@2063 277 mod_ac_timer(&schedule_data[cpu].s_timer, r_time);
gm281@2007 278 }
gm281@2007 279
gm281@2007 280
cl349@2957 281 static void bvt_sleep(struct exec_domain *d)
gm281@2007 282 {
cl349@2957 283 if ( test_bit(EDF_RUNNING, &d->ed_flags) )
gm281@2007 284 cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ);
kaf24@2633 285 else if ( __task_on_runqueue(d) )
kaf24@2633 286 __del_from_runqueue(d);
gm281@2007 287 }
gm281@2007 288
mwilli2@1232 289 /**
mwilli2@1232 290 * bvt_free_task - free BVT private structures for a task
kaf24@2633 291 * @d: task
mwilli2@1232 292 */
kaf24@2633 293 void bvt_free_task(struct domain *d)
mwilli2@1232 294 {
kaf24@2633 295 ASSERT(d->sched_priv != NULL);
iap10@3651 296 xfree(d->sched_priv);
mwilli2@1232 297 }
mwilli2@1232 298
mwilli2@1232 299 /* Control the scheduler. */
mwilli2@1232 300 int bvt_ctl(struct sched_ctl_cmd *cmd)
mwilli2@1232 301 {
mwilli2@1232 302 struct bvt_ctl *params = &cmd->u.bvt;
mwilli2@1284 303
mwilli2@1284 304 if ( cmd->direction == SCHED_INFO_PUT )
mwilli2@1284 305 ctx_allow = params->ctx_allow;
mwilli2@1284 306 else
mwilli2@1284 307 params->ctx_allow = ctx_allow;
mwilli2@1232 308
mwilli2@1232 309 return 0;
mwilli2@1232 310 }
mwilli2@1232 311
mwilli2@1232 312 /* Adjust scheduling parameter for a given domain. */
kaf24@2633 313 int bvt_adjdom(
kaf24@2633 314 struct domain *d, struct sched_adjdom_cmd *cmd)
mwilli2@1232 315 {
mwilli2@1232 316 struct bvt_adjdom *params = &cmd->u.bvt;
kaf24@2633 317
mwilli2@1284 318 if ( cmd->direction == SCHED_INFO_PUT )
mwilli2@1284 319 {
gm281@2096 320 u32 mcu_adv = params->mcu_adv;
gm281@2096 321 u32 warpback = params->warpback;
gm281@2096 322 s32 warpvalue = params->warpvalue;
gm281@2096 323 s_time_t warpl = params->warpl;
gm281@2096 324 s_time_t warpu = params->warpu;
mwilli2@1284 325
kaf24@2633 326 struct bvt_dom_info *inf = BVT_INFO(d);
mwilli2@1284 327
mwilli2@1284 328 /* Sanity -- this can avoid divide-by-zero. */
kaf24@2633 329 if ( (mcu_adv == 0) || (warpl < 0) || (warpu < 0) )
mwilli2@1284 330 return -EINVAL;
kaf24@2633 331
mwilli2@1284 332 inf->mcu_advance = mcu_adv;
gm281@2129 333 inf->warpback = warpback;
gm281@2129 334 /* The warp should be the same as warpback */
gm281@2129 335 inf->warp = warpback;
gm281@2096 336 inf->warp_value = warpvalue;
gm281@2138 337 inf->warpl = MILLISECS(warpl);
gm281@2138 338 inf->warpu = MILLISECS(warpu);
gm281@2138 339
gm281@2138 340 /* If the unwarp timer set up it needs to be removed */
gm281@2138 341 rem_ac_timer(&inf->unwarp_timer);
gm281@2138 342 /* If we stop warping the warp timer needs to be removed */
kaf24@2633 343 if ( !warpback )
gm281@2138 344 rem_ac_timer(&inf->warp_timer);
mwilli2@1284 345 }
mwilli2@1284 346 else if ( cmd->direction == SCHED_INFO_GET )
mwilli2@1284 347 {
kaf24@2633 348 struct bvt_dom_info *inf = BVT_INFO(d);
gm281@2096 349 params->mcu_adv = inf->mcu_advance;
gm281@2096 350 params->warpvalue = inf->warp_value;
gm281@2096 351 params->warpback = inf->warpback;
gm281@2096 352 params->warpl = inf->warpl;
gm281@2096 353 params->warpu = inf->warpu;
mwilli2@1284 354 }
mwilli2@1284 355
mwilli2@1232 356 return 0;
mwilli2@1232 357 }
mwilli2@1232 358
mwilli2@1232 359
mwilli2@1232 360 /*
mwilli2@1232 361 * The main function
mwilli2@1232 362 * - deschedule the current domain.
mwilli2@1232 363 * - pick a new domain.
mwilli2@1232 364 * i.e., the domain with lowest EVT.
mwilli2@1232 365 * The runqueue should be ordered by EVT so that is easy.
mwilli2@1232 366 */
mwilli2@1232 367 static task_slice_t bvt_do_schedule(s_time_t now)
mwilli2@1232 368 {
cl349@2957 369 struct domain *d;
cl349@2957 370 struct exec_domain *prev = current, *next = NULL, *next_prime, *ed;
mwilli2@1232 371 int cpu = prev->processor;
mwilli2@1232 372 s32 r_time; /* time for new dom to run */
mwilli2@1232 373 u32 next_evt, next_prime_evt, min_avt;
cl349@2957 374 struct bvt_dom_info *prev_inf = BVT_INFO(prev->domain);
cl349@2957 375 struct bvt_edom_info *prev_einf = EBVT_INFO(prev);
cl349@2957 376 struct bvt_edom_info *p_einf = NULL;
cl349@2957 377 struct bvt_edom_info *next_einf = NULL;
cl349@2957 378 struct bvt_edom_info *next_prime_einf = NULL;
mwilli2@1232 379 task_slice_t ret;
mwilli2@1232 380
cl349@2957 381 ASSERT(prev->ed_sched_priv != NULL);
cl349@2957 382 ASSERT(prev_einf != NULL);
gm281@2017 383 ASSERT(__task_on_runqueue(prev));
mwilli2@1232 384
cl349@2957 385 if ( likely(!is_idle_task(prev->domain)) )
mwilli2@1232 386 {
cl349@2957 387 prev_einf->avt = calc_avt(prev, now);
cl349@2957 388 prev_einf->evt = calc_evt(prev, prev_einf->avt);
gm281@2096 389
gm281@2129 390 if(prev_inf->warpback && prev_inf->warpl > 0)
gm281@2129 391 rem_ac_timer(&prev_inf->warp_timer);
gm281@2129 392
gm281@2017 393 __del_from_runqueue(prev);
mwilli2@1232 394
kaf24@1543 395 if ( domain_runnable(prev) )
gm281@2017 396 __add_to_runqueue_tail(prev);
mwilli2@1232 397 }
mwilli2@1232 398
gm281@1937 399
mwilli2@1232 400 /* We should at least have the idle task */
gm281@1937 401 ASSERT(!list_empty(RUNQUEUE(cpu)));
mwilli2@1232 402
mwilli2@1232 403 /*
mwilli2@1232 404 * scan through the run queue and pick the task with the lowest evt
mwilli2@1232 405 * *and* the task the second lowest evt.
mwilli2@1232 406 * this code is O(n) but we expect n to be small.
mwilli2@1232 407 */
cl349@2957 408 next_einf = EBVT_INFO(schedule_data[cpu].idle);
cl349@2957 409 next_prime_einf = NULL;
mwilli2@1232 410
mwilli2@1232 411 next_evt = ~0U;
mwilli2@1232 412 next_prime_evt = ~0U;
mwilli2@1232 413 min_avt = ~0U;
mwilli2@1232 414
kaf24@3571 415 list_for_each_entry ( p_einf, RUNQUEUE(cpu), run_list )
mwilli2@1232 416 {
cl349@2957 417 if ( p_einf->evt < next_evt )
mwilli2@1232 418 {
cl349@2957 419 next_prime_einf = next_einf;
gm281@1937 420 next_prime_evt = next_evt;
cl349@2957 421 next_einf = p_einf;
cl349@2957 422 next_evt = p_einf->evt;
mwilli2@1232 423 }
mwilli2@1232 424 else if ( next_prime_evt == ~0U )
mwilli2@1232 425 {
cl349@2957 426 next_prime_evt = p_einf->evt;
cl349@2957 427 next_prime_einf = p_einf;
mwilli2@1232 428 }
cl349@2957 429 else if ( p_einf->evt < next_prime_evt )
mwilli2@1232 430 {
cl349@2957 431 next_prime_evt = p_einf->evt;
cl349@2957 432 next_prime_einf = p_einf;
mwilli2@1232 433 }
mwilli2@1232 434
mwilli2@1232 435 /* Determine system virtual time. */
cl349@2957 436 if ( p_einf->avt < min_avt )
cl349@2957 437 min_avt = p_einf->avt;
mwilli2@1232 438 }
gm281@2007 439
cl349@2957 440 if(next_einf->inf->warp && next_einf->inf->warpl > 0)
gm281@2129 441 {
gm281@2129 442 /* Set the timer up */
cl349@2957 443 next_einf->inf->warp_timer.expires = now + next_einf->inf->warpl;
gm281@2129 444 /* Add it to the heap */
cl349@2957 445 add_ac_timer(&next_einf->inf->warp_timer);
gm281@2129 446 }
gm281@2129 447
gm281@1937 448 /* Extract the domain pointers from the dom infos */
cl349@2957 449 next = next_einf->exec_domain;
cl349@2957 450 next_prime = next_prime_einf->exec_domain;
gm281@1937 451
mwilli2@1232 452 /* Update system virtual time. */
mwilli2@1232 453 if ( min_avt != ~0U )
mwilli2@1232 454 CPU_SVT(cpu) = min_avt;
mwilli2@1232 455
mwilli2@1232 456 /* check for virtual time overrun on this cpu */
mwilli2@1232 457 if ( CPU_SVT(cpu) >= 0xf0000000 )
mwilli2@1232 458 {
kaf24@2633 459 ASSERT(!local_irq_is_enabled());
kaf24@2633 460
kaf24@2844 461 write_lock(&domlist_lock);
gm281@2007 462
cl349@2957 463 for_each_domain ( d )
mwilli2@1232 464 {
cl349@2957 465 for_each_exec_domain (d, ed) {
cl349@2957 466 if ( ed->processor == cpu )
cl349@2957 467 {
cl349@2957 468 p_einf = EBVT_INFO(ed);
cl349@2957 469 p_einf->evt -= 0xe0000000;
cl349@2957 470 p_einf->avt -= 0xe0000000;
cl349@2957 471 }
mwilli2@1232 472 }
mwilli2@1232 473 }
gm281@2007 474
kaf24@2844 475 write_unlock(&domlist_lock);
gm281@2007 476
mwilli2@1232 477 CPU_SVT(cpu) -= 0xe0000000;
mwilli2@1232 478 }
mwilli2@1232 479
mwilli2@1232 480 /* work out time for next run through scheduler */
cl349@2957 481 if ( is_idle_task(next->domain) )
mwilli2@1232 482 {
mwilli2@1232 483 r_time = ctx_allow;
mwilli2@1232 484 goto sched_done;
mwilli2@1232 485 }
mwilli2@1232 486
cl349@2957 487 if ( (next_prime == NULL) || is_idle_task(next_prime->domain) )
mwilli2@1232 488 {
mwilli2@1232 489 /* We have only one runnable task besides the idle task. */
mwilli2@1232 490 r_time = 10 * ctx_allow; /* RN: random constant */
mwilli2@1232 491 goto sched_done;
mwilli2@1232 492 }
mwilli2@1232 493
mwilli2@1232 494 /*
mwilli2@1232 495 * If we are here then we have two runnable tasks.
mwilli2@1232 496 * Work out how long 'next' can run till its evt is greater than
mwilli2@1232 497 * 'next_prime's evt. Take context switch allowance into account.
mwilli2@1232 498 */
cl349@3037 499 ASSERT(next_prime_einf->evt >= next_einf->evt);
mwilli2@1232 500
cl349@2957 501 r_time = ((next_prime_einf->evt - next_einf->evt)/next_einf->inf->mcu_advance)
mwilli2@1232 502 + ctx_allow;
mwilli2@1232 503
mwilli2@1232 504 ASSERT(r_time >= ctx_allow);
mwilli2@1232 505
mwilli2@1232 506 sched_done:
mwilli2@1232 507 ret.task = next;
mwilli2@1232 508 ret.time = r_time;
mwilli2@1232 509 return ret;
mwilli2@1232 510 }
mwilli2@1232 511
mwilli2@1232 512
cl349@2957 513 static void bvt_dump_runq_el(struct exec_domain *p)
mwilli2@1232 514 {
cl349@2957 515 struct bvt_edom_info *inf = EBVT_INFO(p);
mwilli2@1232 516
gm281@2096 517 printk("mcua=%d ev=0x%08X av=0x%08X ",
cl349@2957 518 inf->inf->mcu_advance, inf->evt, inf->avt);
mwilli2@1232 519 }
mwilli2@1232 520
mwilli2@1232 521 static void bvt_dump_settings(void)
mwilli2@1232 522 {
mwilli2@1232 523 printk("BVT: mcu=0x%08Xns ctx_allow=0x%08Xns ", (u32)MCU, (s32)ctx_allow );
mwilli2@1232 524 }
mwilli2@1232 525
mwilli2@1232 526 static void bvt_dump_cpu_state(int i)
mwilli2@1232 527 {
kaf24@3571 528 struct list_head *queue;
gm281@1937 529 int loop = 0;
cl349@2957 530 struct bvt_edom_info *d_inf;
cl349@2957 531 struct exec_domain *d;
gm281@1937 532
mwilli2@1232 533 printk("svt=0x%08lX ", CPU_SVT(i));
gm281@1937 534
gm281@1937 535 queue = RUNQUEUE(i);
gm281@1937 536 printk("QUEUE rq %lx n: %lx, p: %lx\n", (unsigned long)queue,
kaf24@2633 537 (unsigned long) queue->next, (unsigned long) queue->prev);
gm281@1937 538
kaf24@3571 539 list_for_each_entry ( d_inf, queue, run_list )
gm281@1937 540 {
cl349@2957 541 d = d_inf->exec_domain;
cl349@2957 542 printk("%3d: %u has=%c ", loop++, d->domain->id,
cl349@2957 543 test_bit(EDF_RUNNING, &d->ed_flags) ? 'T':'F');
gm281@1937 544 bvt_dump_runq_el(d);
gm281@1937 545 printk("c=0x%X%08X\n", (u32)(d->cpu_time>>32), (u32)d->cpu_time);
kaf24@3571 546 printk(" l: %p n: %p p: %p\n",
kaf24@3571 547 &d_inf->run_list, d_inf->run_list.next, d_inf->run_list.prev);
gm281@1937 548 }
gm281@1937 549 }
mwilli2@1232 550
mwilli2@1232 551 /* Initialise the data structures. */
mwilli2@1232 552 int bvt_init_scheduler()
mwilli2@1232 553 {
mwilli2@1232 554 int i;
mwilli2@1232 555
mwilli2@1232 556 for ( i = 0; i < NR_CPUS; i++ )
mwilli2@1232 557 {
iap10@3650 558 schedule_data[i].sched_priv = xmalloc(struct bvt_cpu_info);
gm281@2007 559
kaf24@1627 560 if ( schedule_data[i].sched_priv == NULL )
mwilli2@1232 561 {
kaf24@1234 562 printk("Failed to allocate BVT scheduler per-CPU memory!\n");
mwilli2@1232 563 return -1;
mwilli2@1232 564 }
mwilli2@1232 565
gm281@2007 566 INIT_LIST_HEAD(RUNQUEUE(i));
gm281@2007 567
mwilli2@1232 568 CPU_SVT(i) = 0; /* XXX do I really need to do this? */
mwilli2@1232 569 }
mwilli2@1232 570
mwilli2@1232 571 return 0;
mwilli2@1232 572 }
mwilli2@1232 573
mwilli2@1232 574 struct scheduler sched_bvt_def = {
mwilli2@1232 575 .name = "Borrowed Virtual Time",
mwilli2@1232 576 .opt_name = "bvt",
mwilli2@1232 577 .sched_id = SCHED_BVT,
mwilli2@1232 578
mwilli2@1232 579 .init_scheduler = bvt_init_scheduler,
gm281@1937 580 .init_idle_task = bvt_init_idle_task,
mwilli2@1232 581 .alloc_task = bvt_alloc_task,
mwilli2@1232 582 .add_task = bvt_add_task,
mwilli2@1232 583 .free_task = bvt_free_task,
mwilli2@1232 584 .do_schedule = bvt_do_schedule,
mwilli2@1232 585 .control = bvt_ctl,
mwilli2@1232 586 .adjdom = bvt_adjdom,
mwilli2@1232 587 .dump_settings = bvt_dump_settings,
mwilli2@1232 588 .dump_cpu_state = bvt_dump_cpu_state,
kaf24@1916 589 .sleep = bvt_sleep,
kaf24@1916 590 .wake = bvt_wake,
mwilli2@1232 591 };