brintos

brintos / linux-shallow public Read only

0
0
Text · 3.5 KiB · 48df719 Raw
144 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Sample fifo dma implementation4 *5 * Copyright (C) 2010 Stefani Seibold <stefani@seibold.net>6 */7 8#include <linux/init.h>9#include <linux/kfifo.h>10#include <linux/module.h>11#include <linux/scatterlist.h>12 13/*14 * This module shows how to handle fifo dma operations.15 */16 17/* fifo size in elements (bytes) */18#define FIFO_SIZE	3219 20static struct kfifo fifo;21 22static int __init example_init(void)23{24	int			i;25	unsigned int		ret;26	unsigned int		nents;27	struct scatterlist	sg[10];28 29	printk(KERN_INFO "DMA fifo test start\n");30 31	if (kfifo_alloc(&fifo, FIFO_SIZE, GFP_KERNEL)) {32		printk(KERN_WARNING "error kfifo_alloc\n");33		return -ENOMEM;34	}35 36	printk(KERN_INFO "queue size: %u\n", kfifo_size(&fifo));37 38	kfifo_in(&fifo, "test", 4);39 40	for (i = 0; i != 9; i++)41		kfifo_put(&fifo, i);42 43	/* kick away first byte */44	kfifo_skip(&fifo);45 46	printk(KERN_INFO "queue len: %u\n", kfifo_len(&fifo));47 48	/*49	 * Configure the kfifo buffer to receive data from DMA input.50	 *51	 *  .--------------------------------------.52	 *  | 0 | 1 | 2 | ... | 12 | 13 | ... | 31 |53	 *  |---|------------------|---------------|54	 *   \_/ \________________/ \_____________/55	 *    \          \                  \56	 *     \          \_allocated data   \57	 *      \_*free space*                \_*free space*58	 *59	 * We need two different SG entries: one for the free space area at the60	 * end of the kfifo buffer (19 bytes) and another for the first free61	 * byte at the beginning, after the kfifo_skip().62	 */63	sg_init_table(sg, ARRAY_SIZE(sg));64	nents = kfifo_dma_in_prepare(&fifo, sg, ARRAY_SIZE(sg), FIFO_SIZE);65	printk(KERN_INFO "DMA sgl entries: %d\n", nents);66	if (!nents) {67		/* fifo is full and no sgl was created */68		printk(KERN_WARNING "error kfifo_dma_in_prepare\n");69		return -EIO;70	}71 72	/* receive data */73	printk(KERN_INFO "scatterlist for receive:\n");74	for (i = 0; i < nents; i++) {75		printk(KERN_INFO76		"sg[%d] -> "77		"page %p offset 0x%.8x length 0x%.8x\n",78			i, sg_page(&sg[i]), sg[i].offset, sg[i].length);79 80		if (sg_is_last(&sg[i]))81			break;82	}83 84	/* put here your code to setup and exectute the dma operation */85	/* ... */86 87	/* example: zero bytes received */88	ret = 0;89 90	/* finish the dma operation and update the received data */91	kfifo_dma_in_finish(&fifo, ret);92 93	/* Prepare to transmit data, example: 8 bytes */94	nents = kfifo_dma_out_prepare(&fifo, sg, ARRAY_SIZE(sg), 8);95	printk(KERN_INFO "DMA sgl entries: %d\n", nents);96	if (!nents) {97		/* no data was available and no sgl was created */98		printk(KERN_WARNING "error kfifo_dma_out_prepare\n");99		return -EIO;100	}101 102	printk(KERN_INFO "scatterlist for transmit:\n");103	for (i = 0; i < nents; i++) {104		printk(KERN_INFO105		"sg[%d] -> "106		"page %p offset 0x%.8x length 0x%.8x\n",107			i, sg_page(&sg[i]), sg[i].offset, sg[i].length);108 109		if (sg_is_last(&sg[i]))110			break;111	}112 113	/* put here your code to setup and exectute the dma operation */114	/* ... */115 116	/* example: 5 bytes transmitted */117	ret = 5;118 119	/* finish the dma operation and update the transmitted data */120	kfifo_dma_out_finish(&fifo, ret);121 122	ret = kfifo_len(&fifo);123	printk(KERN_INFO "queue len: %u\n", kfifo_len(&fifo));124 125	if (ret != 7) {126		printk(KERN_WARNING "size mismatch: test failed");127		return -EIO;128	}129	printk(KERN_INFO "test passed\n");130 131	return 0;132}133 134static void __exit example_exit(void)135{136	kfifo_free(&fifo);137}138 139module_init(example_init);140module_exit(example_exit);141MODULE_DESCRIPTION("Sample fifo dma implementation");142MODULE_LICENSE("GPL");143MODULE_AUTHOR("Stefani Seibold <stefani@seibold.net>");144