greybus: loopback: fix broken tabs in greybus_protocols.h
[linux-2.6-block.git] / drivers / staging / greybus / loopback.c
CommitLineData
355a7058
AB
1/*
2 * Loopback bridge driver for the Greybus loopback module.
3 *
4 * Copyright 2014 Google Inc.
5 * Copyright 2014 Linaro Ltd.
6 *
7 * Released under the GPLv2 only.
8 */
9#include <linux/kernel.h>
10#include <linux/module.h>
11#include <linux/slab.h>
12#include <linux/kthread.h>
13#include <linux/delay.h>
14#include <linux/random.h>
5679f783 15#include <linux/sizes.h>
1ffc12be
JH
16#include <asm/div64.h>
17
355a7058
AB
18#include "greybus.h"
19
20struct gb_loopback_stats {
21 u32 min;
22 u32 max;
23 u32 avg;
24 u32 sum;
25 u32 count;
26};
27
28struct gb_loopback {
29 struct gb_connection *connection;
30 u8 version_major;
31 u8 version_minor;
32
33 struct task_struct *task;
34
35 int type;
36 u32 size;
c3bba87a 37 u32 size_max;
355a7058
AB
38 int ms_wait;
39
40 struct gb_loopback_stats latency;
41 struct gb_loopback_stats throughput;
42 struct gb_loopback_stats frequency;
43 struct timeval ts;
44 struct timeval te;
45 u64 elapsed_nsecs;
46 u32 error;
47};
48
91262c3a 49#define GB_LOOPBACK_MS_WAIT_MAX 1000
355a7058
AB
50
51/* Define get_version() routine */
52define_get_version(gb_loopback, LOOPBACK);
53
54/* interface sysfs attributes */
55#define gb_loopback_ro_attr(field, type) \
56static ssize_t field##_show(struct device *dev, \
57 struct device_attribute *attr, \
58 char *buf) \
59{ \
60 struct gb_connection *connection = to_gb_connection(dev); \
61 struct gb_loopback *gb = \
62 (struct gb_loopback *)connection->private; \
63 return sprintf(buf, "%"#type"\n", gb->field); \
64} \
65static DEVICE_ATTR_RO(field)
66
67#define gb_loopback_ro_stats_attr(name, field, type) \
68static ssize_t name##_##field##_show(struct device *dev, \
69 struct device_attribute *attr, \
70 char *buf) \
71{ \
72 struct gb_connection *connection = to_gb_connection(dev); \
73 struct gb_loopback *gb = \
74 (struct gb_loopback *)connection->private; \
75 return sprintf(buf, "%"#type"\n", gb->name.field); \
76} \
77static DEVICE_ATTR_RO(name##_##field)
78
79#define gb_loopback_stats_attrs(field) \
80 gb_loopback_ro_stats_attr(field, min, d); \
81 gb_loopback_ro_stats_attr(field, max, d); \
82 gb_loopback_ro_stats_attr(field, avg, d);
83
84#define gb_loopback_attr(field, type) \
85static ssize_t field##_show(struct device *dev, \
86 struct device_attribute *attr, \
87 char *buf) \
88{ \
89 struct gb_connection *connection = to_gb_connection(dev); \
90 struct gb_loopback *gb = \
91 (struct gb_loopback *)connection->private; \
92 return sprintf(buf, "%"#type"\n", gb->field); \
93} \
94static ssize_t field##_store(struct device *dev, \
95 struct device_attribute *attr, \
96 const char *buf, \
97 size_t len) \
98{ \
99 int ret; \
100 struct gb_connection *connection = to_gb_connection(dev); \
101 struct gb_loopback *gb = \
102 (struct gb_loopback *)connection->private; \
103 ret = sscanf(buf, "%"#type, &gb->field); \
355a7058
AB
104 if (ret != 1) \
105 return -EINVAL; \
106 gb_loopback_check_attr(gb); \
107 return len; \
108} \
109static DEVICE_ATTR_RW(field)
110
111static void gb_loopback_reset_stats(struct gb_loopback *gb);
112static void gb_loopback_check_attr(struct gb_loopback *gb)
113{
a598f438
BD
114 switch (gb->type) {
115 case GB_LOOPBACK_TYPE_PING:
116 case GB_LOOPBACK_TYPE_TRANSFER:
384a7a3c 117 case GB_LOOPBACK_TYPE_SINK:
a598f438
BD
118 break;
119 default:
120 gb->type = 0;
121 break;
122 }
91262c3a
AE
123 if (gb->ms_wait > GB_LOOPBACK_MS_WAIT_MAX)
124 gb->ms_wait = GB_LOOPBACK_MS_WAIT_MAX;
c3bba87a
BD
125 if (gb->size > gb->size_max)
126 gb->size = gb->size_max;
355a7058
AB
127 gb->error = 0;
128 gb_loopback_reset_stats(gb);
129}
130
131/* Time to send and receive one message */
132gb_loopback_stats_attrs(latency);
133/* Number of packet sent per second on this cport */
134gb_loopback_stats_attrs(frequency);
135/* Quantity of data sent and received on this cport */
136gb_loopback_stats_attrs(throughput);
137gb_loopback_ro_attr(error, d);
138
139/*
140 * Type of loopback message to send
141 * 0 => Don't send message
142 * 1 => Send ping message continuously (message without payload)
143 * 2 => Send transer message continuously (message with payload)
144 */
145gb_loopback_attr(type, d);
146/* Size of transfer message payload: 0-4096 bytes */
147gb_loopback_attr(size, u);
48f19ee8 148/* Time to wait between two messages: 0-1000 ms */
355a7058
AB
149gb_loopback_attr(ms_wait, d);
150
151#define dev_stats_attrs(name) \
152 &dev_attr_##name##_min.attr, \
153 &dev_attr_##name##_max.attr, \
154 &dev_attr_##name##_avg.attr
155
156static struct attribute *loopback_attrs[] = {
157 dev_stats_attrs(latency),
158 dev_stats_attrs(frequency),
159 dev_stats_attrs(throughput),
160 &dev_attr_type.attr,
161 &dev_attr_size.attr,
162 &dev_attr_ms_wait.attr,
163 &dev_attr_error.attr,
164 NULL,
165};
166ATTRIBUTE_GROUPS(loopback);
167
384a7a3c
BD
168static int gb_loopback_sink(struct gb_loopback *gb,
169 struct timeval *tping, u32 len)
170{
171 struct timeval ts, te;
172 u64 elapsed_nsecs;
173 struct gb_loopback_transfer_request *request;
174 int retval;
175
176 request = kmalloc(len + sizeof(*request), GFP_KERNEL);
177 if (!request)
178 return -ENOMEM;
179
180 request->len = cpu_to_le32(len);
181
182 do_gettimeofday(&ts);
183 retval = gb_operation_sync(gb->connection, GB_LOOPBACK_TYPE_SINK,
184 request, len + sizeof(*request), NULL, 0);
c3bba87a 185
384a7a3c
BD
186 do_gettimeofday(&te);
187 elapsed_nsecs = timeval_to_ns(&te) - timeval_to_ns(&ts);
188 *tping = ns_to_timeval(elapsed_nsecs);
189
190 kfree(request);
191 return retval;
192}
193
355a7058
AB
194static int gb_loopback_transfer(struct gb_loopback *gb,
195 struct timeval *tping, u32 len)
196{
197 struct timeval ts, te;
198 u64 elapsed_nsecs;
199 struct gb_loopback_transfer_request *request;
200 struct gb_loopback_transfer_response *response;
201 int retval;
202
203 request = kmalloc(len + sizeof(*request), GFP_KERNEL);
204 if (!request)
205 return -ENOMEM;
206 response = kmalloc(len + sizeof(*response), GFP_KERNEL);
207 if (!response) {
208 kfree(request);
209 return -ENOMEM;
210 }
211
212 request->len = cpu_to_le32(len);
213
214 do_gettimeofday(&ts);
215 retval = gb_operation_sync(gb->connection, GB_LOOPBACK_TYPE_TRANSFER,
216 request, len + sizeof(*request),
217 response, len + sizeof(*response));
218 do_gettimeofday(&te);
219 elapsed_nsecs = timeval_to_ns(&te) - timeval_to_ns(&ts);
220 *tping = ns_to_timeval(elapsed_nsecs);
221
222 if (retval)
223 goto gb_error;
224
225 if (memcmp(request->data, response->data, len))
226 retval = -EREMOTEIO;
227
228gb_error:
229 kfree(request);
230 kfree(response);
231
232 return retval;
233}
234
235static int gb_loopback_ping(struct gb_loopback *gb, struct timeval *tping)
236{
237 struct timeval ts, te;
238 u64 elapsed_nsecs;
239 int retval;
240
241 do_gettimeofday(&ts);
242 retval = gb_operation_sync(gb->connection, GB_LOOPBACK_TYPE_PING,
243 NULL, 0, NULL, 0);
244 do_gettimeofday(&te);
245 elapsed_nsecs = timeval_to_ns(&te) - timeval_to_ns(&ts);
246 *tping = ns_to_timeval(elapsed_nsecs);
247
248 return retval;
249}
250
ac1c2840
AE
251static int gb_loopback_request_recv(u8 type, struct gb_operation *operation)
252{
253 struct gb_connection *connection = operation->connection;
c3bba87a 254 struct gb_loopback *gb = connection->private;
ac1c2840
AE
255 struct gb_loopback_transfer_request *request;
256 struct gb_loopback_transfer_response *response;
257 u32 len;
258
259 /* By convention, the AP initiates the version operation */
260 switch (type) {
261 case GB_LOOPBACK_TYPE_PROTOCOL_VERSION:
262 dev_err(&connection->dev,
263 "module-initiated version operation\n");
264 return -EINVAL;
265 case GB_LOOPBACK_TYPE_PING:
384a7a3c 266 case GB_LOOPBACK_TYPE_SINK:
ac1c2840
AE
267 return 0;
268 case GB_LOOPBACK_TYPE_TRANSFER:
269 if (operation->request->payload_size < sizeof(*request)) {
270 dev_err(&connection->dev,
271 "transfer request too small (%zu < %zu)\n",
272 operation->request->payload_size,
273 sizeof(*request));
274 return -EINVAL; /* -EMSGSIZE */
275 }
276 request = operation->request->payload;
277 len = le32_to_cpu(request->len);
c3bba87a
BD
278 if (len > gb->size_max) {
279 dev_err(&connection->dev,
280 "transfer request too large (%zu > %zu)\n",
281 len, gb->size_max);
282 return -EINVAL;
283 }
284
ac1c2840
AE
285 if (len) {
286 if (!gb_operation_response_alloc(operation, len)) {
287 dev_err(&connection->dev,
288 "error allocating response\n");
289 return -ENOMEM;
290 }
291 response = operation->response->payload;
292 memcpy(response->data, request->data, len);
293 }
294 return 0;
295 default:
296 dev_err(&connection->dev,
297 "unsupported request: %hhu\n", type);
298 return -EINVAL;
299 }
300}
301
355a7058
AB
302static void gb_loopback_reset_stats(struct gb_loopback *gb)
303{
304 struct gb_loopback_stats reset = {
305 .min = 0xffffffff,
306 };
307 memcpy(&gb->latency, &reset, sizeof(struct gb_loopback_stats));
308 memcpy(&gb->throughput, &reset, sizeof(struct gb_loopback_stats));
309 memcpy(&gb->frequency, &reset, sizeof(struct gb_loopback_stats));
310 memset(&gb->ts, 0, sizeof(struct timeval));
311}
312
313static void gb_loopback_update_stats(struct gb_loopback_stats *stats,
314 u64 elapsed_nsecs)
315{
316 u32 avg;
1ffc12be 317 u64 tmp;
355a7058
AB
318
319 if (elapsed_nsecs >= NSEC_PER_SEC) {
1ffc12be
JH
320 if (!stats->count) {
321 tmp = elapsed_nsecs;
322 do_div(tmp, NSEC_PER_SEC);
323 avg = stats->sum * tmp;
324 } else {
355a7058 325 avg = stats->sum / stats->count;
1ffc12be 326 }
355a7058
AB
327 if (stats->min > avg)
328 stats->min = avg;
329 if (stats->max < avg)
330 stats->max = avg;
331 stats->avg = avg;
332 stats->count = 0;
333 stats->sum = 0;
334 }
335}
336
337static void gb_loopback_freq_update(struct gb_loopback *gb)
338{
339 gb->frequency.sum++;
340 gb_loopback_update_stats(&gb->frequency, gb->elapsed_nsecs);
341}
342
f7908e4d 343static void gb_loopback_throughput_update(struct gb_loopback *gb)
355a7058 344{
f7908e4d
BD
345 u32 aggregate_size = sizeof(struct gb_operation_msg_hdr) * 2;
346
347 switch (gb->type) {
348 case GB_LOOPBACK_TYPE_PING:
349 break;
350 case GB_LOOPBACK_TYPE_SINK:
351 aggregate_size += sizeof(struct gb_loopback_transfer_request) +
352 gb->size;
353 break;
354 case GB_LOOPBACK_TYPE_TRANSFER:
355 aggregate_size += sizeof(struct gb_loopback_transfer_request) +
356 sizeof(struct gb_loopback_transfer_response) +
357 gb->size * 2;
358 break;
359 default:
360 return;
361 }
362 gb->throughput.sum += aggregate_size;
355a7058
AB
363 gb_loopback_update_stats(&gb->throughput, gb->elapsed_nsecs);
364}
365
366static void gb_loopback_latency_update(struct gb_loopback *gb,
367 struct timeval *tlat)
368{
369 u32 lat;
1ffc12be 370 u64 tmp;
355a7058 371
1ffc12be
JH
372 tmp = timeval_to_ns(tlat);
373 do_div(tmp, NSEC_PER_MSEC);
374 lat = tmp;
355a7058
AB
375
376 if (gb->latency.min > lat)
377 gb->latency.min = lat;
378 if (gb->latency.max < lat)
379 gb->latency.max = lat;
380 gb->latency.sum += lat;
381 gb->latency.count++;
382 gb_loopback_update_stats(&gb->latency, gb->elapsed_nsecs);
383}
384
385static int gb_loopback_fn(void *data)
386{
387 int error = 0;
388 struct timeval tlat = {0, 0};
389 struct gb_loopback *gb = (struct gb_loopback *)data;
390
391 while (!kthread_should_stop()) {
a598f438 392 if (!gb->type) {
355a7058
AB
393 msleep(1000);
394 continue;
395 }
a598f438 396 if (gb->type == GB_LOOPBACK_TYPE_PING)
355a7058 397 error = gb_loopback_ping(gb, &tlat);
a598f438 398 else if (gb->type == GB_LOOPBACK_TYPE_TRANSFER)
355a7058 399 error = gb_loopback_transfer(gb, &tlat, gb->size);
384a7a3c
BD
400 else if (gb->type == GB_LOOPBACK_TYPE_SINK)
401 error = gb_loopback_sink(gb, &tlat, gb->size);
355a7058
AB
402 if (error)
403 gb->error++;
404 if (gb->ts.tv_usec == 0 && gb->ts.tv_sec == 0) {
405 do_gettimeofday(&gb->ts);
406 continue;
407 }
408 do_gettimeofday(&gb->te);
409 gb->elapsed_nsecs = timeval_to_ns(&gb->te) -
410 timeval_to_ns(&gb->ts);
411 gb_loopback_freq_update(gb);
f7908e4d 412 gb_loopback_throughput_update(gb);
355a7058
AB
413 gb_loopback_latency_update(gb, &tlat);
414 if (gb->elapsed_nsecs >= NSEC_PER_SEC)
415 gb->ts = gb->te;
416 if (gb->ms_wait)
417 msleep(gb->ms_wait);
418
419 }
420 return 0;
421}
422
423static int gb_loopback_connection_init(struct gb_connection *connection)
424{
425 struct gb_loopback *gb;
426 int retval;
427
428 gb = kzalloc(sizeof(*gb), GFP_KERNEL);
429 if (!gb)
430 return -ENOMEM;
431
432 gb->connection = connection;
433 connection->private = gb;
7a51b936 434 retval = sysfs_create_groups(&connection->dev.kobj, loopback_groups);
355a7058 435 if (retval)
6f8528e0 436 goto out_free;
355a7058
AB
437
438 /* Check the version */
439 retval = get_version(gb);
440 if (retval)
6f8528e0 441 goto out_get_ver;
355a7058 442
c3bba87a
BD
443 /* Calculate maximum payload */
444 gb->size_max = gb_operation_get_payload_size_max(connection);
445 if (gb->size_max <= sizeof(struct gb_loopback_transfer_request)) {
446 retval = -EINVAL;
447 goto out_get_ver;
448 }
449 gb->size_max -= sizeof(struct gb_loopback_transfer_request);
450
355a7058
AB
451 gb_loopback_reset_stats(gb);
452 gb->task = kthread_run(gb_loopback_fn, gb, "gb_loopback");
453 if (IS_ERR(gb->task)) {
69f60347 454 retval = PTR_ERR(gb->task);
6f8528e0 455 goto out_get_ver;
355a7058
AB
456 }
457
458 return 0;
459
6f8528e0
PT
460out_get_ver:
461 sysfs_remove_groups(&connection->dev.kobj, loopback_groups);
462out_free:
355a7058
AB
463 kfree(gb);
464 return retval;
465}
466
467static void gb_loopback_connection_exit(struct gb_connection *connection)
468{
469 struct gb_loopback *gb = connection->private;
470
471 if (!IS_ERR_OR_NULL(gb->task))
472 kthread_stop(gb->task);
7a51b936 473 sysfs_remove_groups(&connection->dev.kobj, loopback_groups);
355a7058
AB
474 kfree(gb);
475}
476
477static struct gb_protocol loopback_protocol = {
478 .name = "loopback",
479 .id = GREYBUS_PROTOCOL_LOOPBACK,
480 .major = GB_LOOPBACK_VERSION_MAJOR,
481 .minor = GB_LOOPBACK_VERSION_MINOR,
482 .connection_init = gb_loopback_connection_init,
483 .connection_exit = gb_loopback_connection_exit,
ac1c2840 484 .request_recv = gb_loopback_request_recv,
355a7058
AB
485};
486
487gb_protocol_driver(&loopback_protocol);
488
489MODULE_LICENSE("GPL v2");