File Index
Files and directories
Sign in
FILE

axis-fifo.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/axis-fifo/axis-fifo.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Xilinx AXIS FIFO: interface to the Xilinx AXI-Stream FIFO IP core
  4 *
  5 * Copyright (C) 2018 Jacob Feder
  6 *
  7 * Authors:  Jacob Feder <jacobsfeder@gmail.com>
  8 *
  9 * See Xilinx PG080 document for IP details
 10 */
 11
 12/* ----------------------------
 13 *           includes
 14 * ----------------------------
 15 */
 16
 17#include <linux/kernel.h>
 18#include <linux/of.h>
 19#include <linux/platform_device.h>
 20#include <linux/wait.h>
 21#include <linux/mutex.h>
 22#include <linux/device.h>
 23#include <linux/cdev.h>
 24#include <linux/init.h>
 25#include <linux/module.h>
 26#include <linux/slab.h>
 27#include <linux/io.h>
 28#include <linux/moduleparam.h>
 29#include <linux/interrupt.h>
 30#include <linux/param.h>
 31#include <linux/fs.h>
 32#include <linux/types.h>
 33#include <linux/uaccess.h>
 34#include <linux/jiffies.h>
 35#include <linux/miscdevice.h>
 36#include <linux/debugfs.h>
 37
 38/* ----------------------------
 39 *       driver parameters
 40 * ----------------------------
 41 */
 42
 43#define DRIVER_NAME "axis_fifo"
 44
 45#define READ_BUF_SIZE 128U /* read buffer length in words */
 46
 47#define AXIS_FIFO_DEBUG_REG_NAME_MAX_LEN	4
 48
 49/* ----------------------------
 50 *     IP register offsets
 51 * ----------------------------
 52 */
 53
 54#define XLLF_ISR_OFFSET  0x00000000  /* Interrupt Status */
 55#define XLLF_IER_OFFSET  0x00000004  /* Interrupt Enable */
 56
 57#define XLLF_TDFR_OFFSET 0x00000008  /* Transmit Reset */
 58#define XLLF_TDFV_OFFSET 0x0000000c  /* Transmit Vacancy */
 59#define XLLF_TDFD_OFFSET 0x00000010  /* Transmit Data */
 60#define XLLF_TLR_OFFSET  0x00000014  /* Transmit Length */
 61
 62#define XLLF_RDFR_OFFSET 0x00000018  /* Receive Reset */
 63#define XLLF_RDFO_OFFSET 0x0000001c  /* Receive Occupancy */
 64#define XLLF_RDFD_OFFSET 0x00000020  /* Receive Data */
 65#define XLLF_RLR_OFFSET  0x00000024  /* Receive Length */
 66#define XLLF_SRR_OFFSET  0x00000028  /* Local Link Reset */
 67#define XLLF_TDR_OFFSET  0x0000002C  /* Transmit Destination */
 68#define XLLF_RDR_OFFSET  0x00000030  /* Receive Destination */
 69
 70/* ----------------------------
 71 *     reset register masks
 72 * ----------------------------
 73 */
 74
 75#define XLLF_RDFR_RESET_MASK        0x000000a5 /* receive reset value */
 76#define XLLF_TDFR_RESET_MASK        0x000000a5 /* Transmit reset value */
 77#define XLLF_SRR_RESET_MASK         0x000000a5 /* Local Link reset value */
 78
 79/* ----------------------------
 80 *       interrupt masks
 81 * ----------------------------
 82 */
 83
 84#define XLLF_INT_RPURE_MASK       0x80000000 /* Receive under-read */
 85#define XLLF_INT_RPORE_MASK       0x40000000 /* Receive over-read */
 86#define XLLF_INT_RPUE_MASK        0x20000000 /* Receive underrun (empty) */
 87#define XLLF_INT_TPOE_MASK        0x10000000 /* Transmit overrun */
 88#define XLLF_INT_TC_MASK          0x08000000 /* Transmit complete */
 89#define XLLF_INT_RC_MASK          0x04000000 /* Receive complete */
 90#define XLLF_INT_TSE_MASK         0x02000000 /* Transmit length mismatch */
 91
 92#define XLLF_INT_CLEAR_ALL	GENMASK(31, 0)
 93
 94/* ----------------------------
 95 *           globals
 96 * ----------------------------
 97 */
 98static long read_timeout = 1000; /* ms to wait before read() times out */
 99static long write_timeout = 1000; /* ms to wait before write() times out */
100
101static DEFINE_IDA(axis_fifo_ida);
102
103/* ----------------------------
104 * module command-line arguments
105 * ----------------------------
106 */
107
108module_param(read_timeout, long, 0444);
109MODULE_PARM_DESC(read_timeout, "ms to wait before blocking read() timing out; set to -1 for no timeout");
110module_param(write_timeout, long, 0444);
111MODULE_PARM_DESC(write_timeout, "ms to wait before blocking write() timing out; set to -1 for no timeout");
112
113/* ----------------------------
114 *            types
115 * ----------------------------
116 */
117
118struct axis_fifo {
119	int id;
120	void __iomem *base_addr; /* kernel space memory */
121
122	unsigned int rx_fifo_depth; /* max words in the receive fifo */
123	unsigned int tx_fifo_depth; /* max words in the transmit fifo */
124	int has_rx_fifo; /* whether the IP has the rx fifo enabled */
125	int has_tx_fifo; /* whether the IP has the tx fifo enabled */
126
127	wait_queue_head_t read_queue; /* wait queue for asynchronos read */
128	struct mutex read_lock; /* lock for reading */
129	wait_queue_head_t write_queue; /* wait queue for asynchronos write */
130	struct mutex write_lock; /* lock for writing */
131
132	struct device *dt_device; /* device created from the device tree */
133	struct miscdevice miscdev;
134
135	struct dentry *debugfs_dir;
136};
137
138struct axis_fifo_debug_reg {
139	const char * const name;
140	unsigned int offset;
141};
142
143/* ----------------------------
144 *        implementation
145 * ----------------------------
146 */
147
148static void reset_ip_core(struct axis_fifo *fifo)
149{
150	iowrite32(XLLF_SRR_RESET_MASK, fifo->base_addr + XLLF_SRR_OFFSET);
151	iowrite32(XLLF_TDFR_RESET_MASK, fifo->base_addr + XLLF_TDFR_OFFSET);
152	iowrite32(XLLF_RDFR_RESET_MASK, fifo->base_addr + XLLF_RDFR_OFFSET);
153	iowrite32(XLLF_INT_TC_MASK | XLLF_INT_RC_MASK | XLLF_INT_RPURE_MASK |
154		  XLLF_INT_RPORE_MASK | XLLF_INT_RPUE_MASK |
155		  XLLF_INT_TPOE_MASK | XLLF_INT_TSE_MASK,
156		  fifo->base_addr + XLLF_IER_OFFSET);
157	iowrite32(XLLF_INT_CLEAR_ALL, fifo->base_addr + XLLF_ISR_OFFSET);
158}
159
160/**
161 * axis_fifo_read() - Read a packet from AXIS-FIFO character device.
162 * @f: Open file.
163 * @buf: User space buffer to read to.
164 * @len: User space buffer length.
165 * @off: Buffer offset.
166 *
167 * As defined by the device's documentation, we need to check the device's
168 * occupancy before reading the length register and then the data. All these
169 * operations must be executed atomically, in order and one after the other
170 * without missing any.
171 *
172 * Returns the number of bytes read from the device or negative error code
173 *	on failure.
174 */
175static ssize_t axis_fifo_read(struct file *f, char __user *buf,
176			      size_t len, loff_t *off)
177{
178	struct axis_fifo *fifo = (struct axis_fifo *)f->private_data;
179	size_t bytes_available;
180	unsigned int words_available;
181	unsigned int copied;
182	unsigned int copy;
183	unsigned int i;
184	int ret;
185	u32 tmp_buf[READ_BUF_SIZE];
186
187	if (f->f_flags & O_NONBLOCK) {
188		/*
189		 * Device opened in non-blocking mode. Try to lock it and then
190		 * check if any packet is available.
191		 */
192		if (!mutex_trylock(&fifo->read_lock))
193			return -EAGAIN;
194
195		if (!ioread32(fifo->base_addr + XLLF_RDFO_OFFSET)) {
196			ret = -EAGAIN;
197			goto end_unlock;
198		}
199	} else {
200		/* opened in blocking mode
201		 * wait for a packet available interrupt (or timeout)
202		 * if nothing is currently available
203		 */
204		mutex_lock(&fifo->read_lock);
205		ret = wait_event_interruptible_timeout(fifo->read_queue,
206						       ioread32(fifo->base_addr + XLLF_RDFO_OFFSET),
207						       read_timeout);
208
209		if (ret <= 0) {
210			if (ret == 0) {
211				ret = -EAGAIN;
212			} else if (ret != -ERESTARTSYS) {
213				dev_err(fifo->dt_device, "wait_event_interruptible_timeout() error in read (ret=%i)\n",
214					ret);
215			}
216
217			goto end_unlock;
218		}
219	}
220
221	bytes_available = ioread32(fifo->base_addr + XLLF_RLR_OFFSET);
222	words_available = bytes_available / sizeof(u32);
223	if (!bytes_available) {
224		dev_err(fifo->dt_device, "received a packet of length 0\n");
225		ret = -EIO;
226		goto end_unlock;
227	}
228
229	if (bytes_available > len) {
230		dev_err(fifo->dt_device, "user read buffer too small (available bytes=%zu user buffer bytes=%zu)\n",
231			bytes_available, len);
232		ret = -EINVAL;
233		goto err_flush_rx;
234	}
235
236	if (bytes_available % sizeof(u32)) {
237		/* this probably can't happen unless IP
238		 * registers were previously mishandled
239		 */
240		dev_err(fifo->dt_device, "received a packet that isn't word-aligned\n");
241		ret = -EIO;
242		goto err_flush_rx;
243	}
244
245	/* read data into an intermediate buffer, copying the contents
246	 * to userspace when the buffer is full
247	 */
248	copied = 0;
249	while (words_available > 0) {
250		copy = min(words_available, READ_BUF_SIZE);
251
252		for (i = 0; i < copy; i++) {
253			tmp_buf[i] = ioread32(fifo->base_addr +
254					      XLLF_RDFD_OFFSET);
255		}
256		words_available -= copy;
257
258		if (copy_to_user(buf + copied * sizeof(u32), tmp_buf,
259				 copy * sizeof(u32))) {
260			ret = -EFAULT;
261			goto err_flush_rx;
262		}
263
264		copied += copy;
265	}
266	mutex_unlock(&fifo->read_lock);
267
268	return bytes_available;
269
270err_flush_rx:
271	while (words_available--)
272		ioread32(fifo->base_addr + XLLF_RDFD_OFFSET);
273
274end_unlock:
275	mutex_unlock(&fifo->read_lock);
276
277	return ret;
278}
279
280/**
281 * axis_fifo_write() - Write buffer to AXIS-FIFO character device.
282 * @f: Open file.
283 * @buf: User space buffer to write to the device.
284 * @len: User space buffer length.
285 * @off: Buffer offset.
286 *
287 * As defined by the device's documentation, we need to write to the device's
288 * data buffer then to the device's packet length register atomically. Also,
289 * we need to lock before checking if the device has available space to avoid
290 * any concurrency issue.
291 *
292 * Returns the number of bytes written to the device or negative error code
293 *	on failure.
294 */
295static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
296			       size_t len, loff_t *off)
297{
298	struct axis_fifo *fifo = (struct axis_fifo *)f->private_data;
299	unsigned int words_to_write;
300	u32 *txbuf;
301	int ret;
302
303	if (len % sizeof(u32)) {
304		dev_err(fifo->dt_device,
305			"tried to send a packet that isn't word-aligned\n");
306		return -EINVAL;
307	}
308
309	words_to_write = len / sizeof(u32);
310
311	if (!words_to_write) {
312		dev_err(fifo->dt_device,
313			"tried to send a packet of length 0\n");
314		return -EINVAL;
315	}
316
317	/*
318	 * In 'Store-and-Forward' mode, the maximum packet that can be
319	 * transmitted is limited by the size of the FIFO, which is
320	 * (C_TX_FIFO_DEPTH–4)*(data interface width/8) bytes.
321	 *
322	 * Do not attempt to send a packet larger than 'tx_fifo_depth - 4',
323	 * otherwise a 'Transmit Packet Overrun Error' interrupt will be
324	 * raised, which requires a reset of the TX circuit to recover.
325	 */
326	if (words_to_write > (fifo->tx_fifo_depth - 4))
327		return -EINVAL;
328
329	if (f->f_flags & O_NONBLOCK) {
330		/*
331		 * Device opened in non-blocking mode. Try to lock it and then
332		 * check if there is any room to write the given buffer.
333		 */
334		if (!mutex_trylock(&fifo->write_lock))
335			return -EAGAIN;
336
337		if (words_to_write > ioread32(fifo->base_addr +
338					      XLLF_TDFV_OFFSET)) {
339			ret = -EAGAIN;
340			goto end_unlock;
341		}
342	} else {
343		/* opened in blocking mode */
344
345		/* wait for an interrupt (or timeout) if there isn't
346		 * currently enough room in the fifo
347		 */
348		mutex_lock(&fifo->write_lock);
349		ret = wait_event_interruptible_timeout(fifo->write_queue,
350						       ioread32(fifo->base_addr + XLLF_TDFV_OFFSET)
351								>= words_to_write,
352						       write_timeout);
353
354		if (ret <= 0) {
355			if (ret == 0) {
356				ret = -EAGAIN;
357			} else if (ret != -ERESTARTSYS) {
358				dev_err(fifo->dt_device, "wait_event_interruptible_timeout() error in write (ret=%i)\n",
359					ret);
360			}
361
362			goto end_unlock;
363		}
364	}
365
366	txbuf = vmemdup_user(buf, len);
367	if (IS_ERR(txbuf)) {
368		ret = PTR_ERR(txbuf);
369		goto end_unlock;
370	}
371
372	for (int i = 0; i < words_to_write; ++i)
373		iowrite32(txbuf[i], fifo->base_addr + XLLF_TDFD_OFFSET);
374
375	/* write packet size to fifo */
376	iowrite32(len, fifo->base_addr + XLLF_TLR_OFFSET);
377
378	ret = len;
379	kvfree(txbuf);
380end_unlock:
381	mutex_unlock(&fifo->write_lock);
382
383	return ret;
384}
385
386static irqreturn_t axis_fifo_irq(int irq, void *dw)
387{
388	struct axis_fifo *fifo = dw;
389	u32 isr, ier, intr;
390
391	ier = ioread32(fifo->base_addr + XLLF_IER_OFFSET);
392	isr = ioread32(fifo->base_addr + XLLF_ISR_OFFSET);
393	intr = ier & isr;
394
395	if (intr & XLLF_INT_RC_MASK)
396		wake_up(&fifo->read_queue);
397
398	if (intr & XLLF_INT_TC_MASK)
399		wake_up(&fifo->write_queue);
400
401	if (intr & XLLF_INT_RPURE_MASK)
402		dev_err(fifo->dt_device, "receive under-read interrupt\n");
403
404	if (intr & XLLF_INT_RPORE_MASK)
405		dev_err(fifo->dt_device, "receive over-read interrupt\n");
406
407	if (intr & XLLF_INT_RPUE_MASK)
408		dev_err(fifo->dt_device, "receive underrun error interrupt\n");
409
410	if (intr & XLLF_INT_TPOE_MASK)
411		dev_err(fifo->dt_device, "transmit overrun error interrupt\n");
412
413	if (intr & XLLF_INT_TSE_MASK)
414		dev_err(fifo->dt_device,
415			"transmit length mismatch error interrupt\n");
416
417	iowrite32(XLLF_INT_CLEAR_ALL, fifo->base_addr + XLLF_ISR_OFFSET);
418
419	return IRQ_HANDLED;
420}
421
422static int axis_fifo_open(struct inode *inod, struct file *f)
423{
424	struct axis_fifo *fifo = container_of(f->private_data,
425					      struct axis_fifo, miscdev);
426	unsigned int flags = f->f_flags & O_ACCMODE;
427
428	f->private_data = fifo;
429
430	if ((flags == O_WRONLY || flags == O_RDWR) && !fifo->has_tx_fifo)
431		return -EPERM;
432
433	if ((flags == O_RDONLY || flags == O_RDWR) && !fifo->has_rx_fifo)
434		return -EPERM;
435
436	return 0;
437}
438
439static int axis_fifo_close(struct inode *inod, struct file *f)
440{
441	f->private_data = NULL;
442
443	return 0;
444}
445
446static const struct file_operations fops = {
447	.owner = THIS_MODULE,
448	.open = axis_fifo_open,
449	.release = axis_fifo_close,
450	.read = axis_fifo_read,
451	.write = axis_fifo_write
452};
453
454static int axis_fifo_debugfs_regs_show(struct seq_file *m, void *p)
455{
456	static const struct axis_fifo_debug_reg regs[] = {
457		{"isr", XLLF_ISR_OFFSET},
458		{"ier", XLLF_IER_OFFSET},
459		{"tdfv", XLLF_TDFV_OFFSET},
460		{"rdfo", XLLF_RDFO_OFFSET},
461		{ /* Sentinel */ },
462	};
463	const struct axis_fifo_debug_reg *reg;
464	struct axis_fifo *fifo = m->private;
465
466	for (reg = regs; reg->name; ++reg) {
467		u32 val = ioread32(fifo->base_addr + reg->offset);
468
469		seq_printf(m, "%*s: 0x%08x\n", AXIS_FIFO_DEBUG_REG_NAME_MAX_LEN,
470			   reg->name, val);
471	}
472
473	return 0;
474}
475DEFINE_SHOW_ATTRIBUTE(axis_fifo_debugfs_regs);
476
477static void axis_fifo_debugfs_init(struct axis_fifo *fifo)
478{
479	fifo->debugfs_dir = debugfs_create_dir(dev_name(fifo->dt_device), NULL);
480
481	debugfs_create_file("regs", 0444, fifo->debugfs_dir, fifo,
482			    &axis_fifo_debugfs_regs_fops);
483}
484
485static int axis_fifo_parse_dt(struct axis_fifo *fifo)
486{
487	int ret;
488	unsigned int value;
489	struct device_node *node = fifo->dt_device->of_node;
490
491	ret = of_property_read_u32(node, "xlnx,axi-str-rxd-tdata-width",
492				   &value);
493	if (ret) {
494		dev_err(fifo->dt_device, "missing xlnx,axi-str-rxd-tdata-width property\n");
495		goto end;
496	} else if (value != 32) {
497		dev_err(fifo->dt_device, "xlnx,axi-str-rxd-tdata-width only supports 32 bits\n");
498		ret = -EIO;
499		goto end;
500	}
501
502	ret = of_property_read_u32(node, "xlnx,axi-str-txd-tdata-width",
503				   &value);
504	if (ret) {
505		dev_err(fifo->dt_device, "missing xlnx,axi-str-txd-tdata-width property\n");
506		goto end;
507	} else if (value != 32) {
508		dev_err(fifo->dt_device, "xlnx,axi-str-txd-tdata-width only supports 32 bits\n");
509		ret = -EIO;
510		goto end;
511	}
512
513	ret = of_property_read_u32(node, "xlnx,rx-fifo-depth",
514				   &fifo->rx_fifo_depth);
515	if (ret) {
516		dev_err(fifo->dt_device, "missing xlnx,rx-fifo-depth property\n");
517		ret = -EIO;
518		goto end;
519	}
520
521	ret = of_property_read_u32(node, "xlnx,tx-fifo-depth",
522				   &fifo->tx_fifo_depth);
523	if (ret) {
524		dev_err(fifo->dt_device, "missing xlnx,tx-fifo-depth property\n");
525		ret = -EIO;
526		goto end;
527	}
528
529	ret = of_property_read_u32(node, "xlnx,use-rx-data",
530				   &fifo->has_rx_fifo);
531	if (ret) {
532		dev_err(fifo->dt_device, "missing xlnx,use-rx-data property\n");
533		ret = -EIO;
534		goto end;
535	}
536
537	ret = of_property_read_u32(node, "xlnx,use-tx-data",
538				   &fifo->has_tx_fifo);
539	if (ret) {
540		dev_err(fifo->dt_device, "missing xlnx,use-tx-data property\n");
541		ret = -EIO;
542		goto end;
543	}
544
545end:
546	return ret;
547}
548
549static int axis_fifo_probe(struct platform_device *pdev)
550{
551	struct resource *r_mem; /* IO mem resources */
552	struct device *dev = &pdev->dev; /* OS device (from device tree) */
553	struct axis_fifo *fifo = NULL;
554	char *device_name;
555	int rc = 0; /* error return value */
556	int irq;
557
558	/* ----------------------------
559	 *     init wrapper device
560	 * ----------------------------
561	 */
562
563	device_name = devm_kzalloc(dev, 32, GFP_KERNEL);
564	if (!device_name)
565		return -ENOMEM;
566
567	/* allocate device wrapper memory */
568	fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL);
569	if (!fifo)
570		return -ENOMEM;
571
572	dev_set_drvdata(dev, fifo);
573	fifo->dt_device = dev;
574
575	init_waitqueue_head(&fifo->read_queue);
576	init_waitqueue_head(&fifo->write_queue);
577
578	mutex_init(&fifo->read_lock);
579	mutex_init(&fifo->write_lock);
580
581	/* ----------------------------
582	 *   init device memory space
583	 * ----------------------------
584	 */
585
586	/* get iospace for the device and request physical memory */
587	fifo->base_addr = devm_platform_get_and_ioremap_resource(pdev, 0, &r_mem);
588	if (IS_ERR(fifo->base_addr))
589		return PTR_ERR(fifo->base_addr);
590
591	/* ----------------------------
592	 *          init IP
593	 * ----------------------------
594	 */
595
596	rc = axis_fifo_parse_dt(fifo);
597	if (rc)
598		return rc;
599
600	reset_ip_core(fifo);
601
602	/* ----------------------------
603	 *    init device interrupts
604	 * ----------------------------
605	 */
606
607	/* get IRQ resource */
608	irq = platform_get_irq(pdev, 0);
609	if (irq < 0)
610		return irq;
611
612	/* request IRQ */
613	rc = devm_request_irq(fifo->dt_device, irq, &axis_fifo_irq, 0,
614			      DRIVER_NAME, fifo);
615	if (rc) {
616		dev_err(fifo->dt_device, "couldn't allocate interrupt %i\n",
617			irq);
618		return rc;
619	}
620
621	/* ----------------------------
622	 *      init char device
623	 * ----------------------------
624	 */
625	fifo->id = ida_alloc(&axis_fifo_ida, GFP_KERNEL);
626	if (fifo->id < 0)
627		return fifo->id;
628
629	snprintf(device_name, 32, "%s%d", DRIVER_NAME, fifo->id);
630
631	/* create character device */
632	fifo->miscdev.fops = &fops;
633	fifo->miscdev.minor = MISC_DYNAMIC_MINOR;
634	fifo->miscdev.name = device_name;
635	fifo->miscdev.parent = dev;
636	rc = misc_register(&fifo->miscdev);
637	if (rc < 0) {
638		ida_free(&axis_fifo_ida, fifo->id);
639		return rc;
640	}
641
642	axis_fifo_debugfs_init(fifo);
643
644	return 0;
645}
646
647static void axis_fifo_remove(struct platform_device *pdev)
648{
649	struct device *dev = &pdev->dev;
650	struct axis_fifo *fifo = dev_get_drvdata(dev);
651
652	debugfs_remove(fifo->debugfs_dir);
653	misc_deregister(&fifo->miscdev);
654	ida_free(&axis_fifo_ida, fifo->id);
655}
656
657static const struct of_device_id axis_fifo_of_match[] = {
658	{ .compatible = "xlnx,axi-fifo-mm-s-4.1", },
659	{ .compatible = "xlnx,axi-fifo-mm-s-4.2", },
660	{ .compatible = "xlnx,axi-fifo-mm-s-4.3", },
661	{},
662};
663MODULE_DEVICE_TABLE(of, axis_fifo_of_match);
664
665static struct platform_driver axis_fifo_driver = {
666	.driver = {
667		.name = DRIVER_NAME,
668		.of_match_table	= axis_fifo_of_match,
669	},
670	.probe		= axis_fifo_probe,
671	.remove		= axis_fifo_remove,
672};
673
674static int __init axis_fifo_init(void)
675{
676	if (read_timeout >= 0)
677		read_timeout = msecs_to_jiffies(read_timeout);
678	else
679		read_timeout = MAX_SCHEDULE_TIMEOUT;
680
681	if (write_timeout >= 0)
682		write_timeout = msecs_to_jiffies(write_timeout);
683	else
684		write_timeout = MAX_SCHEDULE_TIMEOUT;
685
686	pr_info("axis-fifo driver loaded with parameters read_timeout = %li, write_timeout = %li\n",
687		read_timeout, write_timeout);
688	return platform_driver_register(&axis_fifo_driver);
689}
690
691module_init(axis_fifo_init);
692
693static void __exit axis_fifo_exit(void)
694{
695	platform_driver_unregister(&axis_fifo_driver);
696	ida_destroy(&axis_fifo_ida);
697}
698
699module_exit(axis_fifo_exit);
700
701MODULE_LICENSE("GPL");
702MODULE_AUTHOR("Jacob Feder <jacobsfeder@gmail.com>");
703MODULE_DESCRIPTION("Xilinx AXI-Stream FIFO IP core driver");
~/ Read-only file preview.