]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/arm-ds5-gator.git/blob - driver/gator_events_meminfo.c
gator: Use device-tree when available for address of pl310 cache
[android-sdk/arm-ds5-gator.git] / driver / gator_events_meminfo.c
1 /**
2  * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  */
10 #include "gator.h"
11 #include <linux/workqueue.h>
12 #include <trace/events/kmem.h>
13 #include <linux/hardirq.h>
15 #define MEMINFO_MEMFREE         0
16 #define MEMINFO_MEMUSED         1
17 #define MEMINFO_BUFFERRAM       2
18 #define MEMINFO_TOTAL           3
20 static ulong meminfo_global_enabled;
21 static ulong meminfo_enabled[MEMINFO_TOTAL];
22 static ulong meminfo_key[MEMINFO_TOTAL];
23 static unsigned long long meminfo_buffer[MEMINFO_TOTAL * 2];
24 static int meminfo_length = 0;
25 static unsigned int mem_event = 0;
26 static bool new_data_avail;
28 static void wq_sched_handler(struct work_struct *wsptr);
29 DECLARE_WORK(work, wq_sched_handler);
30 static struct timer_list meminfo_wake_up_timer;
31 static void meminfo_wake_up_handler(unsigned long unused_data);
33 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
34 GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order))
35 #else
36 GATOR_DEFINE_PROBE(mm_page_free, TP_PROTO(struct page *page, unsigned int order))
37 #endif
38 {
39         mem_event++;
40 }
42 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
43 GATOR_DEFINE_PROBE(mm_pagevec_free, TP_PROTO(struct page *page, int cold))
44 #else
45 GATOR_DEFINE_PROBE(mm_page_free_batched, TP_PROTO(struct page *page, int cold))
46 #endif
47 {
48         mem_event++;
49 }
51 GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype))
52 {
53         mem_event++;
54 }
56 static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root)
57 {
58         struct dentry *dir;
59         int i;
61         for (i = 0; i < MEMINFO_TOTAL; i++) {
62                 switch (i) {
63                 case MEMINFO_MEMFREE:
64                         dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memfree");
65                         break;
66                 case MEMINFO_MEMUSED:
67                         dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memused");
68                         break;
69                 case MEMINFO_BUFFERRAM:
70                         dir = gatorfs_mkdir(sb, root, "Linux_meminfo_bufferram");
71                         break;
72                 default:
73                         return -1;
74                 }
75                 if (!dir) {
76                         return -1;
77                 }
78                 gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]);
79                 gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_key[i]);
80         }
82         return 0;
83 }
85 static int gator_events_meminfo_start(void)
86 {
87         int i;
89         new_data_avail = true;
90         for (i = 0; i < MEMINFO_TOTAL; i++) {
91                 if (meminfo_enabled[i]) {
92                         meminfo_global_enabled = 1;
93                 }
94         }
96         if (meminfo_global_enabled == 0)
97                 return 0;
99 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
100         if (GATOR_REGISTER_TRACE(mm_page_free_direct))
101 #else
102         if (GATOR_REGISTER_TRACE(mm_page_free))
103 #endif
104                 goto mm_page_free_exit;
105 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
106         if (GATOR_REGISTER_TRACE(mm_pagevec_free))
107 #else
108         if (GATOR_REGISTER_TRACE(mm_page_free_batched))
109 #endif
110                 goto mm_page_free_batched_exit;
111         if (GATOR_REGISTER_TRACE(mm_page_alloc))
112                 goto mm_page_alloc_exit;
114         setup_timer(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0);
115         return 0;
117 mm_page_alloc_exit:
118 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
119         GATOR_UNREGISTER_TRACE(mm_pagevec_free);
120 #else
121         GATOR_UNREGISTER_TRACE(mm_page_free_batched);
122 #endif
123 mm_page_free_batched_exit:
124 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
125         GATOR_UNREGISTER_TRACE(mm_page_free_direct);
126 #else
127         GATOR_UNREGISTER_TRACE(mm_page_free);
128 #endif
129 mm_page_free_exit:
130         return -1;
133 static void gator_events_meminfo_stop(void)
135         int i;
137         if (meminfo_global_enabled) {
138 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
139                 GATOR_UNREGISTER_TRACE(mm_page_free_direct);
140                 GATOR_UNREGISTER_TRACE(mm_pagevec_free);
141 #else
142                 GATOR_UNREGISTER_TRACE(mm_page_free);
143                 GATOR_UNREGISTER_TRACE(mm_page_free_batched);
144 #endif
145                 GATOR_UNREGISTER_TRACE(mm_page_alloc);
147                 del_timer_sync(&meminfo_wake_up_timer);
148         }
150         meminfo_global_enabled = 0;
151         for (i = 0; i < MEMINFO_TOTAL; i++) {
152                 meminfo_enabled[i] = 0;
153         }
156 // Must be run in process context as the kernel function si_meminfo() can sleep
157 static void wq_sched_handler(struct work_struct *wsptr)
159         struct sysinfo info;
160         int i, len;
161         unsigned long long value;
163         meminfo_length = len = 0;
165         si_meminfo(&info);
166         for (i = 0; i < MEMINFO_TOTAL; i++) {
167                 if (meminfo_enabled[i]) {
168                         switch (i) {
169                         case MEMINFO_MEMFREE:
170                                 value = info.freeram * PAGE_SIZE;
171                                 break;
172                         case MEMINFO_MEMUSED:
173                                 value = (info.totalram - info.freeram) * PAGE_SIZE;
174                                 break;
175                         case MEMINFO_BUFFERRAM:
176                                 value = info.bufferram * PAGE_SIZE;
177                                 break;
178                         default:
179                                 value = 0;
180                                 break;
181                         }
182                         meminfo_buffer[len++] = (unsigned long long)meminfo_key[i];
183                         meminfo_buffer[len++] = value;
184                 }
185         }
187         meminfo_length = len;
188         new_data_avail = true;
191 static void meminfo_wake_up_handler(unsigned long unused_data)
193         // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
194         schedule_work(&work);
197 static int gator_events_meminfo_read(long long **buffer)
199         static unsigned int last_mem_event = 0;
201         if (!on_primary_core() || !meminfo_global_enabled)
202                 return 0;
204         if (last_mem_event != mem_event) {
205                 last_mem_event = mem_event;
206                 mod_timer(&meminfo_wake_up_timer, jiffies + 1);
207         }
209         if (!new_data_avail)
210                 return 0;
212         new_data_avail = false;
214         if (buffer)
215                 *buffer = meminfo_buffer;
217         return meminfo_length;
220 static struct gator_interface gator_events_meminfo_interface = {
221         .create_files = gator_events_meminfo_create_files,
222         .start = gator_events_meminfo_start,
223         .stop = gator_events_meminfo_stop,
224         .read64 = gator_events_meminfo_read,
225 };
227 int gator_events_meminfo_init(void)
229         int i;
231         meminfo_global_enabled = 0;
232         for (i = 0; i < MEMINFO_TOTAL; i++) {
233                 meminfo_enabled[i] = 0;
234                 meminfo_key[i] = gator_events_get_key();
235         }
237         return gator_events_install(&gator_events_meminfo_interface);
240 gator_events_init(gator_events_meminfo_init);