1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/circ_buf.h>
19#include <linux/types.h>
20#include <linux/io.h>
21#include <linux/errno.h>
22
23#include "scif_rb.h"
24
25#define scif_rb_ring_cnt(head, tail, size) CIRC_CNT(head, tail, size)
26#define scif_rb_ring_space(head, tail, size) CIRC_SPACE(head, tail, size)
27
28
29
30
31
32
33
34
35
36void scif_rb_init(struct scif_rb *rb, u32 *read_ptr, u32 *write_ptr,
37 void *rb_base, u8 size)
38{
39 rb->rb_base = rb_base;
40 rb->size = (1 << size);
41 rb->read_ptr = read_ptr;
42 rb->write_ptr = write_ptr;
43 rb->current_read_offset = *read_ptr;
44 rb->current_write_offset = *write_ptr;
45}
46
47
48static void memcpy_torb(struct scif_rb *rb, void *header,
49 void *msg, u32 size)
50{
51 u32 size1, size2;
52
53 if (header + size >= rb->rb_base + rb->size) {
54
55 size1 = (u32)(rb->rb_base + rb->size - header);
56 size2 = size - size1;
57 memcpy_toio((void __iomem __force *)header, msg, size1);
58 memcpy_toio((void __iomem __force *)rb->rb_base,
59 msg + size1, size2);
60 } else {
61 memcpy_toio((void __iomem __force *)header, msg, size);
62 }
63}
64
65
66static void memcpy_fromrb(struct scif_rb *rb, void *header,
67 void *msg, u32 size)
68{
69 u32 size1, size2;
70
71 if (header + size >= rb->rb_base + rb->size) {
72
73 size1 = (u32)(rb->rb_base + rb->size - header);
74 size2 = size - size1;
75 memcpy_fromio(msg, (void __iomem __force *)header, size1);
76 memcpy_fromio(msg + size1,
77 (void __iomem __force *)rb->rb_base, size2);
78 } else {
79 memcpy_fromio(msg, (void __iomem __force *)header, size);
80 }
81}
82
83
84
85
86
87
88
89u32 scif_rb_space(struct scif_rb *rb)
90{
91 rb->current_read_offset = *rb->read_ptr;
92
93
94
95
96
97 mb();
98 return scif_rb_ring_space(rb->current_write_offset,
99 rb->current_read_offset, rb->size);
100}
101
102
103
104
105
106
107
108
109
110
111int scif_rb_write(struct scif_rb *rb, void *msg, u32 size)
112{
113 void *header;
114
115 if (scif_rb_space(rb) < size)
116 return -ENOMEM;
117 header = rb->rb_base + rb->current_write_offset;
118 memcpy_torb(rb, header, msg, size);
119
120
121
122
123 rb->current_write_offset =
124 (rb->current_write_offset + size) & (rb->size - 1);
125 return 0;
126}
127
128
129
130
131
132void scif_rb_commit(struct scif_rb *rb)
133{
134
135
136
137
138
139
140 wmb();
141 WRITE_ONCE(*rb->write_ptr, rb->current_write_offset);
142#ifdef CONFIG_INTEL_MIC_CARD
143
144
145
146
147
148
149
150 WRITE_ONCE(*rb->write_ptr, rb->current_write_offset);
151#endif
152}
153
154
155
156
157
158
159
160
161
162static void *scif_rb_get(struct scif_rb *rb, u32 size)
163{
164 void *header = NULL;
165
166 if (scif_rb_count(rb, size) >= size)
167 header = rb->rb_base + rb->current_read_offset;
168 return header;
169}
170
171
172
173
174
175
176
177
178
179
180u32 scif_rb_get_next(struct scif_rb *rb, void *msg, u32 size)
181{
182 void *header = NULL;
183 int read_size = 0;
184
185 header = scif_rb_get(rb, size);
186 if (header) {
187 u32 next_cmd_offset =
188 (rb->current_read_offset + size) & (rb->size - 1);
189
190 read_size = size;
191 rb->current_read_offset = next_cmd_offset;
192 memcpy_fromrb(rb, header, msg, size);
193 }
194 return read_size;
195}
196
197
198
199
200
201void scif_rb_update_read_ptr(struct scif_rb *rb)
202{
203 u32 new_offset;
204
205 new_offset = rb->current_read_offset;
206
207
208
209
210
211
212 mb();
213 WRITE_ONCE(*rb->read_ptr, new_offset);
214#ifdef CONFIG_INTEL_MIC_CARD
215
216
217
218
219
220
221
222 WRITE_ONCE(*rb->read_ptr, new_offset);
223#endif
224}
225
226
227
228
229
230
231
232
233u32 scif_rb_count(struct scif_rb *rb, u32 size)
234{
235 if (scif_rb_ring_cnt(rb->current_write_offset,
236 rb->current_read_offset,
237 rb->size) < size) {
238 rb->current_write_offset = *rb->write_ptr;
239
240
241
242
243
244 smp_rmb();
245 }
246 return scif_rb_ring_cnt(rb->current_write_offset,
247 rb->current_read_offset,
248 rb->size);
249}
250