1153 lines · 29.2 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * Loopback bridge driver for the Greybus loopback module. * * Copyright 2014 Google Inc. * Copyright 2014 Linaro Ltd. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h>#include <linux/module.h>#include <linux/mutex.h>#include <linux/slab.h>#include <linux/kthread.h>#include <linux/delay.h>#include <linux/random.h>#include <linux/sizes.h>#include <linux/cdev.h>#include <linux/fs.h>#include <linux/kfifo.h>#include <linux/debugfs.h>#include <linux/list_sort.h>#include <linux/spinlock.h>#include <linux/workqueue.h>#include <linux/atomic.h>#include <linux/pm_runtime.h>#include <linux/greybus.h>#include <asm/div64.h> #define NSEC_PER_DAY 86400000000000ULL struct gb_loopback_stats {	u32 min;	u32 max;	u64 sum;	u32 count;}; struct gb_loopback_device {	struct dentry *root;	u32 count;	size_t size_max; 	/* We need to take a lock in atomic context */	spinlock_t lock;	wait_queue_head_t wq;}; static struct gb_loopback_device gb_dev; struct gb_loopback_async_operation {	struct gb_loopback *gb;	struct gb_operation *operation;	ktime_t ts;	int (*completion)(struct gb_loopback_async_operation *op_async);}; struct gb_loopback {	struct gb_connection *connection; 	struct dentry *file;	struct kfifo kfifo_lat;	struct mutex mutex;	struct task_struct *task;	struct device *dev;	wait_queue_head_t wq;	wait_queue_head_t wq_completion;	atomic_t outstanding_operations; 	/* Per connection stats */	ktime_t ts;	struct gb_loopback_stats latency;	struct gb_loopback_stats throughput;	struct gb_loopback_stats requests_per_second;	struct gb_loopback_stats apbridge_unipro_latency;	struct gb_loopback_stats gbphy_firmware_latency; 	int type;	int async;	int id;	u32 size;	u32 iteration_max;	u32 iteration_count;	int us_wait;	u32 error;	u32 requests_completed;	u32 requests_timedout;	u32 timeout;	u32 jiffy_timeout;	u32 timeout_min;	u32 timeout_max;	u32 outstanding_operations_max;	u64 elapsed_nsecs;	u32 apbridge_latency_ts;	u32 gbphy_latency_ts; 	u32 send_count;}; static struct class loopback_class = {	.name		= "gb_loopback",}; static DEFINE_IDA(loopback_ida); /* Min/max values in jiffies */#define GB_LOOPBACK_TIMEOUT_MIN				1#define GB_LOOPBACK_TIMEOUT_MAX				10000 #define GB_LOOPBACK_FIFO_DEFAULT			8192 static unsigned int kfifo_depth = GB_LOOPBACK_FIFO_DEFAULT;module_param(kfifo_depth, uint, 0444); /* Maximum size of any one send data buffer we support */#define MAX_PACKET_SIZE (PAGE_SIZE * 2) #define GB_LOOPBACK_US_WAIT_MAX				1000000 /* interface sysfs attributes */#define gb_loopback_ro_attr(field)				\static ssize_t field##_show(struct device *dev,			\			    struct device_attribute *attr,		\			    char *buf)					\{									\	struct gb_loopback *gb = dev_get_drvdata(dev);			\	return sysfs_emit(buf, "%u\n", gb->field);			\}									\static DEVICE_ATTR_RO(field) #define gb_loopback_ro_stats_attr(name, field, type)		\static ssize_t name##_##field##_show(struct device *dev,	\			    struct device_attribute *attr,		\			    char *buf)					\{									\	struct gb_loopback *gb = dev_get_drvdata(dev);			\	/* Report 0 for min and max if no transfer succeeded */		\	if (!gb->requests_completed)					\		return sysfs_emit(buf, "0\n");				\	return sysfs_emit(buf, "%" #type "\n", gb->name.field);		\}									\static DEVICE_ATTR_RO(name##_##field) #define gb_loopback_ro_avg_attr(name)			\static ssize_t name##_avg_show(struct device *dev,		\			    struct device_attribute *attr,		\			    char *buf)					\{									\	struct gb_loopback_stats *stats;				\	struct gb_loopback *gb;						\	u64 avg, rem;							\	u32 count;							\	gb = dev_get_drvdata(dev);			\	stats = &gb->name;					\	count = stats->count ? stats->count : 1;			\	avg = stats->sum + count / 2000000; /* round closest */		\	rem = do_div(avg, count);					\	rem *= 1000000;							\	do_div(rem, count);						\	return sysfs_emit(buf, "%llu.%06u\n", avg, (u32)rem);		\}									\static DEVICE_ATTR_RO(name##_avg) #define gb_loopback_stats_attrs(field)				\	gb_loopback_ro_stats_attr(field, min, u);		\	gb_loopback_ro_stats_attr(field, max, u);		\	gb_loopback_ro_avg_attr(field) #define gb_dev_loopback_ro_attr(field)				\static ssize_t field##_show(struct device *dev,		\			    struct device_attribute *attr,		\			    char *buf)					\{									\	struct gb_loopback *gb = dev_get_drvdata(dev);			\	return sysfs_emit(buf, "%u\n", gb->field);				\}									\static DEVICE_ATTR_RO(field) #define gb_dev_loopback_rw_attr(field, type)				\static ssize_t field##_show(struct device *dev,				\			    struct device_attribute *attr,		\			    char *buf)					\{									\	struct gb_loopback *gb = dev_get_drvdata(dev);			\	return sysfs_emit(buf, "%" #type "\n", gb->field);			\}									\static ssize_t field##_store(struct device *dev,			\			    struct device_attribute *attr,		\			    const char *buf,				\			    size_t len)					\{									\	int ret;							\	struct gb_loopback *gb = dev_get_drvdata(dev);			\	mutex_lock(&gb->mutex);						\	ret = sscanf(buf, "%"#type, &gb->field);			\	if (ret != 1)							\		len = -EINVAL;						\	else								\		gb_loopback_check_attr(gb);		\	mutex_unlock(&gb->mutex);					\	return len;							\}									\static DEVICE_ATTR_RW(field) static void gb_loopback_reset_stats(struct gb_loopback *gb);static void gb_loopback_check_attr(struct gb_loopback *gb){	if (gb->us_wait > GB_LOOPBACK_US_WAIT_MAX)		gb->us_wait = GB_LOOPBACK_US_WAIT_MAX;	if (gb->size > gb_dev.size_max)		gb->size = gb_dev.size_max;	gb->requests_timedout = 0;	gb->requests_completed = 0;	gb->iteration_count = 0;	gb->send_count = 0;	gb->error = 0; 	if (kfifo_depth < gb->iteration_max) {		dev_warn(gb->dev,			 "cannot log bytes %u kfifo_depth %u\n",			 gb->iteration_max, kfifo_depth);	}	kfifo_reset_out(&gb->kfifo_lat); 	switch (gb->type) {	case GB_LOOPBACK_TYPE_PING:	case GB_LOOPBACK_TYPE_TRANSFER:	case GB_LOOPBACK_TYPE_SINK:		gb->jiffy_timeout = usecs_to_jiffies(gb->timeout);		if (!gb->jiffy_timeout)			gb->jiffy_timeout = GB_LOOPBACK_TIMEOUT_MIN;		else if (gb->jiffy_timeout > GB_LOOPBACK_TIMEOUT_MAX)			gb->jiffy_timeout = GB_LOOPBACK_TIMEOUT_MAX;		gb_loopback_reset_stats(gb);		wake_up(&gb->wq);		break;	default:		gb->type = 0;		break;	}} /* Time to send and receive one message */gb_loopback_stats_attrs(latency);/* Number of requests sent per second on this cport */gb_loopback_stats_attrs(requests_per_second);/* Quantity of data sent and received on this cport */gb_loopback_stats_attrs(throughput);/* Latency across the UniPro link from APBridge's perspective */gb_loopback_stats_attrs(apbridge_unipro_latency);/* Firmware induced overhead in the GPBridge */gb_loopback_stats_attrs(gbphy_firmware_latency); /* Number of errors encountered during loop */gb_loopback_ro_attr(error);/* Number of requests successfully completed async */gb_loopback_ro_attr(requests_completed);/* Number of requests timed out async */gb_loopback_ro_attr(requests_timedout);/* Timeout minimum in useconds */gb_loopback_ro_attr(timeout_min);/* Timeout minimum in useconds */gb_loopback_ro_attr(timeout_max); /* * Type of loopback message to send based on protocol type definitions * 0 => Don't send message * 2 => Send ping message continuously (message without payload) * 3 => Send transfer message continuously (message with payload, *					   payload returned in response) * 4 => Send a sink message (message with payload, no payload in response) */gb_dev_loopback_rw_attr(type, d);/* Size of transfer message payload: 0-4096 bytes */gb_dev_loopback_rw_attr(size, u);/* Time to wait between two messages: 0-1000 ms */gb_dev_loopback_rw_attr(us_wait, d);/* Maximum iterations for a given operation: 1-(2^32-1), 0 implies infinite */gb_dev_loopback_rw_attr(iteration_max, u);/* The current index of the for (i = 0; i < iteration_max; i++) loop */gb_dev_loopback_ro_attr(iteration_count);/* A flag to indicate synchronous or asynchronous operations */gb_dev_loopback_rw_attr(async, u);/* Timeout of an individual asynchronous request */gb_dev_loopback_rw_attr(timeout, u);/* Maximum number of in-flight operations before back-off */gb_dev_loopback_rw_attr(outstanding_operations_max, u); static struct attribute *loopback_attrs[] = {	&dev_attr_latency_min.attr,	&dev_attr_latency_max.attr,	&dev_attr_latency_avg.attr,	&dev_attr_requests_per_second_min.attr,	&dev_attr_requests_per_second_max.attr,	&dev_attr_requests_per_second_avg.attr,	&dev_attr_throughput_min.attr,	&dev_attr_throughput_max.attr,	&dev_attr_throughput_avg.attr,	&dev_attr_apbridge_unipro_latency_min.attr,	&dev_attr_apbridge_unipro_latency_max.attr,	&dev_attr_apbridge_unipro_latency_avg.attr,	&dev_attr_gbphy_firmware_latency_min.attr,	&dev_attr_gbphy_firmware_latency_max.attr,	&dev_attr_gbphy_firmware_latency_avg.attr,	&dev_attr_type.attr,	&dev_attr_size.attr,	&dev_attr_us_wait.attr,	&dev_attr_iteration_count.attr,	&dev_attr_iteration_max.attr,	&dev_attr_async.attr,	&dev_attr_error.attr,	&dev_attr_requests_completed.attr,	&dev_attr_requests_timedout.attr,	&dev_attr_timeout.attr,	&dev_attr_outstanding_operations_max.attr,	&dev_attr_timeout_min.attr,	&dev_attr_timeout_max.attr,	NULL,};ATTRIBUTE_GROUPS(loopback); static void gb_loopback_calculate_stats(struct gb_loopback *gb, bool error); static u32 gb_loopback_nsec_to_usec_latency(u64 elapsed_nsecs){	do_div(elapsed_nsecs, NSEC_PER_USEC);	return elapsed_nsecs;} static u64 __gb_loopback_calc_latency(u64 t1, u64 t2){	if (t2 > t1)		return t2 - t1;	else		return NSEC_PER_DAY - t2 + t1;} static u64 gb_loopback_calc_latency(ktime_t ts, ktime_t te){	return __gb_loopback_calc_latency(ktime_to_ns(ts), ktime_to_ns(te));} static int gb_loopback_operation_sync(struct gb_loopback *gb, int type,				      void *request, int request_size,				      void *response, int response_size){	struct gb_operation *operation;	ktime_t ts, te;	int ret; 	ts = ktime_get();	operation = gb_operation_create(gb->connection, type, request_size,					response_size, GFP_KERNEL);	if (!operation)		return -ENOMEM; 	if (request_size)		memcpy(operation->request->payload, request, request_size); 	ret = gb_operation_request_send_sync(operation);	if (ret) {		dev_err(&gb->connection->bundle->dev,			"synchronous operation failed: %d\n", ret);		goto out_put_operation;	} else {		if (response_size == operation->response->payload_size) {			memcpy(response, operation->response->payload,			       response_size);		} else {			dev_err(&gb->connection->bundle->dev,				"response size %zu expected %d\n",				operation->response->payload_size,				response_size);			ret = -EINVAL;			goto out_put_operation;		}	} 	te = ktime_get(); 	/* Calculate the total time the message took */	gb->elapsed_nsecs = gb_loopback_calc_latency(ts, te); out_put_operation:	gb_operation_put(operation); 	return ret;} static void gb_loopback_async_wait_all(struct gb_loopback *gb){	wait_event(gb->wq_completion,		   !atomic_read(&gb->outstanding_operations));} static void gb_loopback_async_operation_callback(struct gb_operation *operation){	struct gb_loopback_async_operation *op_async;	struct gb_loopback *gb;	ktime_t te;	int result; 	te = ktime_get();	result = gb_operation_result(operation);	op_async = gb_operation_get_data(operation);	gb = op_async->gb; 	mutex_lock(&gb->mutex); 	if (!result && op_async->completion)		result = op_async->completion(op_async); 	if (!result) {		gb->elapsed_nsecs = gb_loopback_calc_latency(op_async->ts, te);	} else {		gb->error++;		if (result == -ETIMEDOUT)			gb->requests_timedout++;	} 	gb->iteration_count++;	gb_loopback_calculate_stats(gb, result); 	mutex_unlock(&gb->mutex); 	dev_dbg(&gb->connection->bundle->dev, "complete operation %d\n",		operation->id); 	/* Wake up waiters */	atomic_dec(&op_async->gb->outstanding_operations);	wake_up(&gb->wq_completion); 	/* Release resources */	gb_operation_put(operation);	kfree(op_async);} static int gb_loopback_async_operation(struct gb_loopback *gb, int type,				       void *request, int request_size,				       int response_size,				       void *completion){	struct gb_loopback_async_operation *op_async;	struct gb_operation *operation;	int ret; 	op_async = kzalloc_obj(*op_async);	if (!op_async)		return -ENOMEM; 	operation = gb_operation_create(gb->connection, type, request_size,					response_size, GFP_KERNEL);	if (!operation) {		kfree(op_async);		return -ENOMEM;	} 	if (request_size)		memcpy(operation->request->payload, request, request_size); 	gb_operation_set_data(operation, op_async); 	op_async->gb = gb;	op_async->operation = operation;	op_async->completion = completion; 	op_async->ts = ktime_get(); 	atomic_inc(&gb->outstanding_operations);	ret = gb_operation_request_send(operation,					gb_loopback_async_operation_callback,					jiffies_to_msecs(gb->jiffy_timeout),					GFP_KERNEL);	if (ret) {		atomic_dec(&gb->outstanding_operations);		gb_operation_put(operation);		kfree(op_async);	}	return ret;} static int gb_loopback_sync_sink(struct gb_loopback *gb, u32 len){	struct gb_loopback_transfer_request *request;	int retval; 	request = kmalloc(len + sizeof(*request), GFP_KERNEL);	if (!request)		return -ENOMEM; 	request->len = cpu_to_le32(len);	retval = gb_loopback_operation_sync(gb, GB_LOOPBACK_TYPE_SINK,					    request, len + sizeof(*request),					    NULL, 0);	kfree(request);	return retval;} static int gb_loopback_sync_transfer(struct gb_loopback *gb, u32 len)

Lines 1–500 of 1153.