]> rtime.felk.cvut.cz Git - frescor/frsh.git/blob - frsh_api/frsh_power.c
Added speed reading functions.
[frescor/frsh.git] / frsh_api / frsh_power.c
1 /**
2  * @file   frsh_power.c
3  * @author Michael Trimarchi <trimarchimichael@yahoo.it>
4  *         Dario Faggioli <faggioli@gandalf.sssup.it>
5  *
6  * @brief  FRSH core thread related functions not implamented in managers..
7  *
8  *
9  */
10
11 #include <string.h>
12
13 #include <fres_contract.h>
14 #include <fres_contract_idl.h>
15 #include <fres_blocks.h>
16 #include <fcb.h>
17 #include <fra_generic.h>
18 #include <frsh_forb.h>
19 #include "frsh_resources.h"
20 #ifdef CONFIG_ACPI_CPU
21 #  include <fra_acpi_cpu.h>
22 #endif
23 #ifdef CONFIG_ACPI_BATTERY
24 #  include "fra_acpi_battery.h"
25 #endif
26 #ifdef CONFIG_ACPI_LCD
27 #  include <fra_acpi_lcd.h>
28 #endif
29 #include <frsh.h>
30
31 static inline int __is_a_valid_power(int level)
32 {
33         if (level >= 0 && level < 3 )
34                 return 1;
35
36         return 0;
37 }
38
39 static inline
40 fres_block_power_management *__dup_power_management(frsh_contract_t *contract)
41 {
42         fres_block_power_management *p, *old_p;
43
44         old_p = fres_contract_get_power_management(*contract);
45         p = malloc(sizeof(*p));
46         if (!p) return 0;
47         /**
48          * Needed since frsh_contract_del_xxx frees the
49          *  old block.
50          **/
51         if (old_p)
52                 memcpy(p, old_p, sizeof(*old_p));
53         else
54                 bzero(p, sizeof(*p));
55
56         return p;
57 }
58
59 int frsh_contract_set_min_expiration(frsh_contract_t *contract,
60                                      frsh_rel_time_t min_expiration)
61 {
62         fres_block_power_management *p;
63         int ret;
64
65         if (!contract || !*contract)
66                 return FRSH_ERR_BAD_ARGUMENT;
67
68         p = __dup_power_management(contract);
69         if (!p)
70                 return ENOMEM;
71
72         p->min_expiration = min_expiration;
73
74         fres_contract_del_power_management(*contract);
75         ret = fres_contract_add_power_management(*contract, p);
76         if (ret) {
77                 free(p);
78                 return errno;
79         }
80
81         return FRSH_NO_ERROR;
82 }
83
84 int frsh_contract_get_min_expiration(const frsh_contract_t *contract,
85                                      frsh_rel_time_t *min_expiration)
86 {
87         fres_block_power_management *p;
88
89         if (!contract || !*contract)
90                 return FRSH_ERR_BAD_ARGUMENT;
91
92         p = fres_contract_get_power_management(*contract);
93         if (!p)
94                 return FRSH_ERR_BAD_ARGUMENT;
95
96         *min_expiration = p->min_expiration;
97
98         return FRSH_NO_ERROR;
99 }
100
101 int frsh_contract_set_min_budget_pow
102   (frsh_contract_t *contract,
103    frsh_power_level_t power_level,
104    const frsh_rel_time_t *pow_min_budget)
105 {
106         fres_block_power_management *b;
107         int ret;
108
109         if (!contract || !*contract ||
110             !pow_min_budget)
111                 return FRSH_ERR_BAD_ARGUMENT;
112
113         b = __dup_power_management(contract);
114         if (!b)
115                 return ENOMEM;
116
117         b->min_budget[power_level] = *pow_min_budget;
118
119         fres_contract_del_power_management(*contract);
120         ret = fres_contract_add_power_management(*contract, b);
121         if (ret) {
122                 free(b);
123                 return errno;
124         }
125
126         return FRSH_NO_ERROR;
127 }
128
129 int frsh_contract_get_min_budget_pow
130   (const frsh_contract_t *contract,
131    frsh_power_level_t power_level,
132    frsh_rel_time_t *pow_min_budget)
133 {
134         fres_block_power_management *b;
135
136         if (!contract || !*contract ||
137             !__is_a_valid_power(power_level))
138                 return FRSH_ERR_BAD_ARGUMENT;
139
140         b = fres_contract_get_power_management(*contract);
141         if (!b)
142                 return FRSH_ERR_BAD_ARGUMENT;
143
144         *pow_min_budget = b->min_budget[power_level];
145
146         return FRSH_NO_ERROR;
147 }
148
149 int frsh_contract_set_max_budget_pow
150   (frsh_contract_t *contract,
151    frsh_power_level_t power_level,
152    const frsh_rel_time_t *pow_max_budget)
153 {
154         fres_block_power_management *b;
155         int ret;
156
157         if (!contract || !*contract ||
158             !pow_max_budget || !__is_a_valid_power(power_level))
159                 return FRSH_ERR_BAD_ARGUMENT;
160
161         b = __dup_power_management(contract);
162         if (!b)
163                 return ENOMEM;
164
165         b->max_budget[power_level] = *pow_max_budget;
166
167         fres_contract_del_power_management(*contract);
168         ret = fres_contract_add_power_management(*contract, b);
169         if (ret) {
170                 free(b);
171                 return errno;
172         }
173
174         return FRSH_NO_ERROR;
175 }
176
177 int frsh_contract_get_max_budget_pow(const frsh_contract_t *contract,
178                                      frsh_power_level_t power_level,
179                                      frsh_rel_time_t *pow_max_budget)
180 {
181         fres_block_power_management *b;
182
183         if (!contract || !*contract ||
184             !__is_a_valid_power(power_level)) {
185                 return FRSH_ERR_BAD_ARGUMENT;
186         }
187
188         b = fres_contract_get_power_management(*contract);
189         if (!b)
190                 return FRSH_ERR_BAD_ARGUMENT;
191
192         *pow_max_budget = b->max_budget[power_level];
193
194         return FRSH_NO_ERROR;
195 }
196
197 int frsh_contract_set_utilization_pow
198   (frsh_contract_t *contract,
199    frsh_power_level_t power_level,
200    const frsh_rel_time_t *budget,
201    const frsh_rel_time_t *period,
202    const frsh_rel_time_t *deadline)
203 {
204         return FRSH_ERR_NOT_IMPLEMENTED;
205 }
206
207 int frsh_contract_get_utilization_pow
208   (const frsh_contract_t *contract,
209    frsh_power_level_t power_level,
210    frsh_rel_time_t *budget,
211    frsh_rel_time_t *period,
212    frsh_rel_time_t *deadline)
213 {
214         return FRSH_ERR_NOT_IMPLEMENTED;;
215 }
216
217 /* FIXME: What happens when one application set one power-level and
218  * second application different level. I think this function should
219  * not be part of API. It should be used internally (e.g. by contract
220  * broker) to achieve the requirements specified by
221  * frsh_contract_set_min_expiration() and similar functions.
222  *
223  * This implementation also skips FCB when doing changes to resources,
224  * which is certainly not good, because resource manager does not know
225  * about the change.
226  */
227 int frsh_resource_set_power_level
228   (frsh_resource_type_t resource_type,
229    frsh_resource_id_t resource_id,
230    frsh_power_level_t power_level)
231 {
232
233         if (!__is_a_valid_power(power_level))
234                 return FRSH_ERR_BAD_ARGUMENT;
235
236         switch(resource_type)
237         {
238 #ifdef CONFIG_ACPI_CPU
239                 case FRSH_RT_PROCESSOR:
240                 {
241                         int ret;
242                         ret = fra_CPU_power_init(resource_id);
243                         if (ret) return FRSH_ERR_INTERNAL_ERROR;
244                         ret = fra_CPU_set_power(resource_id, power_level);
245                         if (ret) return FRSH_ERR_INTERNAL_ERROR;
246
247                         /**
248                          * @TODO:
249                          * if (i budget sono effettivamente diversi)
250                          *      rinegozia i contratti coi nuovi valori
251                          **/
252                         break;
253                 }
254 #endif
255 #ifdef CONFIG_ACPI_LCD
256                 case FRSH_RT_LCD:
257                 {
258                         int ret;
259                         ret = fra_LCD_power_init(resource_id);
260                         if (ret) return FRSH_ERR_INTERNAL_ERROR;
261                         ret = fra_LCD_set_power(resource_id, power_level);
262                         if (ret) return FRSH_ERR_INTERNAL_ERROR;
263                         break;
264                 }
265 #endif
266                 default:
267                         return FRSH_ERR_NOT_IMPLEMENTED;
268         }
269
270         return FRSH_NO_ERROR;
271 }
272
273 int frsh_resource_get_power_level
274   (frsh_resource_type_t resource_type,
275    frsh_resource_id_t resource_id,
276    frsh_power_level_t *power_level)
277 {
278         switch(resource_type)
279         {
280 #ifdef CONFIG_ACPI_CPU
281                 case FRSH_RT_PROCESSOR:
282                 {
283                         int ret;
284                         ret = fra_CPU_get_power(resource_id,
285                                                 (int*) power_level);
286                         if (ret) return FRSH_ERR_INTERNAL_ERROR;
287
288                         break;
289                 }
290 #endif
291 #ifdef CONFIG_ACPI_LCD
292                 case FRSH_RT_LCD:
293                 {
294                         int ret;
295                         ret = fra_LCD_get_power(resource_id,
296                                                 (int*) power_level);
297                         if (ret) return FRSH_ERR_INTERNAL_ERROR;
298
299                         break;
300                 }
301 #endif
302                 default:
303                         return FRSH_ERR_NOT_IMPLEMENTED;
304         }
305
306         return FRSH_NO_ERROR;
307 }
308
309 int frsh_resource_get_speed
310   (frsh_resource_type_t resource_type,
311    frsh_resource_id_t resource_id,
312    frsh_power_level_t power_level,
313    double *speed_ratio)
314 {
315         switch(resource_type)
316         {
317 #ifdef CONFIG_ACPI_CPU
318                 case FRSH_RT_PROCESSOR:
319                 {
320                         int ret;
321
322                         ret = fra_CPU_power_init(resource_id);
323                         if (ret) return FRSH_ERR_INTERNAL_ERROR;
324                         ret = fra_CPU_get_speed(resource_id,
325                                                 (int) power_level,
326                                                 speed_ratio);
327                         if (ret) return FRSH_ERR_INTERNAL_ERROR;
328
329                         break;
330                 }
331 #endif
332 #ifdef CONFIG_ACPI_LCD
333                 case FRSH_RT_LCD:
334                 {
335                         int ret;
336
337                         ret = fra_LCD_power_init(resource_id);
338                         if (ret) return FRSH_ERR_INTERNAL_ERROR;
339                         ret = fra_LCD_get_speed(resource_id,
340                                                 (int) power_level,
341                                                 speed_ratio);
342                         if (ret) return FRSH_ERR_INTERNAL_ERROR;
343
344                         break;
345                 }
346 #endif
347                 default:
348                         return FRSH_ERR_NOT_IMPLEMENTED;
349         }
350
351         return FRSH_NO_ERROR;
352 }
353
354 int frsh_resource_get_num_power_levels
355   (frsh_resource_type_t resource_type,
356    frsh_resource_id_t resource_id,
357    int *num_power_levels)
358 {
359         int ret;
360
361         *num_power_levels = 1;
362
363         switch(resource_type)
364         {
365                 case FRSH_RT_PROCESSOR:
366                 {
367                         ret = fra_CPU_power_init(resource_id);
368                         if (ret) goto out;
369
370                         break;
371                 }
372                 case FRSH_RT_LCD:
373                 {
374                         ret = fra_LCD_power_init(resource_id);
375                         if (ret) goto out;
376
377                         break;
378                 }
379                 default:
380                         return FRSH_ERR_NOT_IMPLEMENTED;
381         }
382
383         /**
384          * @FIXME:
385          *   This looks tremendous... But the number '3' is hardcoded
386          *   whereever in the headers as the number of power level, so...
387          */
388         *num_power_levels = 3;
389
390 out:
391         return FRSH_NO_ERROR;
392 }
393
394 int frsh_battery_get_expiration(frsh_abs_time_t *expiration)
395 {
396 #ifdef CONFIG_ACPI_BATTERY
397         frsh_rel_time_t interval;
398         int ret;
399
400         ret = fra_battery_init();
401         if (ret) return FRSH_ERR_INTERNAL_ERROR;
402
403         ret = fra_battery_expiration(&interval);
404         if (ret == EAGAIN) return ret;
405         if (ret) return FRSH_ERR_INTERNAL_ERROR;
406
407         fosa_clock_get_time(FOSA_CLOCK_REALTIME, expiration);
408         *expiration = fosa_abs_time_incr(*expiration, interval);
409
410         return FRSH_NO_ERROR;
411 #else
412         return FRSH_ERR_NOT_IMPLEMENTED;        
413 #endif
414 }
415