2 * Loopback bridge driver for the Greybus loopback module.
4 * Copyright 2014 Google Inc.
5 * Copyright 2014 Linaro Ltd.
7 * Released under the GPLv2 only.
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>
15 #include <linux/sizes.h>
16 #include <asm/div64.h>
20 struct gb_loopback_stats {
29 struct gb_connection *connection;
33 struct task_struct *task;
39 struct gb_loopback_stats latency;
40 struct gb_loopback_stats throughput;
41 struct gb_loopback_stats frequency;
48 #define GB_LOOPBACK_MS_WAIT_MAX 1000
49 #define GB_LOOPBACK_SIZE_MAX SZ_4K
51 /* Define get_version() routine */
52 define_get_version(gb_loopback, LOOPBACK);
54 /* interface sysfs attributes */
55 #define gb_loopback_ro_attr(field, type) \
56 static ssize_t field##_show(struct device *dev, \
57 struct device_attribute *attr, \
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); \
65 static DEVICE_ATTR_RO(field)
67 #define gb_loopback_ro_stats_attr(name, field, type) \
68 static ssize_t name##_##field##_show(struct device *dev, \
69 struct device_attribute *attr, \
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); \
77 static DEVICE_ATTR_RO(name##_##field)
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);
84 #define gb_loopback_attr(field, type) \
85 static ssize_t field##_show(struct device *dev, \
86 struct device_attribute *attr, \
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); \
94 static ssize_t field##_store(struct device *dev, \
95 struct device_attribute *attr, \
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); \
106 gb_loopback_check_attr(gb); \
109 static DEVICE_ATTR_RW(field)
111 static void gb_loopback_reset_stats(struct gb_loopback *gb);
112 static void gb_loopback_check_attr(struct gb_loopback *gb)
115 case GB_LOOPBACK_TYPE_PING:
116 case GB_LOOPBACK_TYPE_TRANSFER:
122 if (gb->ms_wait > GB_LOOPBACK_MS_WAIT_MAX)
123 gb->ms_wait = GB_LOOPBACK_MS_WAIT_MAX;
124 if (gb->size > GB_LOOPBACK_SIZE_MAX)
125 gb->size = GB_LOOPBACK_SIZE_MAX;
127 gb_loopback_reset_stats(gb);
130 /* Time to send and receive one message */
131 gb_loopback_stats_attrs(latency);
132 /* Number of packet sent per second on this cport */
133 gb_loopback_stats_attrs(frequency);
134 /* Quantity of data sent and received on this cport */
135 gb_loopback_stats_attrs(throughput);
136 gb_loopback_ro_attr(error, d);
139 * Type of loopback message to send
140 * 0 => Don't send message
141 * 1 => Send ping message continuously (message without payload)
142 * 2 => Send transer message continuously (message with payload)
144 gb_loopback_attr(type, d);
145 /* Size of transfer message payload: 0-4096 bytes */
146 gb_loopback_attr(size, u);
147 /* Time to wait between two messages: 0-1000 ms */
148 gb_loopback_attr(ms_wait, d);
150 #define dev_stats_attrs(name) \
151 &dev_attr_##name##_min.attr, \
152 &dev_attr_##name##_max.attr, \
153 &dev_attr_##name##_avg.attr
155 static struct attribute *loopback_attrs[] = {
156 dev_stats_attrs(latency),
157 dev_stats_attrs(frequency),
158 dev_stats_attrs(throughput),
161 &dev_attr_ms_wait.attr,
162 &dev_attr_error.attr,
165 ATTRIBUTE_GROUPS(loopback);
167 static int gb_loopback_transfer(struct gb_loopback *gb,
168 struct timeval *tping, u32 len)
170 struct timeval ts, te;
172 struct gb_loopback_transfer_request *request;
173 struct gb_loopback_transfer_response *response;
176 request = kmalloc(len + sizeof(*request), GFP_KERNEL);
179 response = kmalloc(len + sizeof(*response), GFP_KERNEL);
185 request->len = cpu_to_le32(len);
187 do_gettimeofday(&ts);
188 retval = gb_operation_sync(gb->connection, GB_LOOPBACK_TYPE_TRANSFER,
189 request, len + sizeof(*request),
190 response, len + sizeof(*response));
191 do_gettimeofday(&te);
192 elapsed_nsecs = timeval_to_ns(&te) - timeval_to_ns(&ts);
193 *tping = ns_to_timeval(elapsed_nsecs);
198 if (memcmp(request->data, response->data, len))
208 static int gb_loopback_ping(struct gb_loopback *gb, struct timeval *tping)
210 struct timeval ts, te;
214 do_gettimeofday(&ts);
215 retval = gb_operation_sync(gb->connection, GB_LOOPBACK_TYPE_PING,
217 do_gettimeofday(&te);
218 elapsed_nsecs = timeval_to_ns(&te) - timeval_to_ns(&ts);
219 *tping = ns_to_timeval(elapsed_nsecs);
224 static int gb_loopback_request_recv(u8 type, struct gb_operation *operation)
226 struct gb_connection *connection = operation->connection;
227 struct gb_loopback_transfer_request *request;
228 struct gb_loopback_transfer_response *response;
231 /* By convention, the AP initiates the version operation */
233 case GB_LOOPBACK_TYPE_PROTOCOL_VERSION:
234 dev_err(&connection->dev,
235 "module-initiated version operation\n");
237 case GB_LOOPBACK_TYPE_PING:
239 case GB_LOOPBACK_TYPE_TRANSFER:
240 if (operation->request->payload_size < sizeof(*request)) {
241 dev_err(&connection->dev,
242 "transfer request too small (%zu < %zu)\n",
243 operation->request->payload_size,
245 return -EINVAL; /* -EMSGSIZE */
247 request = operation->request->payload;
248 len = le32_to_cpu(request->len);
250 if (!gb_operation_response_alloc(operation, len)) {
251 dev_err(&connection->dev,
252 "error allocating response\n");
255 response = operation->response->payload;
256 memcpy(response->data, request->data, len);
260 dev_err(&connection->dev,
261 "unsupported request: %hhu\n", type);
266 static void gb_loopback_reset_stats(struct gb_loopback *gb)
268 struct gb_loopback_stats reset = {
271 memcpy(&gb->latency, &reset, sizeof(struct gb_loopback_stats));
272 memcpy(&gb->throughput, &reset, sizeof(struct gb_loopback_stats));
273 memcpy(&gb->frequency, &reset, sizeof(struct gb_loopback_stats));
274 memset(&gb->ts, 0, sizeof(struct timeval));
277 static void gb_loopback_update_stats(struct gb_loopback_stats *stats,
283 if (elapsed_nsecs >= NSEC_PER_SEC) {
286 do_div(tmp, NSEC_PER_SEC);
287 avg = stats->sum * tmp;
289 avg = stats->sum / stats->count;
291 if (stats->min > avg)
293 if (stats->max < avg)
301 static void gb_loopback_freq_update(struct gb_loopback *gb)
304 gb_loopback_update_stats(&gb->frequency, gb->elapsed_nsecs);
307 static void gb_loopback_bw_update(struct gb_loopback *gb, int error)
310 gb->throughput.sum += gb->size * 2;
311 gb_loopback_update_stats(&gb->throughput, gb->elapsed_nsecs);
314 static void gb_loopback_latency_update(struct gb_loopback *gb,
315 struct timeval *tlat)
320 tmp = timeval_to_ns(tlat);
321 do_div(tmp, NSEC_PER_MSEC);
324 if (gb->latency.min > lat)
325 gb->latency.min = lat;
326 if (gb->latency.max < lat)
327 gb->latency.max = lat;
328 gb->latency.sum += lat;
330 gb_loopback_update_stats(&gb->latency, gb->elapsed_nsecs);
333 static int gb_loopback_fn(void *data)
336 struct timeval tlat = {0, 0};
337 struct gb_loopback *gb = (struct gb_loopback *)data;
339 while (!kthread_should_stop()) {
344 if (gb->type == GB_LOOPBACK_TYPE_PING)
345 error = gb_loopback_ping(gb, &tlat);
346 else if (gb->type == GB_LOOPBACK_TYPE_TRANSFER)
347 error = gb_loopback_transfer(gb, &tlat, gb->size);
350 if (gb->ts.tv_usec == 0 && gb->ts.tv_sec == 0) {
351 do_gettimeofday(&gb->ts);
354 do_gettimeofday(&gb->te);
355 gb->elapsed_nsecs = timeval_to_ns(&gb->te) -
356 timeval_to_ns(&gb->ts);
357 gb_loopback_freq_update(gb);
358 if (gb->type == GB_LOOPBACK_TYPE_PING)
359 gb_loopback_bw_update(gb, error);
360 gb_loopback_latency_update(gb, &tlat);
361 if (gb->elapsed_nsecs >= NSEC_PER_SEC)
370 static int gb_loopback_connection_init(struct gb_connection *connection)
372 struct gb_loopback *gb;
375 gb = kzalloc(sizeof(*gb), GFP_KERNEL);
379 gb->connection = connection;
380 connection->private = gb;
381 retval = sysfs_create_groups(&connection->dev.kobj, loopback_groups);
385 /* Check the version */
386 retval = get_version(gb);
390 gb_loopback_reset_stats(gb);
391 gb->task = kthread_run(gb_loopback_fn, gb, "gb_loopback");
392 if (IS_ERR(gb->task)) {
393 retval = PTR_ERR(gb->task);
400 sysfs_remove_groups(&connection->dev.kobj, loopback_groups);
406 static void gb_loopback_connection_exit(struct gb_connection *connection)
408 struct gb_loopback *gb = connection->private;
410 if (!IS_ERR_OR_NULL(gb->task))
411 kthread_stop(gb->task);
412 sysfs_remove_groups(&connection->dev.kobj, loopback_groups);
416 static struct gb_protocol loopback_protocol = {
418 .id = GREYBUS_PROTOCOL_LOOPBACK,
419 .major = GB_LOOPBACK_VERSION_MAJOR,
420 .minor = GB_LOOPBACK_VERSION_MINOR,
421 .connection_init = gb_loopback_connection_init,
422 .connection_exit = gb_loopback_connection_exit,
423 .request_recv = gb_loopback_request_recv,
426 gb_protocol_driver(&loopback_protocol);
428 MODULE_LICENSE("GPL v2");