// 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",
.owner = THIS_MODULE,
};
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 sprintf(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 sprintf(buf, "0\n"); \
return sprintf(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 sprintf(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_loopback_attr(field, type) \
static ssize_t field##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \