Merge remote-tracking branch 'lsk/v3.10/topic/arm64-hmp' into linux-linaro-lsk
[firefly-linux-kernel-4.4.55.git] / drivers / gator / gator_buffer.c
1 /**
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
10 static 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;
40         case GPU_TRACE_BUF:
41                 frame = FRAME_GPU_TRACE;
42                 break;
43         case IDLE_BUF:
44                 frame = FRAME_IDLE;
45                 break;
46         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
64 static 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
86 static 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
99 static 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
109 static 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
159 static 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 }