1/** 2 * \file 3 * \brief Resource controller 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <monitor.h> 16 17#define MAX_RSRC_DOMAINS 8 18#define MAX_PHASES 8 19 20struct rsrc_phase { 21 bool active; 22 bool gang_scheduling; 23 enum task_type task_type; 24 unsigned long deadline; 25 unsigned long wcet, period, release; 26 unsigned short weight; 27}; 28 29struct rsrc_domain { 30 bool active; 31 struct monitor_blocking_binding *b; 32 struct capref disp; 33 struct rsrc_phase phase[MAX_PHASES]; 34 int active_phase; 35 bool joined[MAX_CPUS]; 36}; 37 38static struct rsrc_domain domain[MAX_CPUS][MAX_RSRC_DOMAINS]; 39 40static inline coreid_t get_rsrc_coreid(rsrcid_t id) 41{ 42 return id >> 16; 43} 44 45static inline struct rsrc_domain *get_rsrc_domain(rsrcid_t id) 46{ 47 struct rsrc_domain *d = &domain[id >> 16][id & 0xffff]; 48 49 if(d->active) { 50 return d; 51 } else { 52 return NULL; 53 } 54} 55 56static inline bool coordinator(rsrcid_t id) 57{ 58 return get_rsrc_coreid(id) == my_core_id; 59} 60 61static void rsrc_phase_data_done(void *arg) 62{ 63 struct intermon_binding *b = arg; 64 struct intermon_state *st = b->st; 65 66 assert(st != NULL); 67 assert(st->rsrcid_inflight == true); 68 69 errval_t err = b->tx_vtbl.rsrc_join_complete(b, NOP_CONT, st->rsrcid); 70 if (err_is_fail(err)) { 71 USER_PANIC_ERR(err, "sending rsrc_join_complete failed"); 72 } 73 74 st->rsrcid_inflight = false; 75} 76 77struct send_phase_data_state { 78 struct intermon_msg_queue_elem elem; 79 struct intermon_rsrc_phase_data__tx_args args; 80}; 81 82static void send_phase_data_handler(struct intermon_binding *b, 83 struct intermon_msg_queue_elem *e); 84 85static void send_phase_data_cont(struct intermon_binding *b, rsrcid_t id) 86{ 87 errval_t err; 88 struct rsrc_domain *d = get_rsrc_domain(id); 89 assert(d != NULL); 90 struct intermon_state *st = b->st; 91 assert(st != NULL); 92 93 if(st->rsrcid_inflight) { 94 goto busy; 95 } 96 97 st->rsrcid = id; 98 st->rsrcid_inflight = true; 99 100 err = b->tx_vtbl.rsrc_phase_data(b, MKCONT(rsrc_phase_data_done,b), id, 101 d->active_phase, (uint8_t *)&d->phase, 102 sizeof(d->phase)); 103 if (err_is_fail(err)) { 104 st->rsrcid_inflight = false; 105 106 if(err_no(err) == FLOUNDER_ERR_TX_BUSY) 107 busy: 108 { 109 struct send_phase_data_state *me = 110 malloc(sizeof(struct send_phase_data_state)); 111 assert(me != NULL); 112 me->args.id = id; 113 me->elem.cont = send_phase_data_handler; 114 115 err = intermon_enqueue_send(b, &st->queue, 116 get_default_waitset(), 117 &me->elem.queue); 118 if (err_is_fail(err)) { 119 USER_PANIC_ERR(err, "intermon_enqueue_send failed"); 120 } 121 return; 122 } 123 124 USER_PANIC_ERR(err, "sending phase data"); 125 } 126} 127 128static void send_phase_data_handler(struct intermon_binding *b, 129 struct intermon_msg_queue_elem *e) 130{ 131 struct send_phase_data_state *st = (struct send_phase_data_state *)e; 132 send_phase_data_cont(b, st->args.id); 133 free(e); 134} 135 136/** 137 * \brief Send phase data to specified satellite 138 */ 139static void send_phase_data(rsrcid_t id, coreid_t coreid) 140{ 141 struct intermon_binding *b = NULL; 142 errval_t err = intermon_binding_get(coreid, &b); 143 assert(err_is_ok(err)); 144 145 send_phase_data_cont(b, id); 146} 147 148/** 149 * \brief Send phase data to all satellites 150 */ 151static void send_phase_data_all(rsrcid_t id) 152{ 153 struct rsrc_domain *d = get_rsrc_domain(id); 154 assert(d != NULL); 155 156 for(coreid_t i = 0; i < MAX_CPUS; i++) { 157 if(d->joined[i]) { 158 send_phase_data(id, i); 159 } 160 } 161} 162 163errval_t rsrc_join_satellite(rsrcid_t id, coreid_t coreid) 164{ 165 struct rsrc_domain *d = get_rsrc_domain(id); 166 assert(coordinator(id)); 167 168 if(d == NULL) { 169 return MON_ERR_RSRC_NOT_FOUND; 170 } 171 172 d->joined[coreid] = true; 173 174 // Send it the phase data 175 send_phase_data(id, coreid); 176 177 return SYS_ERR_OK; 178} 179 180struct monitor_blocking_binding *rsrc_get_binding(rsrcid_t id) 181{ 182 struct rsrc_domain *d = get_rsrc_domain(id); 183 184 if(d != NULL) { 185 return d->b; 186 } else { 187 return NULL; 188 } 189} 190 191errval_t rsrc_join(rsrcid_t id, struct capref dispcap, 192 struct monitor_blocking_binding *mb) 193{ 194 struct rsrc_domain *d = &domain[id >> 16][id & 0xffff]; 195 196 if(d->active) { 197 return MON_ERR_RSRC_MEMBER_LIMIT; 198 } 199 200 d->active = true; 201 d->disp = dispcap; 202 d->b = mb; 203 204 // Join as a satellite 205 coreid_t coreid = get_rsrc_coreid(id); 206 if(!coordinator(id)) { 207 struct intermon_binding *b = NULL; 208 errval_t err = intermon_binding_get(coreid, &b); 209 assert(err_is_ok(err)); 210 err = b->tx_vtbl.rsrc_join(b, NOP_CONT, id, my_core_id); 211 assert(err_is_ok(err)); 212 } 213 214 return SYS_ERR_OK; 215} 216 217errval_t rsrc_new(rsrcid_t *id) 218{ 219 static int idx = 0; 220 221 if(idx >= MAX_RSRC_DOMAINS) { 222 return MON_ERR_RSRC_ALLOC; 223 } 224 225 *id = (my_core_id << 16) | idx; 226 idx++; 227 return SYS_ERR_OK; 228} 229 230errval_t rsrc_submit_manifest(rsrcid_t id, char *manifest) 231{ 232 struct rsrc_domain *d = get_rsrc_domain(id); 233 int phase = 0; 234 235 if(d == NULL) { 236 return MON_ERR_RSRC_NOT_FOUND; 237 } 238 239 // Can only submit manifests on the master for now 240 assert(get_rsrc_coreid(id) == my_core_id); 241 242 // Parse manifest 243 for(char *p = manifest; *p != '\0'; p = strchr(p, '\n') + 1) { 244 unsigned long wcet, period, deadline, release; 245 unsigned int weight; 246 char type; 247 248 struct rsrc_phase *rp = &d->phase[phase]; 249 250 rp->active = true; 251 int rd = sscanf(p, "%c", &type); 252 if(rd != 1) { 253 return MON_ERR_RSRC_ILL_MANIFEST; 254 } 255 256 switch(type) { 257 case 'G': 258 case 'H': 259 if((rd = sscanf(p, "%c %lu %lu %lu %lu\n", &type, &wcet, &period, 260 &deadline, &release)) < 3) { 261 return MON_ERR_RSRC_ILL_MANIFEST; 262 } 263 264 printf("phase %d: %s with WCET = %lu, period = %lu, " 265 "deadline = %lu, release = %lu\n", phase, 266 type == 'G' ? "gang scheduled" : "hard real-time", 267 wcet, period, deadline, release); 268 rp->gang_scheduling = (type == 'G') ? true : false; 269 rp->task_type = TASK_TYPE_HARD_REALTIME; 270 rp->wcet = wcet; 271 rp->period = period; 272 if(rd >= 4) { 273 rp->deadline = deadline; 274 } else { 275 rp->deadline = period; 276 } 277 if(rd == 5) { 278 rp->release = release; 279 } else { 280 rp->release = 0; 281 } 282 break; 283 284 case 'B': 285 if(sscanf(p, "B %u\n", &weight) != 1) { 286 return MON_ERR_RSRC_ILL_MANIFEST; 287 } 288 printf("phase %d: best effort with weight %d\n", phase, weight); 289 rp->task_type = TASK_TYPE_BEST_EFFORT; 290 rp->weight = weight; 291 break; 292 293 default: 294 // TODO: Cleanup 295 return MON_ERR_RSRC_ILL_MANIFEST; 296 } 297 298 phase++; 299 } 300 301 // Activate first phase locally 302 //activate_phase(id, d, active); 303 304 // Update satellites 305 send_phase_data_all(id); 306 307 return SYS_ERR_OK; 308} 309 310/** 311 * \brief Activates a resource phase locally 312 */ 313static void activate_phase(rsrcid_t id, struct rsrc_domain *d, uintptr_t phase, 314 uint64_t timestamp) 315{ 316 errval_t err; 317 struct rsrc_phase *p = &d->phase[phase]; 318 319 d->active_phase = phase; 320 assert(p->active); 321 322 // Set phase parameters 323 err = invoke_dispatcher_properties(d->disp, p->task_type, p->deadline, p->wcet, 324 p->period, p->release + timestamp, p->weight); 325 assert(err_is_ok(err)); 326} 327 328struct rsrc_phase_state { 329 struct intermon_msg_queue_elem elem; 330 struct intermon_rsrc_phase__tx_args args; 331}; 332 333static void rsrc_phase_handler(struct intermon_binding *b, 334 struct intermon_msg_queue_elem *e); 335 336static void rsrc_phase_cont(struct intermon_binding *b, rsrcid_t id, 337 uintptr_t phase, uint64_t timestamp) 338{ 339 errval_t err = b->tx_vtbl.rsrc_phase(b, NOP_CONT, id, phase, timestamp); 340 if(err_is_fail(err)) { 341 if(err_no(err) == FLOUNDER_ERR_TX_BUSY) { 342 struct intermon_state *st = b->st; 343 assert(st != NULL); 344 struct rsrc_phase_state *me = 345 malloc(sizeof(struct rsrc_phase_state)); 346 assert(me != NULL); 347 me->args.id = id; 348 me->args.phase = phase; 349 me->args.timestamp = timestamp; 350 me->elem.cont = rsrc_phase_handler; 351 352 err = intermon_enqueue_send(b, &st->queue, 353 get_default_waitset(), 354 &me->elem.queue); 355 if (err_is_fail(err)) { 356 USER_PANIC_ERR(err, "intermon_enqueue_send failed"); 357 } 358 return; 359 } 360 USER_PANIC_ERR(err, "sending phase change to satellites"); 361 } 362 assert(err_is_ok(err)); 363} 364 365static void rsrc_phase_handler(struct intermon_binding *b, 366 struct intermon_msg_queue_elem *e) 367{ 368 struct rsrc_phase_state *st = (struct rsrc_phase_state *)e; 369 rsrc_phase_cont(b, st->args.id, st->args.phase, st->args.timestamp); 370 free(e); 371} 372 373errval_t rsrc_set_phase_inter(rsrcid_t id, uintptr_t phase, uint64_t timestamp) 374{ 375 struct rsrc_domain *d = get_rsrc_domain(id); 376 377 if(d == NULL) { 378 return MON_ERR_RSRC_NOT_FOUND; 379 } 380 381 activate_phase(id, d, phase, timestamp); 382 383 // Done if satellite 384 if(!coordinator(id)) { 385 return SYS_ERR_OK; 386 } 387 388 // Coordinator: Change the phase globally 389 for(int i = 0; i < MAX_CPUS; i++) { 390 if(d->joined[i]) { 391 struct intermon_binding *b = NULL; 392 errval_t err = intermon_binding_get(i, &b); 393 assert(err_is_ok(err)); 394 rsrc_phase_cont(b, id, phase, timestamp); 395 } 396 } 397 398 return SYS_ERR_OK; 399} 400 401errval_t rsrc_set_phase(rsrcid_t id, uintptr_t phase) 402{ 403 // Send to other monitors to change phase globally 404 if(coordinator(id)) { 405 // Relative times are relative to now 406 uint64_t now; 407#if defined(__x86_64__) || defined(__i386__) 408 errval_t err = sys_debug_timeslice_counter_read(&now); 409 assert(err_is_ok(err)); 410#else 411 now = 0; 412#endif 413 414 // Coordinator: Change the phase globally 415 rsrc_set_phase_inter(id, phase, now); 416 } else { 417 assert(!"no"); 418#if 0 419 // Satellite: Tell coordinator 420 coreid_t coreid = get_rsrc_coreid(id); 421 struct intermon_binding *b = NULL; 422 errval_t err = intermon_binding_get(coreid, &b); 423 assert(err_is_ok(err)); 424 err = b->tx_vtbl.rsrc_phase(b, NOP_CONT, id, phase); 425 assert(err_is_ok(err)); 426#endif 427 } 428 429 return SYS_ERR_OK; 430} 431 432errval_t rsrc_set_phase_data(rsrcid_t id, uintptr_t active, void *data, 433 size_t len) 434{ 435 struct rsrc_domain *d = get_rsrc_domain(id); 436 437 if(d == NULL) { 438 return MON_ERR_RSRC_NOT_FOUND; 439 } 440 441 // Activate current phase 442 //activate_phase(id, d, active); 443 444 // Copy phase data 445 assert(len == sizeof(d->phase)); 446 memcpy(&d->phase, data, len); 447 448 return SYS_ERR_OK; 449} 450