a34d2cb0c0ba4ecbe1cc7dde037ac2c5fe50ba7d
[kernel/swap-modules.git] / energy / energy.c
1 /*
2  *  Dynamic Binary Instrumentation Module based on KProbes
3  *  modules/energy/swap_energy.c
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  * Copyright (C) Samsung Electronics, 2013
20  *
21  * 2013         Vasiliy Ulyanov <v.ulyanov@samsung.com>
22  *              Vyacheslav Cherkashin <v.cherkashin@samsung.com>
23  *
24  */
25
26
27 #include <linux/module.h>
28 #include <linux/file.h>
29 #include <linux/spinlock.h>
30 #include <linux/magic.h>
31 #include <linux/slab.h>
32 #include <linux/spinlock.h>
33 #include <linux/net.h>
34 #include <linux/socket.h>
35 #include <linux/skbuff.h>
36 #include <linux/string.h>
37 #include <linux/fdtable.h>
38 #include <net/sock.h>
39 #include <kprobe/swap_kprobes.h>
40 #include <ksyms/ksyms.h>
41 #include <master/swap_deps.h>
42 #include <us_manager/sspt/sspt_proc.h>
43 #include <us_manager/sspt/sspt_feature.h>
44 #include <linux/atomic.h>
45 #include "energy.h"
46 #include "lcd/lcd_base.h"
47 #include "tm_stat.h"
48
49
50 /* ============================================================================
51  * =                              ENERGY_XXX                                  =
52  * ============================================================================
53  */
54 struct kern_probe {
55         const char *name;
56         struct kretprobe *rp;
57 };
58
59 static int energy_xxx_once(struct kern_probe p[], int size)
60 {
61         int i;
62         const char *sym;
63
64         for (i = 0; i < size; ++i) {
65                 struct kretprobe *rp = p[i].rp;
66
67                 sym = p[i].name;
68                 rp->kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
69                 if (rp->kp.addr == NULL)
70                         goto not_found;
71         }
72
73         return 0;
74
75 not_found:
76         printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
77         return -ESRCH;
78 }
79
80 static int energy_xxx_set(struct kern_probe p[], int size, int *flag)
81 {
82         int i, ret;
83
84         for (i = 0; i < size; ++i) {
85                 ret = swap_register_kretprobe(p[i].rp);
86                 if (ret)
87                         goto fail;
88         }
89
90         *flag = 1;
91         return 0;
92
93 fail:
94         pr_err("swap_register_kretprobe(%s) ret=%d\n", p[i].name, ret);
95
96         for (--i; i != -1; --i)
97                 swap_unregister_kretprobe(p[i].rp);
98
99         return ret;
100 }
101
102 static void energy_xxx_unset(struct kern_probe p[], int size, int *flag)
103 {
104         int i;
105
106         if (*flag == 0)
107                 return;
108
109         for (i = size - 1; i != -1; --i)
110                 swap_unregister_kretprobe(p[i].rp);
111
112         *flag = 0;
113 }
114
115
116
117
118
119 /* ============================================================================
120  * =                              CPUS_TIME                                   =
121  * ============================================================================
122  */
123 struct cpus_time {
124         spinlock_t lock; /* for concurrent access */
125         struct tm_stat tm[NR_CPUS];
126 };
127
128 #define cpus_time_lock(ct, flags) spin_lock_irqsave(&(ct)->lock, flags)
129 #define cpus_time_unlock(ct, flags) spin_unlock_irqrestore(&(ct)->lock, flags)
130
131 static void cpus_time_init(struct cpus_time *ct, u64 time)
132 {
133         int cpu;
134
135         spin_lock_init(&ct->lock);
136
137         for (cpu = 0; cpu < NR_CPUS; ++cpu) {
138                 tm_stat_init(&ct->tm[cpu]);
139                 tm_stat_set_timestamp(&ct->tm[cpu], time);
140         }
141 }
142
143 static inline u64 cpu_time_get_running(struct cpus_time *ct, int cpu, u64 now)
144 {
145         return tm_stat_current_running(&ct->tm[cpu], now);
146 }
147
148 static void *cpus_time_get_running_all(struct cpus_time *ct, u64 *buf, u64 now)
149 {
150         int cpu;
151
152         for (cpu = 0; cpu < NR_CPUS; ++cpu)
153                 buf[cpu] = tm_stat_current_running(&ct->tm[cpu], now);
154
155         return buf;
156 }
157
158 static void *cpus_time_sum_running_all(struct cpus_time *ct, u64 *buf, u64 now)
159 {
160         int cpu;
161
162         for (cpu = 0; cpu < NR_CPUS; ++cpu)
163                 buf[cpu] += tm_stat_current_running(&ct->tm[cpu], now);
164
165         return buf;
166 }
167
168 static void cpus_time_save_entry(struct cpus_time *ct, int cpu, u64 time)
169 {
170         struct tm_stat *tm = &ct->tm[cpu];
171
172         if (unlikely(tm_stat_timestamp(tm))) /* should never happen */
173                 printk("XXX %s[%d/%d]: WARNING tmstamp(%p) set on cpu(%d)\n",
174                        current->comm, current->tgid, current->pid, tm, cpu);
175         tm_stat_set_timestamp(&ct->tm[cpu], time);
176 }
177
178 static void cpus_time_update_running(struct cpus_time *ct, int cpu, u64 now,
179                                      u64 start_time)
180 {
181         struct tm_stat *tm = &ct->tm[cpu];
182
183         if (unlikely(tm_stat_timestamp(tm) == 0)) {
184                  /* not initialized. should happen only once per cpu/task */
185                 printk("XXX %s[%d/%d]: nnitializing tmstamp(%p) on cpu(%d)\n",
186                        current->comm, current->tgid, current->pid, tm, cpu);
187                 tm_stat_set_timestamp(tm, start_time);
188         }
189
190         tm_stat_update(tm, now);
191         tm_stat_set_timestamp(tm, 0); /* set timestamp to 0 */
192 }
193
194
195
196
197
198 struct energy_data {
199         /* for __switch_to */
200         struct cpus_time ct;
201
202         /* for sys_read */
203         atomic64_t bytes_read;
204
205         /*for sys_write */
206         atomic64_t bytes_written;
207
208         /*for recvmsg*/
209         atomic64_t bytes_recv;
210
211         /* for sock_send */
212         atomic64_t bytes_send;
213
214         /* for l2cap_recv */
215         atomic64_t bytes_l2cap_recv_acldata;
216
217         /* for sco_recv_scodata */
218         atomic64_t bytes_sco_recv_scodata;
219
220         /* for hci_send_acl */
221         atomic64_t bytes_hci_send_acl;
222
223         /* for hci_send_sco */
224         atomic64_t bytes_hci_send_sco;
225 };
226
227 static sspt_feature_id_t feature_id = SSPT_FEATURE_ID_BAD;
228
229 static void init_ed(struct energy_data *ed)
230 {
231         /* instead of get_ntime(), CPU time is initialized to 0 here. Timestamp
232          * value will be properly set when the corresponding __switch_to event
233          * occurs */
234         cpus_time_init(&ed->ct, 0);
235         atomic64_set(&ed->bytes_read, 0);
236         atomic64_set(&ed->bytes_written, 0);
237         atomic64_set(&ed->bytes_recv, 0);
238         atomic64_set(&ed->bytes_send, 0);
239         atomic64_set(&ed->bytes_l2cap_recv_acldata, 0);
240         atomic64_set(&ed->bytes_sco_recv_scodata, 0);
241         atomic64_set(&ed->bytes_hci_send_acl, 0);
242         atomic64_set(&ed->bytes_hci_send_sco, 0);
243 }
244
245 static void uninit_ed(struct energy_data *ed)
246 {
247         cpus_time_init(&ed->ct, 0);
248         atomic64_set(&ed->bytes_read, 0);
249         atomic64_set(&ed->bytes_written, 0);
250         atomic64_set(&ed->bytes_recv, 0);
251         atomic64_set(&ed->bytes_send, 0);
252         atomic64_set(&ed->bytes_l2cap_recv_acldata, 0);
253         atomic64_set(&ed->bytes_sco_recv_scodata, 0);
254         atomic64_set(&ed->bytes_hci_send_acl, 0);
255         atomic64_set(&ed->bytes_hci_send_sco, 0);
256 }
257
258 static void *create_ed(void)
259 {
260         struct energy_data *ed;
261
262         ed = kmalloc(sizeof(*ed), GFP_ATOMIC);
263         if (ed)
264                 init_ed(ed);
265
266         return (void *)ed;
267 }
268
269 static void destroy_ed(void *data)
270 {
271         struct energy_data *ed = (struct energy_data *)data;
272         kfree(ed);
273 }
274
275
276 static int init_feature(void)
277 {
278         feature_id = sspt_register_feature(create_ed, destroy_ed);
279
280         if (feature_id == SSPT_FEATURE_ID_BAD)
281                 return -EPERM;
282
283         return 0;
284 }
285
286 static void uninit_feature(void)
287 {
288         sspt_unregister_feature(feature_id);
289         feature_id = SSPT_FEATURE_ID_BAD;
290 }
291
292 static struct energy_data *get_energy_data(struct task_struct *task)
293 {
294         void *data = NULL;
295         struct sspt_proc *proc;
296
297         proc = sspt_proc_get_by_task(task);
298         if (proc)
299                 data = sspt_get_feature_data(proc->feature, feature_id);
300
301         return (struct energy_data *)data;
302 }
303
304 static int check_fs(unsigned long magic)
305 {
306         switch (magic) {
307         case EXT2_SUPER_MAGIC: /* == EXT3_SUPER_MAGIC == EXT4_SUPER_MAGIC */
308         case MSDOS_SUPER_MAGIC:
309                 return 1;
310         }
311
312         return 0;
313 }
314
315 static int check_ftype(int fd)
316 {
317         int err, ret = 0;
318         struct kstat kstat;
319
320         err = vfs_fstat(fd, &kstat);
321         if (err == 0 && S_ISREG(kstat.mode))
322                 ret = 1;
323
324         return ret;
325 }
326
327 static int check_file(int fd)
328 {
329         struct file *file;
330
331         file = fget(fd);
332         if (file) {
333                 int magic = 0;
334                 if (file->f_dentry && file->f_dentry->d_sb)
335                         magic = file->f_dentry->d_sb->s_magic;
336
337                 fput(file);
338
339                 if (check_fs(magic) && check_ftype(fd))
340                         return 1;
341         }
342
343         return 0;
344 }
345
346 static unsigned long get_arg0(struct pt_regs *regs)
347 {
348 #if defined(CONFIG_ARM)
349         return regs->ARM_r0;
350 #elif defined(CONFIG_X86_32)
351         return regs->bx;
352 #else
353         #error "this architecture is not supported"
354 #endif /* CONFIG_arch */
355 }
356
357
358
359
360
361 static struct cpus_time ct_idle;
362 static struct energy_data ed_system;
363 static u64 start_time;
364
365 static void init_data_energy(void)
366 {
367         start_time = get_ntime();
368         init_ed(&ed_system);
369         cpus_time_init(&ct_idle, 0);
370 }
371
372 static void uninit_data_energy(void)
373 {
374         start_time = 0;
375         uninit_ed(&ed_system);
376         cpus_time_init(&ct_idle, 0);
377 }
378
379
380
381
382
383 /* ============================================================================
384  * =                             __switch_to                                  =
385  * ============================================================================
386  */
387 static int entry_handler_switch(struct kretprobe_instance *ri, struct pt_regs *regs)
388 {
389         int cpu;
390         struct cpus_time *ct;
391         struct energy_data *ed;
392         unsigned long flags;
393
394         cpu = smp_processor_id();
395
396         ct = current->tgid ? &ed_system.ct: &ct_idle;
397         cpus_time_lock(ct, flags);
398         cpus_time_update_running(ct, cpu, get_ntime(), start_time);
399         cpus_time_unlock(ct, flags);
400
401         ed = get_energy_data(current);
402         if (ed) {
403                 ct = &ed->ct;
404                 cpus_time_lock(ct, flags);
405                 cpus_time_update_running(ct, cpu, get_ntime(), start_time);
406                 cpus_time_unlock(ct, flags);
407         }
408
409         return 0;
410 }
411
412 static int ret_handler_switch(struct kretprobe_instance *ri, struct pt_regs *regs)
413 {
414         int cpu;
415         struct cpus_time *ct;
416         struct energy_data *ed;
417         unsigned long flags;
418
419         cpu = smp_processor_id();
420
421         ct = current->tgid ? &ed_system.ct: &ct_idle;
422         cpus_time_lock(ct, flags);
423         cpus_time_save_entry(ct, cpu, get_ntime());
424         cpus_time_unlock(ct, flags);
425
426         ed = get_energy_data(current);
427         if (ed) {
428                 ct = &ed->ct;
429                 cpus_time_lock(ct, flags);
430                 cpus_time_save_entry(ct, cpu, get_ntime());
431                 cpus_time_unlock(ct, flags);
432         }
433
434         return 0;
435 }
436
437 static struct kretprobe switch_to_krp = {
438         .entry_handler = entry_handler_switch,
439         .handler = ret_handler_switch,
440 };
441
442
443
444
445
446 /* ============================================================================
447  * =                                sys_read                                  =
448  * ============================================================================
449  */
450 struct sys_read_data {
451         int fd;
452 };
453
454 static int entry_handler_sys_read(struct kretprobe_instance *ri, struct pt_regs *regs)
455 {
456         struct sys_read_data *srd = (struct sys_read_data *)ri->data;
457
458         srd->fd = (int)get_arg0(regs);
459
460         return 0;
461 }
462
463 static int ret_handler_sys_read(struct kretprobe_instance *ri,
464                                 struct pt_regs *regs)
465 {
466         int ret = regs_return_value(regs);
467
468         if (ret > 0) {
469                 struct sys_read_data *srd;
470
471                 srd = (struct sys_read_data *)ri->data;
472                 if (check_file(srd->fd)) {
473                         struct energy_data *ed;
474
475                         ed = get_energy_data(current);
476                         if (ed)
477                                 atomic64_add(ret, &ed->bytes_read);
478
479                         atomic64_add(ret, &ed_system.bytes_read);
480                 }
481         }
482
483         return 0;
484 }
485
486 static struct kretprobe sys_read_krp = {
487         .entry_handler = entry_handler_sys_read,
488         .handler = ret_handler_sys_read,
489         .data_size = sizeof(struct sys_read_data)
490 };
491
492
493
494
495
496 /* ============================================================================
497  * =                               sys_write                                  =
498  * ============================================================================
499  */
500 static int entry_handler_sys_write(struct kretprobe_instance *ri, struct pt_regs *regs)
501 {
502         struct sys_read_data *srd = (struct sys_read_data *)ri->data;
503
504         srd->fd = (int)get_arg0(regs);
505
506         return 0;
507 }
508
509 static int ret_handler_sys_write(struct kretprobe_instance *ri, struct pt_regs *regs)
510 {
511         int ret = regs_return_value(regs);
512
513         if (ret > 0) {
514                 struct sys_read_data *srd;
515
516                 srd = (struct sys_read_data *)ri->data;
517                 if (check_file(srd->fd)) {
518                         struct energy_data *ed;
519
520                         ed = get_energy_data(current);
521                         if (ed)
522                                 atomic64_add(ret, &ed->bytes_written);
523
524                         atomic64_add(ret, &ed_system.bytes_written);
525                 }
526         }
527
528         return 0;
529 }
530
531 static struct kretprobe sys_write_krp = {
532         .entry_handler = entry_handler_sys_write,
533         .handler = ret_handler_sys_write,
534         .data_size = sizeof(struct sys_read_data)
535 };
536
537
538
539
540
541 /* ============================================================================
542  * =                                wifi                                      =
543  * ============================================================================
544  */
545 static bool check_wlan0(struct socket *sock)
546 {
547         /* FIXME: hardcode interface */
548         const char *name_intrf = "wlan0";
549
550         if (sock->sk->sk_dst_cache &&
551             sock->sk->sk_dst_cache->dev &&
552             !strcmp(sock->sk->sk_dst_cache->dev->name, name_intrf))
553                 return true;
554
555         return false;
556 }
557
558 static bool check_socket(struct task_struct *task, struct socket *socket)
559 {
560         bool ret = false;
561         unsigned int fd;
562         struct files_struct *files;
563
564         files = swap_get_files_struct(task);
565         if (files == NULL)
566                 return false;
567
568         rcu_read_lock();
569         for (fd = 0; fd < files_fdtable(files)->max_fds; ++fd) {
570                 if (fcheck_files(files, fd) == socket->file) {
571                         ret = true;
572                         goto unlock;
573                 }
574         }
575
576 unlock:
577         rcu_read_unlock();
578         swap_put_files_struct(files);
579         return ret;
580 }
581
582 static struct energy_data *get_energy_data_by_socket(struct task_struct *task,
583                                                      struct socket *socket)
584 {
585         struct energy_data *ed;
586
587         ed = get_energy_data(task);
588         if (ed)
589                 ed = check_socket(task, socket) ? ed : NULL;
590
591         return ed;
592 }
593
594 static int wf_sock_eh(struct kretprobe_instance *ri, struct pt_regs *regs)
595 {
596         struct socket *socket = (struct socket *)swap_get_karg(regs, 0);
597
598         *(struct socket **)ri->data = check_wlan0(socket) ? socket : NULL;
599
600         return 0;
601 }
602
603 static int wf_sock_aio_eh(struct kretprobe_instance *ri, struct pt_regs *regs)
604 {
605         struct kiocb *iocb = (struct kiocb *)swap_get_karg(regs, 0);
606         struct socket *socket = iocb->ki_filp->private_data;
607
608         *(struct socket **)ri->data = check_wlan0(socket) ? socket : NULL;
609
610         return 0;
611 }
612
613 static int wf_sock_recv_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
614 {
615         int ret = regs_return_value(regs);
616
617         if (ret > 0) {
618                 struct socket *socket = *(struct socket **)ri->data;
619
620                 if (socket) {
621                         struct energy_data *ed;
622
623                         ed = get_energy_data_by_socket(current, socket);
624                         if (ed)
625                                 atomic64_add(ret, &ed->bytes_recv);
626                         atomic64_add(ret, &ed_system.bytes_recv);
627                 }
628         }
629
630         return 0;
631 }
632
633 static int wf_sock_send_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
634 {
635         int ret = regs_return_value(regs);
636
637         if (ret > 0) {
638                 struct socket *socket = *(struct socket **)ri->data;
639
640                 if (socket) {
641                         struct energy_data *ed;
642
643                         ed = get_energy_data_by_socket(current, socket);
644                         if (ed)
645                                 atomic64_add(ret, &ed->bytes_send);
646                         atomic64_add(ret, &ed_system.bytes_send);
647                 }
648         }
649
650         return 0;
651 }
652
653 static struct kretprobe sock_recv_krp = {
654         .entry_handler = wf_sock_eh,
655         .handler = wf_sock_recv_rh,
656         .data_size = sizeof(struct socket *)
657 };
658
659 static struct kretprobe sock_send_krp = {
660         .entry_handler = wf_sock_eh,
661         .handler = wf_sock_send_rh,
662         .data_size = sizeof(struct socket *)
663 };
664
665 static struct kretprobe sock_aio_read_krp = {
666         .entry_handler = wf_sock_aio_eh,
667         .handler = wf_sock_recv_rh,
668         .data_size = sizeof(struct socket *)
669 };
670
671 static struct kretprobe sock_aio_write_krp = {
672         .entry_handler = wf_sock_aio_eh,
673         .handler = wf_sock_send_rh,
674         .data_size = sizeof(struct socket *)
675 };
676
677 static struct kern_probe wifi_probes[] = {
678         {
679                 .name = "sock_recvmsg",
680                 .rp = &sock_recv_krp,
681         },
682         {
683                 .name = "sock_sendmsg",
684                 .rp = &sock_send_krp,
685         },
686         {
687                 .name = "sock_aio_read",
688                 .rp = &sock_aio_read_krp,
689         },
690         {
691                 .name = "sock_aio_write",
692                 .rp = &sock_aio_write_krp,
693         }
694 };
695
696 enum { wifi_probes_cnt = ARRAY_SIZE(wifi_probes) };
697 static int wifi_flag = 0;
698
699
700
701
702
703 /* ============================================================================
704  * =                                bluetooth                                 =
705  * ============================================================================
706  */
707 #define RET_HANDLER_BT_NAME(name)       ret_handler_bt_##name
708 #define DEFINE_RET_HANDLER_BT(name) \
709         int RET_HANDLER_BT_NAME(name)(struct kretprobe_instance *ri, \
710                                       struct pt_regs *regs) \
711         { \
712                 unsigned int len = *(unsigned int *)ri->data; \
713                 if (len) { \
714                         struct energy_data *ed = get_energy_data(current); \
715                         if (ed) \
716                                 atomic64_add(len, &ed->bytes_##name); \
717                         atomic64_add(len, &ed_system.bytes_##name); \
718                 } \
719         return 0; \
720 }
721
722 static DEFINE_RET_HANDLER_BT(l2cap_recv_acldata)
723 static DEFINE_RET_HANDLER_BT(sco_recv_scodata)
724 static DEFINE_RET_HANDLER_BT(hci_send_acl)
725 static DEFINE_RET_HANDLER_BT(hci_send_sco)
726
727 static int entry_handler_generic_bt(struct kretprobe_instance *ri,
728                                     struct pt_regs *regs)
729 {
730         struct sk_buff *skb = (struct sk_buff *)swap_get_sarg(regs, 1);
731         unsigned int *len = (unsigned int *)ri->data;
732
733         *len = skb ? skb->len : 0;
734
735         return 0;
736 }
737
738 static struct kretprobe l2cap_recv_acldata_krp = {
739         .entry_handler = entry_handler_generic_bt,
740         .handler = RET_HANDLER_BT_NAME(l2cap_recv_acldata),
741         .data_size = sizeof(unsigned int)
742 };
743
744 static struct kretprobe sco_recv_scodata_krp = {
745         .entry_handler = entry_handler_generic_bt,
746         .handler = RET_HANDLER_BT_NAME(sco_recv_scodata),
747         .data_size = sizeof(unsigned int)
748 };
749
750 static struct kretprobe hci_send_acl_krp = {
751         .entry_handler = entry_handler_generic_bt,
752         .handler = RET_HANDLER_BT_NAME(hci_send_acl),
753         .data_size = sizeof(unsigned int)
754 };
755
756 static struct kretprobe hci_send_sco_krp = {
757         .entry_handler = entry_handler_generic_bt,
758         .handler = RET_HANDLER_BT_NAME(hci_send_sco),
759         .data_size = sizeof(unsigned int)
760 };
761
762
763 static int energy_bt_once(void)
764 {
765         const char *sym;
766
767         sym = "l2cap_recv_acldata";
768         l2cap_recv_acldata_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
769         if (l2cap_recv_acldata_krp.kp.addr == NULL)
770                 goto not_found;
771
772         sym = "sco_recv_scodata";
773         sco_recv_scodata_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
774         if (sco_recv_scodata_krp.kp.addr == NULL)
775                 goto not_found;
776
777         sym = "hci_send_acl";
778         hci_send_acl_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
779         if (hci_send_acl_krp.kp.addr == NULL)
780                 goto not_found;
781
782         sym = "hci_send_sco";
783         hci_send_sco_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
784         if (hci_send_sco_krp.kp.addr == NULL)
785                 goto not_found;
786
787         return 0;
788
789 not_found:
790         printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
791         return -ESRCH;
792 }
793
794 static int energy_bt_flag = 0;
795
796 static int energy_bt_set(void)
797 {
798         int ret;
799
800         ret = swap_register_kretprobe(&l2cap_recv_acldata_krp);
801         if (ret) {
802                 pr_err("register fail 'l2cap_recv_acldata_krp' ret=%d\n", ret);
803                 return ret;
804         }
805
806         ret = swap_register_kretprobe(&sco_recv_scodata_krp);
807         if (ret) {
808                 printk("register fail 'sco_recv_scodata_krp' ret=%d\n" ,ret);
809                 goto unreg_l2cap_recv_acldata;
810         }
811
812         ret = swap_register_kretprobe(&hci_send_acl_krp);
813         if (ret) {
814                 printk("register fail 'hci_send_acl_krp' ret=%d\n", ret);
815                 goto unreg_sco_recv_scodata;
816         }
817
818         ret = swap_register_kretprobe(&hci_send_sco_krp);
819         if (ret) {
820                 printk("register fail 'hci_send_sco_krp' ret=%d\n", ret);
821                 goto unreg_hci_send_acl;
822         }
823
824         energy_bt_flag = 1;
825
826         return 0;
827
828 unreg_hci_send_acl:
829         swap_unregister_kretprobe(&hci_send_acl_krp);
830
831 unreg_sco_recv_scodata:
832         swap_unregister_kretprobe(&sco_recv_scodata_krp);
833
834 unreg_l2cap_recv_acldata:
835         swap_unregister_kretprobe(&l2cap_recv_acldata_krp);
836
837         return ret;
838 }
839
840 static void energy_bt_unset(void)
841 {
842         if (energy_bt_flag == 0)
843                 return;
844
845         swap_unregister_kretprobe(&hci_send_sco_krp);
846         swap_unregister_kretprobe(&hci_send_acl_krp);
847         swap_unregister_kretprobe(&sco_recv_scodata_krp);
848         swap_unregister_kretprobe(&l2cap_recv_acldata_krp);
849
850         energy_bt_flag = 0;
851 }
852
853
854
855
856
857 enum parameter_type {
858         PT_CPU,
859         PT_READ,
860         PT_WRITE,
861         PT_WF_RECV,
862         PT_WF_SEND,
863         PT_L2CAP_RECV,
864         PT_SCO_RECV,
865         PT_SEND_ACL,
866         PT_SEND_SCO
867 };
868
869 struct cmd_pt {
870         enum parameter_type pt;
871         void *buf;
872         int sz;
873 };
874
875 static void callback_for_proc(struct sspt_proc *proc, void *data)
876 {
877         void *f_data = sspt_get_feature_data(proc->feature, feature_id);
878         struct energy_data *ed = (struct energy_data *)f_data;
879
880         if (ed) {
881                 unsigned long flags;
882                 struct cmd_pt *cmdp = (struct cmd_pt *)data;
883                 u64 *val = cmdp->buf;
884
885                 switch (cmdp->pt) {
886                 case PT_CPU:
887                         cpus_time_lock(&ed->ct, flags);
888                         cpus_time_sum_running_all(&ed->ct, val, get_ntime());
889                         cpus_time_unlock(&ed->ct, flags);
890                         break;
891                 case PT_READ:
892                         *val += atomic64_read(&ed->bytes_read);
893                         break;
894                 case PT_WRITE:
895                         *val += atomic64_read(&ed->bytes_written);
896                         break;
897                 case PT_WF_RECV:
898                         *val += atomic64_read(&ed->bytes_recv);
899                         break;
900                 case PT_WF_SEND:
901                         *val += atomic64_read(&ed->bytes_send);
902                         break;
903                 case PT_L2CAP_RECV:
904                         *val += atomic64_read(&ed->bytes_l2cap_recv_acldata);
905                         break;
906                 case PT_SCO_RECV:
907                         *val += atomic64_read(&ed->bytes_sco_recv_scodata);
908                         break;
909                 case PT_SEND_ACL:
910                         *val += atomic64_read(&ed->bytes_hci_send_acl);
911                         break;
912                 case PT_SEND_SCO:
913                         *val += atomic64_read(&ed->bytes_hci_send_sco);
914                         break;
915                 default:
916                         break;
917                 }
918         }
919 }
920
921 static int current_parameter_apps(enum parameter_type pt, void *buf, int sz)
922 {
923         struct cmd_pt cmdp;
924
925         cmdp.pt = pt;
926         cmdp.buf = buf;
927         cmdp.sz = sz;
928
929         on_each_proc(callback_for_proc, (void *)&cmdp);
930
931         return 0;
932 }
933
934 /**
935  * @brief Get energy parameter
936  *
937  * @param pe Type of energy parameter
938  * @param buf Buffer
939  * @param sz Buffer size
940  * @return Error code
941  */
942 int get_parameter_energy(enum parameter_energy pe, void *buf, size_t sz)
943 {
944         unsigned long flags;
945         u64 *val = buf; /* currently all parameters are u64 vals */
946         int ret = 0;
947
948         switch (pe) {
949         case PE_TIME_IDLE:
950                 cpus_time_lock(&ct_idle, flags);
951                 /* for the moment we consider only CPU[0] idle time */
952                 *val = cpu_time_get_running(&ct_idle, 0, get_ntime());
953                 cpus_time_unlock(&ct_idle, flags);
954                 break;
955         case PE_TIME_SYSTEM:
956                 cpus_time_lock(&ed_system.ct, flags);
957                 cpus_time_get_running_all(&ed_system.ct, val, get_ntime());
958                 cpus_time_unlock(&ed_system.ct, flags);
959                 break;
960         case PE_TIME_APPS:
961                 current_parameter_apps(PT_CPU, buf, sz);
962                 break;
963         case PE_READ_SYSTEM:
964                 *val = atomic64_read(&ed_system.bytes_read);
965                 break;
966         case PE_WRITE_SYSTEM:
967                 *val = atomic64_read(&ed_system.bytes_written);
968                 break;
969         case PE_WF_RECV_SYSTEM:
970                 *val = atomic64_read(&ed_system.bytes_recv);
971                 break;
972         case PE_WF_SEND_SYSTEM:
973                 *val = atomic64_read(&ed_system.bytes_send);
974                 break;
975         case PE_L2CAP_RECV_SYSTEM:
976                 *val = atomic64_read(&ed_system.bytes_l2cap_recv_acldata);
977                 break;
978         case PE_SCO_RECV_SYSTEM:
979                 *val = atomic64_read(&ed_system.bytes_sco_recv_scodata);
980                 break;
981         case PT_SEND_ACL_SYSTEM:
982                 *val = atomic64_read(&ed_system.bytes_hci_send_acl);
983                 break;
984         case PT_SEND_SCO_SYSTEM:
985                 *val = atomic64_read(&ed_system.bytes_hci_send_sco);
986                 break;
987         case PE_READ_APPS:
988                 current_parameter_apps(PT_READ, buf, sz);
989                 break;
990         case PE_WRITE_APPS:
991                 current_parameter_apps(PT_WRITE, buf, sz);
992                 break;
993         case PE_WF_RECV_APPS:
994                 current_parameter_apps(PT_WF_RECV, buf, sz);
995                 break;
996         case PE_WF_SEND_APPS:
997                 current_parameter_apps(PT_WF_SEND, buf, sz);
998                 break;
999         case PE_L2CAP_RECV_APPS:
1000                 current_parameter_apps(PT_L2CAP_RECV, buf, sz);
1001                 break;
1002         case PE_SCO_RECV_APPS:
1003                 current_parameter_apps(PT_SCO_RECV, buf, sz);
1004                 break;
1005         case PT_SEND_ACL_APPS:
1006                 current_parameter_apps(PT_SEND_ACL, buf, sz);
1007                 break;
1008         case PT_SEND_SCO_APPS:
1009                 current_parameter_apps(PT_SEND_SCO, buf, sz);
1010                 break;
1011         default:
1012                 ret = -EINVAL;
1013                 break;
1014         }
1015
1016         return ret;
1017 }
1018
1019 int do_set_energy(void)
1020 {
1021         int ret = 0;
1022
1023         init_data_energy();
1024
1025         ret = swap_register_kretprobe(&sys_read_krp);
1026         if (ret) {
1027                 printk("swap_register_kretprobe(sys_read) result=%d!\n", ret);
1028                 return ret;
1029         }
1030
1031         ret = swap_register_kretprobe(&sys_write_krp);
1032         if (ret != 0) {
1033                 printk("swap_register_kretprobe(sys_write) result=%d!\n", ret);
1034                 goto unregister_sys_read;
1035         }
1036
1037         ret = swap_register_kretprobe(&switch_to_krp);
1038         if (ret) {
1039                 printk("swap_register_kretprobe(__switch_to) result=%d!\n",
1040                        ret);
1041                 goto unregister_sys_write;
1042         }
1043
1044         energy_bt_set();
1045         energy_xxx_set(wifi_probes, wifi_probes_cnt, &wifi_flag);
1046
1047         /* TODO: check return value */
1048         lcd_set_energy();
1049
1050         return ret;
1051
1052 unregister_sys_read:
1053         swap_unregister_kretprobe(&sys_read_krp);
1054
1055 unregister_sys_write:
1056         swap_unregister_kretprobe(&sys_write_krp);
1057
1058         return ret;
1059 }
1060
1061 void do_unset_energy(void)
1062 {
1063         lcd_unset_energy();
1064         energy_xxx_unset(wifi_probes, wifi_probes_cnt, &wifi_flag);
1065         energy_bt_unset();
1066
1067         swap_unregister_kretprobe(&switch_to_krp);
1068         swap_unregister_kretprobe(&sys_write_krp);
1069         swap_unregister_kretprobe(&sys_read_krp);
1070
1071         uninit_data_energy();
1072 }
1073
1074 static DEFINE_MUTEX(mutex_enable);
1075 static int energy_enable = 0;
1076
1077 /**
1078  * @brief Start measuring the energy consumption
1079  *
1080  * @return Error code
1081  */
1082 int set_energy(void)
1083 {
1084         int ret = -EINVAL;
1085
1086         mutex_lock(&mutex_enable);
1087         if (energy_enable) {
1088                 printk("energy profiling is already run!\n");
1089                 goto unlock;
1090         }
1091
1092         ret = do_set_energy();
1093         if (ret == 0)
1094                 energy_enable = 1;
1095
1096 unlock:
1097         mutex_unlock(&mutex_enable);
1098
1099         return ret;
1100 }
1101 EXPORT_SYMBOL_GPL(set_energy);
1102
1103 /**
1104  * @brief Stop measuring the energy consumption
1105  *
1106  * @return Error code
1107  */
1108 int unset_energy(void)
1109 {
1110         int ret = 0;
1111
1112         mutex_lock(&mutex_enable);
1113         if (energy_enable == 0) {
1114                 printk("energy profiling is not running!\n");
1115                 ret = -EINVAL;
1116                 goto unlock;
1117         }
1118
1119         do_unset_energy();
1120
1121         energy_enable = 0;
1122 unlock:
1123         mutex_unlock(&mutex_enable);
1124
1125         return ret;
1126 }
1127 EXPORT_SYMBOL_GPL(unset_energy);
1128
1129 int energy_once(void)
1130 {
1131         const char *sym;
1132
1133         sym = "__switch_to";
1134         switch_to_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
1135         if (switch_to_krp.kp.addr == NULL)
1136                 goto not_found;
1137
1138         sym = "sys_read";
1139         sys_read_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
1140         if (sys_read_krp.kp.addr == NULL)
1141                 goto not_found;
1142
1143         sym = "sys_write";
1144         sys_write_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
1145         if (sys_write_krp.kp.addr == NULL)
1146                 goto not_found;
1147
1148         energy_bt_once();
1149         energy_xxx_once(wifi_probes, wifi_probes_cnt);
1150
1151         return 0;
1152
1153 not_found:
1154         printk("ERROR: symbol '%s' not found\n", sym);
1155         return -ESRCH;
1156 }
1157
1158 /**
1159  * @brief Initialization energy
1160  *
1161  * @return Error code
1162  */
1163 int energy_init(void)
1164 {
1165         int ret;
1166
1167         ret = init_feature();
1168         if (ret)
1169                 printk(KERN_INFO "Cannot init feature\n");
1170
1171         return ret;
1172 }
1173
1174 /**
1175  * @brief Deinitialization energy
1176  *
1177  * @return Void
1178  */
1179 void energy_uninit(void)
1180 {
1181         uninit_feature();
1182
1183         if (energy_enable)
1184                 do_unset_energy();
1185 }