blob: dfbc97d80221bbe883434fa3db49e7a2669ecdbe [file] [log] [blame]
Jon Medhurst15ce78d2014-04-10 09:02:02 +01001/**
2 * Copyright (C) ARM Limited 2010-2014. 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 */
9
10static void marshal_frame(int cpu, int buftype)
11{
12 int frame;
13
14 if (!per_cpu(gator_buffer, cpu)[buftype]) {
15 return;
16 }
17
18 switch (buftype) {
19 case SUMMARY_BUF:
20 frame = FRAME_SUMMARY;
21 break;
22 case BACKTRACE_BUF:
23 frame = FRAME_BACKTRACE;
24 break;
25 case NAME_BUF:
26 frame = FRAME_NAME;
27 break;
28 case COUNTER_BUF:
29 frame = FRAME_COUNTER;
30 break;
31 case BLOCK_COUNTER_BUF:
32 frame = FRAME_BLOCK_COUNTER;
33 break;
34 case ANNOTATE_BUF:
35 frame = FRAME_ANNOTATE;
36 break;
37 case SCHED_TRACE_BUF:
38 frame = FRAME_SCHED_TRACE;
39 break;
Jon Medhurst15ce78d2014-04-10 09:02:02 +010040 case IDLE_BUF:
41 frame = FRAME_IDLE;
42 break;
Jon Medhurste31266f2014-08-04 15:47:44 +010043 case ACTIVITY_BUF:
44 frame = FRAME_ACTIVITY;
45 break;
Jon Medhurst15ce78d2014-04-10 09:02:02 +010046 default:
47 frame = -1;
48 break;
49 }
50
51 // add response type
52 if (gator_response_type > 0) {
53 gator_buffer_write_packed_int(cpu, buftype, gator_response_type);
54 }
55
56 // leave space for 4-byte unpacked length
57 per_cpu(gator_buffer_write, cpu)[buftype] = (per_cpu(gator_buffer_write, cpu)[buftype] + sizeof(s32)) & gator_buffer_mask[buftype];
58
59 // add frame type and core number
60 gator_buffer_write_packed_int(cpu, buftype, frame);
61 gator_buffer_write_packed_int(cpu, buftype, cpu);
62}
63
64static int buffer_bytes_available(int cpu, int buftype)
65{
66 int remaining, filled;
67
68 filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype];
69 if (filled < 0) {
70 filled += gator_buffer_size[buftype];
71 }
72
73 remaining = gator_buffer_size[buftype] - filled;
74
75 if (per_cpu(buffer_space_available, cpu)[buftype]) {
76 // Give some extra room; also allows space to insert the overflow error packet
77 remaining -= 200;
78 } else {
79 // Hysteresis, prevents multiple overflow messages
80 remaining -= 2000;
81 }
82
83 return remaining;
84}
85
86static bool buffer_check_space(int cpu, int buftype, int bytes)
87{
88 int remaining = buffer_bytes_available(cpu, buftype);
89
90 if (remaining < bytes) {
91 per_cpu(buffer_space_available, cpu)[buftype] = false;
92 } else {
93 per_cpu(buffer_space_available, cpu)[buftype] = true;
94 }
95
96 return per_cpu(buffer_space_available, cpu)[buftype];
97}
98
99static int contiguous_space_available(int cpu, int buftype)
100{
101 int remaining = buffer_bytes_available(cpu, buftype);
102 int contiguous = gator_buffer_size[buftype] - per_cpu(gator_buffer_write, cpu)[buftype];
103 if (remaining < contiguous)
104 return remaining;
105 else
106 return contiguous;
107}
108
109static void gator_commit_buffer(int cpu, int buftype, u64 time)
110{
111 int type_length, commit, length, byte;
112 unsigned long flags;
113
114 if (!per_cpu(gator_buffer, cpu)[buftype])
115 return;
116
117 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
118 local_irq_save(flags);
119 type_length = gator_response_type ? 1 : 0;
120 commit = per_cpu(gator_buffer_commit, cpu)[buftype];
121 length = per_cpu(gator_buffer_write, cpu)[buftype] - commit;
122 if (length < 0) {
123 length += gator_buffer_size[buftype];
124 }
125 length = length - type_length - sizeof(s32);
126
127 if (length <= FRAME_HEADER_SIZE) {
128 // Nothing to write, only the frame header is present
129 local_irq_restore(flags);
130 return;
131 }
132
133 for (byte = 0; byte < sizeof(s32); byte++) {
134 per_cpu(gator_buffer, cpu)[buftype][(commit + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF;
135 }
136
137 per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
138
139 if (gator_live_rate > 0) {
140 while (time > per_cpu(gator_buffer_commit_time, cpu)) {
141 per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate;
142 }
143 }
144
145 marshal_frame(cpu, buftype);
146 local_irq_restore(flags);
147
148 // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
149 if (per_cpu(in_scheduler_context, cpu)) {
150#ifndef CONFIG_PREEMPT_RT_FULL
151 // mod_timer can not be used in interrupt context in RT-Preempt full
152 mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
153#endif
154 } else {
155 up(&gator_buffer_wake_sem);
156 }
157}
158
159static void buffer_check(int cpu, int buftype, u64 time)
160{
161 int filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_commit, cpu)[buftype];
162 if (filled < 0) {
163 filled += gator_buffer_size[buftype];
164 }
165 if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) {
166 gator_commit_buffer(cpu, buftype, time);
167 }
168}