brintos

brintos / linux-shallow public Read only

0
0
Text · 8.6 KiB · 59a8f3a Raw
346 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Sloppy logic analyzer using GPIOs (to be run on an isolated CPU)4 *5 * Use the 'gpio-sloppy-logic-analyzer' script in the 'tools/gpio' folder for6 * easier usage and further documentation. Note that this is a last resort7 * analyzer which can be affected by latencies and non-deterministic code8 * paths. However, for e.g. remote development, it may be useful to get a first9 * view and aid further debugging.10 *11 * Copyright (C) Wolfram Sang <wsa@sang-engineering.com>12 * Copyright (C) Renesas Electronics Corporation13 */14 15#include <linux/ctype.h>16#include <linux/debugfs.h>17#include <linux/delay.h>18#include <linux/device.h>19#include <linux/err.h>20#include <linux/gpio/consumer.h>21#include <linux/init.h>22#include <linux/ktime.h>23#include <linux/mod_devicetable.h>24#include <linux/module.h>25#include <linux/mutex.h>26#include <linux/platform_device.h>27#include <linux/property.h>28#include <linux/slab.h>29#include <linux/sizes.h>30#include <linux/timekeeping.h>31#include <linux/types.h>32#include <linux/vmalloc.h>33 34#define GPIO_LA_NAME "gpio-sloppy-logic-analyzer"35#define GPIO_LA_DEFAULT_BUF_SIZE SZ_256K36/* can be increased but then we need to extend the u8 buffers */37#define GPIO_LA_MAX_PROBES 838#define GPIO_LA_NUM_TESTS 102439 40struct gpio_la_poll_priv {41	struct mutex blob_lock; /* serialize access to the blob (data) */42	u32 buf_idx;43	struct gpio_descs *descs;44	unsigned long delay_ns;45	unsigned long acq_delay;46	struct debugfs_blob_wrapper blob;47	struct dentry *debug_dir;48	struct dentry *blob_dent;49	struct debugfs_blob_wrapper meta;50	struct device *dev;51	unsigned int trig_len;52	u8 *trig_data;53};54 55static struct dentry *gpio_la_poll_debug_dir;56 57static __always_inline int gpio_la_get_array(struct gpio_descs *d, unsigned long *sptr)58{59	int ret;60 61	ret = gpiod_get_array_value(d->ndescs, d->desc, d->info, sptr);62	if (ret == 0 && fatal_signal_pending(current))63		ret = -EINTR;64 65	return ret;66}67 68static int fops_capture_set(void *data, u64 val)69{70	struct gpio_la_poll_priv *priv = data;71	u8 *la_buf = priv->blob.data;72	unsigned long state = 0; /* zeroed because GPIO arrays are bitfields */73	unsigned long delay;74	ktime_t start_time;75	unsigned int i;76	int ret;77 78	if (!val)79		return 0;80 81	if (!la_buf)82		return -ENOMEM;83 84	if (!priv->delay_ns)85		return -EINVAL;86 87	mutex_lock(&priv->blob_lock);88	if (priv->blob_dent) {89		debugfs_remove(priv->blob_dent);90		priv->blob_dent = NULL;91	}92 93	priv->buf_idx = 0;94 95	local_irq_disable();96	preempt_disable_notrace();97 98	/* Measure delay of reading GPIOs */99	start_time = ktime_get();100	for (i = 0; i < GPIO_LA_NUM_TESTS; i++) {101		ret = gpio_la_get_array(priv->descs, &state);102		if (ret)103			goto out;104	}105 106	priv->acq_delay = ktime_sub(ktime_get(), start_time) / GPIO_LA_NUM_TESTS;107	if (priv->delay_ns < priv->acq_delay) {108		ret = -ERANGE;109		goto out;110	}111 112	delay = priv->delay_ns - priv->acq_delay;113 114	/* Wait for triggers */115	for (i = 0; i < priv->trig_len; i += 2) {116		do {117			ret = gpio_la_get_array(priv->descs, &state);118			if (ret)119				goto out;120 121			ndelay(delay);122		} while ((state & priv->trig_data[i]) != priv->trig_data[i + 1]);123	}124 125	/* With triggers, final state is also the first sample */126	if (priv->trig_len)127		la_buf[priv->buf_idx++] = state;128 129	/* Sample */130	while (priv->buf_idx < priv->blob.size) {131		ret = gpio_la_get_array(priv->descs, &state);132		if (ret)133			goto out;134 135		la_buf[priv->buf_idx++] = state;136		ndelay(delay);137	}138out:139	preempt_enable_notrace();140	local_irq_enable();141	if (ret)142		dev_err(priv->dev, "couldn't read GPIOs: %d\n", ret);143 144	kfree(priv->trig_data);145	priv->trig_data = NULL;146	priv->trig_len = 0;147 148	priv->blob_dent = debugfs_create_blob("sample_data", 0400, priv->debug_dir, &priv->blob);149	mutex_unlock(&priv->blob_lock);150 151	return ret;152}153DEFINE_DEBUGFS_ATTRIBUTE(fops_capture, NULL, fops_capture_set, "%llu\n");154 155static int fops_buf_size_get(void *data, u64 *val)156{157	struct gpio_la_poll_priv *priv = data;158 159	*val = priv->blob.size;160 161	return 0;162}163 164static int fops_buf_size_set(void *data, u64 val)165{166	struct gpio_la_poll_priv *priv = data;167	int ret = 0;168	void *p;169 170	if (!val)171		return -EINVAL;172 173	mutex_lock(&priv->blob_lock);174 175	vfree(priv->blob.data);176	p = vzalloc(val);177	if (!p) {178		val = 0;179		ret = -ENOMEM;180	}181 182	priv->blob.data = p;183	priv->blob.size = val;184 185	mutex_unlock(&priv->blob_lock);186	return ret;187}188DEFINE_DEBUGFS_ATTRIBUTE(fops_buf_size, fops_buf_size_get, fops_buf_size_set, "%llu\n");189 190static int trigger_open(struct inode *inode, struct file *file)191{192	return single_open(file, NULL, inode->i_private);193}194 195static ssize_t trigger_write(struct file *file, const char __user *ubuf,196			     size_t count, loff_t *offset)197{198	struct seq_file *m = file->private_data;199	struct gpio_la_poll_priv *priv = m->private;200	char *buf;201 202	/* upper limit is arbitrary but should be less than PAGE_SIZE */203	if (count > 2048 || count & 1)204		return -EINVAL;205 206	buf = memdup_user(ubuf, count);207	if (IS_ERR(buf))208		return PTR_ERR(buf);209 210	priv->trig_data = buf;211	priv->trig_len = count;212 213	return count;214}215 216static const struct file_operations fops_trigger = {217	.owner = THIS_MODULE,218	.open = trigger_open,219	.write = trigger_write,220	.release = single_release,221};222 223static int gpio_la_poll_probe(struct platform_device *pdev)224{225	struct gpio_la_poll_priv *priv;226	struct device *dev = &pdev->dev;227	const char *devname = dev_name(dev);228	const char *gpio_names[GPIO_LA_MAX_PROBES];229	char *meta = NULL;230	unsigned int i, meta_len = 0;231	int ret;232 233	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);234	if (!priv)235		return -ENOMEM;236 237	ret = devm_mutex_init(dev, &priv->blob_lock);238	if (ret)239		return ret;240 241	fops_buf_size_set(priv, GPIO_LA_DEFAULT_BUF_SIZE);242 243	priv->descs = devm_gpiod_get_array(dev, "probe", GPIOD_IN);244	if (IS_ERR(priv->descs))245		return PTR_ERR(priv->descs);246 247	/* artificial limit to keep 1 byte per sample for now */248	if (priv->descs->ndescs > GPIO_LA_MAX_PROBES)249		return -EFBIG;250 251	ret = device_property_read_string_array(dev, "probe-names", gpio_names,252						priv->descs->ndescs);253	if (ret >= 0 && ret != priv->descs->ndescs)254		ret = -EBADR;255	if (ret < 0)256		return dev_err_probe(dev, ret, "error naming the GPIOs");257 258	for (i = 0; i < priv->descs->ndescs; i++) {259		unsigned int add_len;260		char *new_meta, *consumer_name;261 262		if (gpiod_cansleep(priv->descs->desc[i]))263			return -EREMOTE;264 265		consumer_name = kasprintf(GFP_KERNEL, "%s: %s", devname, gpio_names[i]);266		if (!consumer_name)267			return -ENOMEM;268		gpiod_set_consumer_name(priv->descs->desc[i], consumer_name);269		kfree(consumer_name);270 271		/* '10' is length of 'probe00=\n\0' */272		add_len = strlen(gpio_names[i]) + 10;273 274		new_meta = devm_krealloc(dev, meta, meta_len + add_len, GFP_KERNEL);275		if (!new_meta)276			return -ENOMEM;277 278		meta = new_meta;279		meta_len += snprintf(meta + meta_len, add_len, "probe%02u=%s\n",280				     i + 1, gpio_names[i]);281	}282 283	platform_set_drvdata(pdev, priv);284	priv->dev = dev;285 286	priv->meta.data = meta;287	priv->meta.size = meta_len;288	priv->debug_dir = debugfs_create_dir(devname, gpio_la_poll_debug_dir);289	debugfs_create_blob("meta_data", 0400, priv->debug_dir, &priv->meta);290	debugfs_create_ulong("delay_ns", 0600, priv->debug_dir, &priv->delay_ns);291	debugfs_create_ulong("delay_ns_acquisition", 0400, priv->debug_dir, &priv->acq_delay);292	debugfs_create_file_unsafe("buf_size", 0600, priv->debug_dir, priv, &fops_buf_size);293	debugfs_create_file_unsafe("capture", 0200, priv->debug_dir, priv, &fops_capture);294	debugfs_create_file_unsafe("trigger", 0200, priv->debug_dir, priv, &fops_trigger);295 296	return 0;297}298 299static void gpio_la_poll_remove(struct platform_device *pdev)300{301	struct gpio_la_poll_priv *priv = platform_get_drvdata(pdev);302 303	mutex_lock(&priv->blob_lock);304	debugfs_remove_recursive(priv->debug_dir);305	mutex_unlock(&priv->blob_lock);306}307 308static const struct of_device_id gpio_la_poll_of_match[] = {309	{ .compatible = GPIO_LA_NAME },310	{ }311};312MODULE_DEVICE_TABLE(of, gpio_la_poll_of_match);313 314static struct platform_driver gpio_la_poll_device_driver = {315	.probe = gpio_la_poll_probe,316	.remove_new = gpio_la_poll_remove,317	.driver = {318		.name = GPIO_LA_NAME,319		.of_match_table = gpio_la_poll_of_match,320	}321};322 323static int __init gpio_la_poll_init(void)324{325	gpio_la_poll_debug_dir = debugfs_create_dir(GPIO_LA_NAME, NULL);326 327	return platform_driver_register(&gpio_la_poll_device_driver);328}329/*330 * Non-strict pin controllers can read GPIOs while being muxed to something else.331 * To support that, we need to claim GPIOs before further pinmuxing happens. So,332 * we probe early using 'late_initcall'333 */334late_initcall(gpio_la_poll_init);335 336static void __exit gpio_la_poll_exit(void)337{338	platform_driver_unregister(&gpio_la_poll_device_driver);339	debugfs_remove_recursive(gpio_la_poll_debug_dir);340}341module_exit(gpio_la_poll_exit);342 343MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");344MODULE_DESCRIPTION("Sloppy logic analyzer using GPIOs");345MODULE_LICENSE("GPL");346