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