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