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