xref: /openwifi/driver/side_ch/side_ch.c (revision 22dd0cc4861dbe973efee122229ab82ac3dd2c9a)
1*22dd0cc4SXianjun Jiao /*
2*22dd0cc4SXianjun Jiao  * openwifi side channel driver
3*22dd0cc4SXianjun Jiao  * Xianjun jiao. [email protected]; [email protected]
4*22dd0cc4SXianjun Jiao  */
5*22dd0cc4SXianjun Jiao 
6*22dd0cc4SXianjun Jiao #include <linux/bitops.h>
7*22dd0cc4SXianjun Jiao #include <linux/dmapool.h>
8*22dd0cc4SXianjun Jiao #include <linux/dma/xilinx_dma.h>
9*22dd0cc4SXianjun Jiao #include <linux/init.h>
10*22dd0cc4SXianjun Jiao #include <linux/interrupt.h>
11*22dd0cc4SXianjun Jiao #include <linux/io.h>
12*22dd0cc4SXianjun Jiao #include <linux/iopoll.h>
13*22dd0cc4SXianjun Jiao #include <linux/module.h>
14*22dd0cc4SXianjun Jiao #include <linux/of_address.h>
15*22dd0cc4SXianjun Jiao #include <linux/of_dma.h>
16*22dd0cc4SXianjun Jiao #include <linux/of_platform.h>
17*22dd0cc4SXianjun Jiao #include <linux/of_irq.h>
18*22dd0cc4SXianjun Jiao #include <linux/slab.h>
19*22dd0cc4SXianjun Jiao #include <linux/clk.h>
20*22dd0cc4SXianjun Jiao #include <linux/io-64-nonatomic-lo-hi.h>
21*22dd0cc4SXianjun Jiao #include <linux/delay.h>
22*22dd0cc4SXianjun Jiao #include <linux/dmaengine.h>
23*22dd0cc4SXianjun Jiao 
24*22dd0cc4SXianjun Jiao #include <net/sock.h>
25*22dd0cc4SXianjun Jiao #include <linux/netlink.h>
26*22dd0cc4SXianjun Jiao #include <linux/skbuff.h>
27*22dd0cc4SXianjun Jiao 
28*22dd0cc4SXianjun Jiao #include "side_ch.h"
29*22dd0cc4SXianjun Jiao 
30*22dd0cc4SXianjun Jiao static int num_eq_init = 8; // should be 0~8
31*22dd0cc4SXianjun Jiao 
32*22dd0cc4SXianjun Jiao module_param(num_eq_init, int, 0);
33*22dd0cc4SXianjun Jiao MODULE_PARM_DESC(num_eq_init, "num_eq_init. 0~8. number of equalizer output (52 each) appended to CSI");
34*22dd0cc4SXianjun Jiao 
35*22dd0cc4SXianjun Jiao static void __iomem *base_addr; // to store driver specific base address needed for mmu to translate virtual address to physical address in our FPGA design
36*22dd0cc4SXianjun Jiao 
37*22dd0cc4SXianjun Jiao struct dma_chan *chan_to_pl = NULL;
38*22dd0cc4SXianjun Jiao struct dma_chan *chan_to_ps = NULL;
39*22dd0cc4SXianjun Jiao u8 *side_info_buf = NULL;
40*22dd0cc4SXianjun Jiao dma_cookie_t chan_to_ps_cookie;
41*22dd0cc4SXianjun Jiao const int max_side_info_buf_size = MAX_NUM_DMA_SYMBOL*8;
42*22dd0cc4SXianjun Jiao 
43*22dd0cc4SXianjun Jiao /* IO accessors */
44*22dd0cc4SXianjun Jiao static inline u32 reg_read(u32 reg)
45*22dd0cc4SXianjun Jiao {
46*22dd0cc4SXianjun Jiao 	return ioread32(base_addr + reg);
47*22dd0cc4SXianjun Jiao }
48*22dd0cc4SXianjun Jiao 
49*22dd0cc4SXianjun Jiao static inline void reg_write(u32 reg, u32 value)
50*22dd0cc4SXianjun Jiao {
51*22dd0cc4SXianjun Jiao 	iowrite32(value, base_addr + reg);
52*22dd0cc4SXianjun Jiao }
53*22dd0cc4SXianjun Jiao 
54*22dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_MULTI_RST_write(u32 Data) {
55*22dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_MULTI_RST_ADDR, Data);
56*22dd0cc4SXianjun Jiao }
57*22dd0cc4SXianjun Jiao 
58*22dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_CONFIG_read(void){
59*22dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_CONFIG_ADDR);
60*22dd0cc4SXianjun Jiao }
61*22dd0cc4SXianjun Jiao 
62*22dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_CONFIG_write(u32 value){
63*22dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_CONFIG_ADDR, value);
64*22dd0cc4SXianjun Jiao }
65*22dd0cc4SXianjun Jiao 
66*22dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_NUM_DMA_SYMBOL_read(void){
67*22dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_NUM_DMA_SYMBOL_ADDR);
68*22dd0cc4SXianjun Jiao }
69*22dd0cc4SXianjun Jiao 
70*22dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_NUM_DMA_SYMBOL_write(u32 value){
71*22dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_NUM_DMA_SYMBOL_ADDR, value);
72*22dd0cc4SXianjun Jiao }
73*22dd0cc4SXianjun Jiao 
74*22dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_START_DMA_TO_PS_read(void){
75*22dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_START_DMA_TO_PS_ADDR);
76*22dd0cc4SXianjun Jiao }
77*22dd0cc4SXianjun Jiao 
78*22dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_START_DMA_TO_PS_write(u32 value){
79*22dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_START_DMA_TO_PS_ADDR, value);
80*22dd0cc4SXianjun Jiao }
81*22dd0cc4SXianjun Jiao 
82*22dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_NUM_EQ_read(void){
83*22dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_NUM_EQ_ADDR);
84*22dd0cc4SXianjun Jiao }
85*22dd0cc4SXianjun Jiao 
86*22dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_NUM_EQ_write(u32 value){
87*22dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_NUM_EQ_ADDR, value);
88*22dd0cc4SXianjun Jiao }
89*22dd0cc4SXianjun Jiao 
90*22dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_FC_TARGET_read(void){
91*22dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_FC_TARGET_ADDR);
92*22dd0cc4SXianjun Jiao }
93*22dd0cc4SXianjun Jiao 
94*22dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_FC_TARGET_write(u32 value){
95*22dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_FC_TARGET_ADDR, value);
96*22dd0cc4SXianjun Jiao }
97*22dd0cc4SXianjun Jiao 
98*22dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_ADDR1_TARGET_read(void){
99*22dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_ADDR1_TARGET_ADDR);
100*22dd0cc4SXianjun Jiao }
101*22dd0cc4SXianjun Jiao 
102*22dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_ADDR1_TARGET_write(u32 value){
103*22dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_ADDR1_TARGET_ADDR, value);
104*22dd0cc4SXianjun Jiao }
105*22dd0cc4SXianjun Jiao 
106*22dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_ADDR2_TARGET_read(void){
107*22dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_ADDR2_TARGET_ADDR);
108*22dd0cc4SXianjun Jiao }
109*22dd0cc4SXianjun Jiao 
110*22dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_ADDR2_TARGET_write(u32 value){
111*22dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_ADDR2_TARGET_ADDR, value);
112*22dd0cc4SXianjun Jiao }
113*22dd0cc4SXianjun Jiao 
114*22dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_M_AXIS_DATA_COUNT_read(void){
115*22dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_M_AXIS_DATA_COUNT_ADDR);
116*22dd0cc4SXianjun Jiao }
117*22dd0cc4SXianjun Jiao 
118*22dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_M_AXIS_DATA_COUNT_write(u32 value){
119*22dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_M_AXIS_DATA_COUNT_ADDR, value);
120*22dd0cc4SXianjun Jiao }
121*22dd0cc4SXianjun Jiao 
122*22dd0cc4SXianjun Jiao static const struct of_device_id dev_of_ids[] = {
123*22dd0cc4SXianjun Jiao 	{ .compatible = "sdr,side_ch", },
124*22dd0cc4SXianjun Jiao 	{}
125*22dd0cc4SXianjun Jiao };
126*22dd0cc4SXianjun Jiao MODULE_DEVICE_TABLE(of, dev_of_ids);
127*22dd0cc4SXianjun Jiao 
128*22dd0cc4SXianjun Jiao static void chan_to_ps_callback(void *completion)
129*22dd0cc4SXianjun Jiao {
130*22dd0cc4SXianjun Jiao 	complete(completion);
131*22dd0cc4SXianjun Jiao }
132*22dd0cc4SXianjun Jiao 
133*22dd0cc4SXianjun Jiao #if 0
134*22dd0cc4SXianjun Jiao static void chan_to_pl_callback(void *completion)
135*22dd0cc4SXianjun Jiao {
136*22dd0cc4SXianjun Jiao 	complete(completion);
137*22dd0cc4SXianjun Jiao }
138*22dd0cc4SXianjun Jiao 
139*22dd0cc4SXianjun Jiao static int dma_loopback_test(int num_test, int num_dma_symbol) {
140*22dd0cc4SXianjun Jiao 	int i, err = 0;
141*22dd0cc4SXianjun Jiao 
142*22dd0cc4SXianjun Jiao 	// -----------dma loop back test-------------------------
143*22dd0cc4SXianjun Jiao 	enum dma_status status;
144*22dd0cc4SXianjun Jiao 	enum dma_ctrl_flags flags;
145*22dd0cc4SXianjun Jiao 	u8 *src_buf, *dst_buf;
146*22dd0cc4SXianjun Jiao 	// int num_dma_symbol = 16;
147*22dd0cc4SXianjun Jiao 	int test_buf_size = num_dma_symbol*8;
148*22dd0cc4SXianjun Jiao 	dma_addr_t src_buf_dma;
149*22dd0cc4SXianjun Jiao 	dma_addr_t dst_buf_dma;
150*22dd0cc4SXianjun Jiao 	struct dma_device *chan_to_pl_dev = chan_to_pl->device;
151*22dd0cc4SXianjun Jiao 	struct dma_device *chan_to_ps_dev = chan_to_ps->device;
152*22dd0cc4SXianjun Jiao 	struct scatterlist chan_to_pl_sg[1];
153*22dd0cc4SXianjun Jiao 	struct scatterlist chan_to_ps_sg[1];
154*22dd0cc4SXianjun Jiao 	dma_cookie_t chan_to_pl_cookie;
155*22dd0cc4SXianjun Jiao 	dma_cookie_t chan_to_ps_cookie;
156*22dd0cc4SXianjun Jiao 	struct completion chan_to_pl_cmp;
157*22dd0cc4SXianjun Jiao 	struct completion chan_to_ps_cmp;
158*22dd0cc4SXianjun Jiao 	struct dma_async_tx_descriptor *chan_to_pl_d = NULL;
159*22dd0cc4SXianjun Jiao 	struct dma_async_tx_descriptor *chan_to_ps_d = NULL;
160*22dd0cc4SXianjun Jiao 	unsigned long chan_to_ps_tmo =	msecs_to_jiffies(300000);
161*22dd0cc4SXianjun Jiao 	unsigned long chan_to_pl_tmo =  msecs_to_jiffies(30000);
162*22dd0cc4SXianjun Jiao 	int test_idx;
163*22dd0cc4SXianjun Jiao 
164*22dd0cc4SXianjun Jiao 	for (test_idx=0; test_idx<num_test; test_idx++) {
165*22dd0cc4SXianjun Jiao 		printk("%s test_idx %d\n", side_ch_compatible_str, test_idx);
166*22dd0cc4SXianjun Jiao 		//set number of dma symbols expected to pl and ps
167*22dd0cc4SXianjun Jiao 		SIDE_CH_REG_NUM_DMA_SYMBOL_write((num_dma_symbol<<16)|num_dma_symbol);
168*22dd0cc4SXianjun Jiao 
169*22dd0cc4SXianjun Jiao 		src_buf = kmalloc(test_buf_size, GFP_KERNEL);
170*22dd0cc4SXianjun Jiao 		if (!src_buf)
171*22dd0cc4SXianjun Jiao 			goto err_src_buf;
172*22dd0cc4SXianjun Jiao 
173*22dd0cc4SXianjun Jiao 		dst_buf = kmalloc(test_buf_size, GFP_KERNEL);
174*22dd0cc4SXianjun Jiao 		if (!dst_buf)
175*22dd0cc4SXianjun Jiao 			goto err_dst_buf;
176*22dd0cc4SXianjun Jiao 
177*22dd0cc4SXianjun Jiao 		// test buf init
178*22dd0cc4SXianjun Jiao 		for (i=0; i<test_buf_size; i++) {
179*22dd0cc4SXianjun Jiao 			src_buf[i] = (test_idx+test_buf_size-i-1);
180*22dd0cc4SXianjun Jiao 			dst_buf[i] = 0;
181*22dd0cc4SXianjun Jiao 		}
182*22dd0cc4SXianjun Jiao 
183*22dd0cc4SXianjun Jiao 		set_user_nice(current, 10);
184*22dd0cc4SXianjun Jiao 		flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
185*22dd0cc4SXianjun Jiao 
186*22dd0cc4SXianjun Jiao 		src_buf_dma = dma_map_single(chan_to_pl_dev->dev, src_buf, test_buf_size, DMA_MEM_TO_DEV);
187*22dd0cc4SXianjun Jiao 		if (dma_mapping_error(chan_to_pl_dev->dev, src_buf_dma)) {
188*22dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test WARNING chan_to_pl_dev DMA mapping error\n", side_ch_compatible_str);
189*22dd0cc4SXianjun Jiao 			goto err_src_buf_dma_mapping;
190*22dd0cc4SXianjun Jiao 		}
191*22dd0cc4SXianjun Jiao 
192*22dd0cc4SXianjun Jiao 		dst_buf_dma = dma_map_single(chan_to_ps_dev->dev, dst_buf, test_buf_size, DMA_DEV_TO_MEM);
193*22dd0cc4SXianjun Jiao 		if (dma_mapping_error(chan_to_ps_dev->dev, dst_buf_dma)) {
194*22dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test WARNING chan_to_ps_dev DMA mapping error\n", side_ch_compatible_str);
195*22dd0cc4SXianjun Jiao 			goto err_dst_buf_dma_mapping;
196*22dd0cc4SXianjun Jiao 		}
197*22dd0cc4SXianjun Jiao 
198*22dd0cc4SXianjun Jiao 		sg_init_table(chan_to_ps_sg, 1);
199*22dd0cc4SXianjun Jiao 		sg_init_table(chan_to_pl_sg, 1);
200*22dd0cc4SXianjun Jiao 
201*22dd0cc4SXianjun Jiao 		sg_dma_address(&chan_to_ps_sg[0]) = dst_buf_dma;
202*22dd0cc4SXianjun Jiao 		sg_dma_address(&chan_to_pl_sg[0]) = src_buf_dma;
203*22dd0cc4SXianjun Jiao 
204*22dd0cc4SXianjun Jiao 		sg_dma_len(&chan_to_ps_sg[0]) = test_buf_size;
205*22dd0cc4SXianjun Jiao 		sg_dma_len(&chan_to_pl_sg[0]) = test_buf_size;
206*22dd0cc4SXianjun Jiao 
207*22dd0cc4SXianjun Jiao 		chan_to_ps_d = chan_to_ps_dev->device_prep_slave_sg(chan_to_ps, chan_to_ps_sg, 1, DMA_DEV_TO_MEM, flags, NULL);
208*22dd0cc4SXianjun Jiao 		chan_to_pl_d = chan_to_pl_dev->device_prep_slave_sg(chan_to_pl, chan_to_pl_sg, 1, DMA_MEM_TO_DEV, flags, NULL);
209*22dd0cc4SXianjun Jiao 
210*22dd0cc4SXianjun Jiao 		if (!chan_to_ps_d || !chan_to_pl_d) {
211*22dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test WARNING !chan_to_ps_d || !chan_to_pl_d\n", side_ch_compatible_str);
212*22dd0cc4SXianjun Jiao 			goto err_dst_buf_with_unmap;
213*22dd0cc4SXianjun Jiao 		}
214*22dd0cc4SXianjun Jiao 
215*22dd0cc4SXianjun Jiao 		init_completion(&chan_to_pl_cmp);
216*22dd0cc4SXianjun Jiao 		chan_to_pl_d->callback = chan_to_pl_callback;
217*22dd0cc4SXianjun Jiao 		chan_to_pl_d->callback_param = &chan_to_pl_cmp;
218*22dd0cc4SXianjun Jiao 		chan_to_pl_cookie = chan_to_pl_d->tx_submit(chan_to_pl_d);
219*22dd0cc4SXianjun Jiao 
220*22dd0cc4SXianjun Jiao 		init_completion(&chan_to_ps_cmp);
221*22dd0cc4SXianjun Jiao 		chan_to_ps_d->callback = chan_to_ps_callback;
222*22dd0cc4SXianjun Jiao 		chan_to_ps_d->callback_param = &chan_to_ps_cmp;
223*22dd0cc4SXianjun Jiao 		chan_to_ps_cookie = chan_to_ps_d->tx_submit(chan_to_ps_d);
224*22dd0cc4SXianjun Jiao 
225*22dd0cc4SXianjun Jiao 		if (dma_submit_error(chan_to_pl_cookie) ||	dma_submit_error(chan_to_ps_cookie)) {
226*22dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test WARNING dma_submit_error\n", side_ch_compatible_str);
227*22dd0cc4SXianjun Jiao 			goto err_dst_buf_with_unmap;
228*22dd0cc4SXianjun Jiao 		}
229*22dd0cc4SXianjun Jiao 
230*22dd0cc4SXianjun Jiao 		dma_async_issue_pending(chan_to_pl);
231*22dd0cc4SXianjun Jiao 		dma_async_issue_pending(chan_to_ps);
232*22dd0cc4SXianjun Jiao 
233*22dd0cc4SXianjun Jiao 		chan_to_pl_tmo = wait_for_completion_timeout(&chan_to_pl_cmp, chan_to_pl_tmo);
234*22dd0cc4SXianjun Jiao 
235*22dd0cc4SXianjun Jiao 		status = dma_async_is_tx_complete(chan_to_pl, chan_to_pl_cookie, NULL, NULL);
236*22dd0cc4SXianjun Jiao 		if (chan_to_pl_tmo == 0) {
237*22dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test chan_to_pl_tmo == 0\n", side_ch_compatible_str);
238*22dd0cc4SXianjun Jiao 			goto err_dst_buf_with_unmap;
239*22dd0cc4SXianjun Jiao 		} else if (status != DMA_COMPLETE) {
240*22dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test chan_to_pl status != DMA_COMPLETE\n", side_ch_compatible_str);
241*22dd0cc4SXianjun Jiao 			goto err_dst_buf_with_unmap;
242*22dd0cc4SXianjun Jiao 		}
243*22dd0cc4SXianjun Jiao 
244*22dd0cc4SXianjun Jiao 		chan_to_ps_tmo = wait_for_completion_timeout(&chan_to_ps_cmp, chan_to_ps_tmo);
245*22dd0cc4SXianjun Jiao 		status = dma_async_is_tx_complete(chan_to_ps, chan_to_ps_cookie, NULL, NULL);
246*22dd0cc4SXianjun Jiao 		if (chan_to_ps_tmo == 0) {
247*22dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test chan_to_ps_tmo == 0\n", side_ch_compatible_str);
248*22dd0cc4SXianjun Jiao 			goto err_dst_buf_with_unmap;
249*22dd0cc4SXianjun Jiao 		} else if (status != DMA_COMPLETE) {
250*22dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test chan_to_ps status != DMA_COMPLETE\n", side_ch_compatible_str);
251*22dd0cc4SXianjun Jiao 			goto err_dst_buf_with_unmap;
252*22dd0cc4SXianjun Jiao 		}
253*22dd0cc4SXianjun Jiao 
254*22dd0cc4SXianjun Jiao 		dma_unmap_single(chan_to_pl_dev->dev, src_buf_dma, test_buf_size, DMA_MEM_TO_DEV);
255*22dd0cc4SXianjun Jiao 		dma_unmap_single(chan_to_ps_dev->dev, dst_buf_dma, test_buf_size, DMA_DEV_TO_MEM);
256*22dd0cc4SXianjun Jiao 
257*22dd0cc4SXianjun Jiao 		// test buf verification
258*22dd0cc4SXianjun Jiao 		for (i=0; i<test_buf_size; i++) {
259*22dd0cc4SXianjun Jiao 			//printk("%d ", dst_buf[i]);
260*22dd0cc4SXianjun Jiao 			if ( dst_buf[i] != ((test_idx+test_buf_size-i-1)%256) )
261*22dd0cc4SXianjun Jiao 				break;
262*22dd0cc4SXianjun Jiao 		}
263*22dd0cc4SXianjun Jiao 		printk("\n");
264*22dd0cc4SXianjun Jiao 		printk("%s dma_loopback_test buf verification end idx %d (test_buf_size %d)\n", side_ch_compatible_str, i, test_buf_size);
265*22dd0cc4SXianjun Jiao 
266*22dd0cc4SXianjun Jiao 		kfree(src_buf);
267*22dd0cc4SXianjun Jiao 		kfree(dst_buf);
268*22dd0cc4SXianjun Jiao 	}
269*22dd0cc4SXianjun Jiao 
270*22dd0cc4SXianjun Jiao 	printk("%s dma_loopback_test err %d\n", side_ch_compatible_str, err);
271*22dd0cc4SXianjun Jiao 	return(err);
272*22dd0cc4SXianjun Jiao 
273*22dd0cc4SXianjun Jiao err_dst_buf_with_unmap:
274*22dd0cc4SXianjun Jiao 	dma_unmap_single(chan_to_ps_dev->dev, dst_buf_dma, test_buf_size, DMA_DEV_TO_MEM);
275*22dd0cc4SXianjun Jiao 
276*22dd0cc4SXianjun Jiao err_dst_buf_dma_mapping:
277*22dd0cc4SXianjun Jiao 	dma_unmap_single(chan_to_pl_dev->dev, src_buf_dma, test_buf_size, DMA_MEM_TO_DEV);
278*22dd0cc4SXianjun Jiao 
279*22dd0cc4SXianjun Jiao err_src_buf_dma_mapping:
280*22dd0cc4SXianjun Jiao 
281*22dd0cc4SXianjun Jiao err_dst_buf:
282*22dd0cc4SXianjun Jiao 	err = -4;
283*22dd0cc4SXianjun Jiao 	kfree((void*)dst_buf);
284*22dd0cc4SXianjun Jiao 
285*22dd0cc4SXianjun Jiao err_src_buf:
286*22dd0cc4SXianjun Jiao 	err = -3;
287*22dd0cc4SXianjun Jiao 	kfree(src_buf);
288*22dd0cc4SXianjun Jiao 
289*22dd0cc4SXianjun Jiao 	return(err);
290*22dd0cc4SXianjun Jiao }
291*22dd0cc4SXianjun Jiao #endif
292*22dd0cc4SXianjun Jiao 
293*22dd0cc4SXianjun Jiao static int init_side_channel(void) {
294*22dd0cc4SXianjun Jiao 	side_info_buf = kmalloc(max_side_info_buf_size, GFP_KERNEL);
295*22dd0cc4SXianjun Jiao 	if (!side_info_buf)
296*22dd0cc4SXianjun Jiao 		return(-1);
297*22dd0cc4SXianjun Jiao 
298*22dd0cc4SXianjun Jiao 	return(0);
299*22dd0cc4SXianjun Jiao }
300*22dd0cc4SXianjun Jiao 
301*22dd0cc4SXianjun Jiao static int get_side_info(int num_eq) {
302*22dd0cc4SXianjun Jiao 	// int err = 0;//, i;
303*22dd0cc4SXianjun Jiao 	struct scatterlist chan_to_ps_sg[1];
304*22dd0cc4SXianjun Jiao 	enum dma_status status;
305*22dd0cc4SXianjun Jiao 	enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
306*22dd0cc4SXianjun Jiao 	int num_dma_symbol, num_dma_symbol_per_trans, side_info_buf_size;
307*22dd0cc4SXianjun Jiao 	dma_addr_t side_info_buf_dma;
308*22dd0cc4SXianjun Jiao 	struct dma_device *chan_to_ps_dev = chan_to_ps->device;
309*22dd0cc4SXianjun Jiao 	struct completion chan_to_ps_cmp;
310*22dd0cc4SXianjun Jiao 	struct dma_async_tx_descriptor *chan_to_ps_d = NULL;
311*22dd0cc4SXianjun Jiao 	unsigned long chan_to_ps_tmo =	msecs_to_jiffies(100);
312*22dd0cc4SXianjun Jiao 
313*22dd0cc4SXianjun Jiao 	if (side_info_buf==NULL) {
314*22dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING side_info_buf==NULL\n", side_ch_compatible_str);
315*22dd0cc4SXianjun Jiao 		return(-1);
316*22dd0cc4SXianjun Jiao 	}
317*22dd0cc4SXianjun Jiao 
318*22dd0cc4SXianjun Jiao 	status = dma_async_is_tx_complete(chan_to_ps, chan_to_ps_cookie, NULL, NULL);
319*22dd0cc4SXianjun Jiao 	if (status!=DMA_COMPLETE) {
320*22dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING status!=DMA_COMPLETE\n", side_ch_compatible_str);
321*22dd0cc4SXianjun Jiao 		return(-1);
322*22dd0cc4SXianjun Jiao 	}
323*22dd0cc4SXianjun Jiao 
324*22dd0cc4SXianjun Jiao 	set_user_nice(current, 10);
325*22dd0cc4SXianjun Jiao 
326*22dd0cc4SXianjun Jiao 	num_dma_symbol_per_trans = HEADER_LEN + CSI_LEN + num_eq*EQUALIZER_LEN;
327*22dd0cc4SXianjun Jiao 	//set number of dma symbols expected to ps
328*22dd0cc4SXianjun Jiao 	num_dma_symbol = SIDE_CH_REG_M_AXIS_DATA_COUNT_read();
329*22dd0cc4SXianjun Jiao 	printk("%s get_side_info m axis data count %d per trans %d\n", side_ch_compatible_str, num_dma_symbol, num_dma_symbol_per_trans);
330*22dd0cc4SXianjun Jiao 	num_dma_symbol = num_dma_symbol_per_trans*(num_dma_symbol/num_dma_symbol_per_trans);
331*22dd0cc4SXianjun Jiao 	printk("%s get_side_info actual num dma symbol %d\n", side_ch_compatible_str, num_dma_symbol);
332*22dd0cc4SXianjun Jiao 	if (num_dma_symbol == 0)
333*22dd0cc4SXianjun Jiao 		return(-2);
334*22dd0cc4SXianjun Jiao 
335*22dd0cc4SXianjun Jiao 	side_info_buf_size = num_dma_symbol*8;
336*22dd0cc4SXianjun Jiao 	side_info_buf_dma = dma_map_single(chan_to_ps_dev->dev, side_info_buf, side_info_buf_size, DMA_DEV_TO_MEM);
337*22dd0cc4SXianjun Jiao 	if (dma_mapping_error(chan_to_ps_dev->dev, side_info_buf_dma)) {
338*22dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING chan_to_ps_dev DMA mapping error\n", side_ch_compatible_str);
339*22dd0cc4SXianjun Jiao 		return(-3);
340*22dd0cc4SXianjun Jiao 	}
341*22dd0cc4SXianjun Jiao 
342*22dd0cc4SXianjun Jiao 	sg_init_table(chan_to_ps_sg, 1);
343*22dd0cc4SXianjun Jiao 	sg_dma_address(&chan_to_ps_sg[0]) = side_info_buf_dma;
344*22dd0cc4SXianjun Jiao 	sg_dma_len(&chan_to_ps_sg[0]) = side_info_buf_size;
345*22dd0cc4SXianjun Jiao 
346*22dd0cc4SXianjun Jiao 	chan_to_ps_d = chan_to_ps_dev->device_prep_slave_sg(chan_to_ps, chan_to_ps_sg, 1, DMA_DEV_TO_MEM, flags, NULL);
347*22dd0cc4SXianjun Jiao 	if (!chan_to_ps_d) {
348*22dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING !chan_to_ps_d\n", side_ch_compatible_str);
349*22dd0cc4SXianjun Jiao 		goto err_dst_buf_with_unmap;
350*22dd0cc4SXianjun Jiao 	}
351*22dd0cc4SXianjun Jiao 
352*22dd0cc4SXianjun Jiao 	init_completion(&chan_to_ps_cmp);
353*22dd0cc4SXianjun Jiao 	chan_to_ps_d->callback = chan_to_ps_callback;
354*22dd0cc4SXianjun Jiao 	chan_to_ps_d->callback_param = &chan_to_ps_cmp;
355*22dd0cc4SXianjun Jiao 
356*22dd0cc4SXianjun Jiao 	chan_to_ps_cookie = chan_to_ps_d->tx_submit(chan_to_ps_d);
357*22dd0cc4SXianjun Jiao 	if (dma_submit_error(chan_to_ps_cookie)) {
358*22dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING dma_submit_error\n", side_ch_compatible_str);
359*22dd0cc4SXianjun Jiao 		goto err_dst_buf_with_unmap;
360*22dd0cc4SXianjun Jiao 	}
361*22dd0cc4SXianjun Jiao 
362*22dd0cc4SXianjun Jiao 	SIDE_CH_REG_NUM_DMA_SYMBOL_write(num_dma_symbol); //dma from fpga will start automatically
363*22dd0cc4SXianjun Jiao 
364*22dd0cc4SXianjun Jiao 	dma_async_issue_pending(chan_to_ps);
365*22dd0cc4SXianjun Jiao 
366*22dd0cc4SXianjun Jiao 	chan_to_ps_tmo = wait_for_completion_timeout(&chan_to_ps_cmp, chan_to_ps_tmo);
367*22dd0cc4SXianjun Jiao 	status = dma_async_is_tx_complete(chan_to_ps, chan_to_ps_cookie, NULL, NULL);
368*22dd0cc4SXianjun Jiao 	if (chan_to_ps_tmo == 0) {
369*22dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING chan_to_ps_tmo == 0\n", side_ch_compatible_str);
370*22dd0cc4SXianjun Jiao 		goto err_dst_buf_with_unmap;
371*22dd0cc4SXianjun Jiao 	} else if (status != DMA_COMPLETE) {
372*22dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING chan_to_ps status != DMA_COMPLETE\n", side_ch_compatible_str);
373*22dd0cc4SXianjun Jiao 		goto err_dst_buf_with_unmap;
374*22dd0cc4SXianjun Jiao 	}
375*22dd0cc4SXianjun Jiao 
376*22dd0cc4SXianjun Jiao 	dma_unmap_single(chan_to_ps_dev->dev, side_info_buf_dma, side_info_buf_size, DMA_DEV_TO_MEM);
377*22dd0cc4SXianjun Jiao 	return(side_info_buf_size);
378*22dd0cc4SXianjun Jiao 
379*22dd0cc4SXianjun Jiao err_dst_buf_with_unmap:
380*22dd0cc4SXianjun Jiao 	dma_unmap_single(chan_to_ps_dev->dev, side_info_buf_dma, side_info_buf_size, DMA_DEV_TO_MEM);
381*22dd0cc4SXianjun Jiao 	return(-100);
382*22dd0cc4SXianjun Jiao }
383*22dd0cc4SXianjun Jiao 
384*22dd0cc4SXianjun Jiao // -----------------netlink recv and send-----------------
385*22dd0cc4SXianjun Jiao // should align with side_ch_ctl.c in user_space
386*22dd0cc4SXianjun Jiao #define ACTION_INVALID       0
387*22dd0cc4SXianjun Jiao #define ACTION_REG_WRITE     1
388*22dd0cc4SXianjun Jiao #define ACTION_REG_READ      2
389*22dd0cc4SXianjun Jiao #define ACTION_SIDE_INFO_GET 3
390*22dd0cc4SXianjun Jiao 
391*22dd0cc4SXianjun Jiao #define REG_TYPE_INVALID     0
392*22dd0cc4SXianjun Jiao #define REG_TYPE_HARDWARE    1
393*22dd0cc4SXianjun Jiao #define REG_TYPE_SOFTWARE    2
394*22dd0cc4SXianjun Jiao 
395*22dd0cc4SXianjun Jiao // #define NETLINK_USER 31
396*22dd0cc4SXianjun Jiao struct sock *nl_sk = NULL;
397*22dd0cc4SXianjun Jiao static void side_ch_nl_recv_msg(struct sk_buff *skb) {
398*22dd0cc4SXianjun Jiao 	struct nlmsghdr *nlh;
399*22dd0cc4SXianjun Jiao 	int pid;
400*22dd0cc4SXianjun Jiao 	struct sk_buff *skb_out;
401*22dd0cc4SXianjun Jiao 	int msg_size;
402*22dd0cc4SXianjun Jiao 	int *msg=(int*)side_info_buf;
403*22dd0cc4SXianjun Jiao 	int action_flag, reg_type, reg_idx;
404*22dd0cc4SXianjun Jiao 	u32 reg_val, *cmd_buf;
405*22dd0cc4SXianjun Jiao 	int res;
406*22dd0cc4SXianjun Jiao 
407*22dd0cc4SXianjun Jiao 	// printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
408*22dd0cc4SXianjun Jiao 
409*22dd0cc4SXianjun Jiao 	// msg_size=strlen(msg);
410*22dd0cc4SXianjun Jiao 
411*22dd0cc4SXianjun Jiao 	nlh=(struct nlmsghdr*)skb->data;
412*22dd0cc4SXianjun Jiao 	cmd_buf = (u32*)nlmsg_data(nlh);
413*22dd0cc4SXianjun Jiao 	// printk(KERN_INFO "Netlink received msg payload:%s\n",(char*)nlmsg_data(nlh));
414*22dd0cc4SXianjun Jiao 	action_flag = cmd_buf[0];
415*22dd0cc4SXianjun Jiao     reg_type = cmd_buf[1];
416*22dd0cc4SXianjun Jiao     reg_idx = cmd_buf[2];
417*22dd0cc4SXianjun Jiao     reg_val = cmd_buf[3];
418*22dd0cc4SXianjun Jiao 	printk("%s recv msg: len %d action_flag %d reg_type %d reg_idx %d reg_val %u\n", side_ch_compatible_str, nlmsg_len(nlh), action_flag, reg_type, reg_idx, reg_val);
419*22dd0cc4SXianjun Jiao 
420*22dd0cc4SXianjun Jiao 	pid = nlh->nlmsg_pid; /*pid of sending process */
421*22dd0cc4SXianjun Jiao 
422*22dd0cc4SXianjun Jiao 	if (action_flag==ACTION_SIDE_INFO_GET) {
423*22dd0cc4SXianjun Jiao 		res = get_side_info(num_eq_init);
424*22dd0cc4SXianjun Jiao 		printk(KERN_INFO "%s recv msg: get_side_info(%d) res %d\n", side_ch_compatible_str, num_eq_init, res);
425*22dd0cc4SXianjun Jiao 		if (res>0) {
426*22dd0cc4SXianjun Jiao 			msg_size = res;
427*22dd0cc4SXianjun Jiao 			// printk("%s recv msg: %d %d %d %d %d %d %d %d\n", side_ch_compatible_str, msg[0], msg[1], msg[2], msg[3], msg[4], msg[5], msg[6], msg[7]);
428*22dd0cc4SXianjun Jiao 		} else {
429*22dd0cc4SXianjun Jiao 			msg_size = 4;
430*22dd0cc4SXianjun Jiao 			msg[0] = -2;
431*22dd0cc4SXianjun Jiao 		}
432*22dd0cc4SXianjun Jiao 	} else if (action_flag==ACTION_REG_READ) {
433*22dd0cc4SXianjun Jiao 		msg_size = 4;
434*22dd0cc4SXianjun Jiao 		// if (reg_idx<0 || reg_idx>31) {
435*22dd0cc4SXianjun Jiao 		// 	msg[0] = -3;
436*22dd0cc4SXianjun Jiao 		// 	printk("%s recv msg: invalid reg_idx\n", side_ch_compatible_str);
437*22dd0cc4SXianjun Jiao 		// } else {
438*22dd0cc4SXianjun Jiao 			msg[0] = reg_read(reg_idx*4);
439*22dd0cc4SXianjun Jiao 		// }
440*22dd0cc4SXianjun Jiao 	} else if (action_flag==ACTION_REG_WRITE) {
441*22dd0cc4SXianjun Jiao 		msg_size = 4;
442*22dd0cc4SXianjun Jiao 		// if (reg_idx<0 || reg_idx>31) {
443*22dd0cc4SXianjun Jiao 		// 	msg[0] = -4;
444*22dd0cc4SXianjun Jiao 		// 	printk("%s recv msg: invalid reg_idx\n", side_ch_compatible_str);
445*22dd0cc4SXianjun Jiao 		// } else {
446*22dd0cc4SXianjun Jiao 			msg[0] = 0;
447*22dd0cc4SXianjun Jiao 			reg_write(reg_idx*4, reg_val);
448*22dd0cc4SXianjun Jiao 		// }
449*22dd0cc4SXianjun Jiao 	} else {
450*22dd0cc4SXianjun Jiao 		msg_size = 4;
451*22dd0cc4SXianjun Jiao 		msg[0] = -1;
452*22dd0cc4SXianjun Jiao 		printk("%s recv msg: invalid action_flag\n", side_ch_compatible_str);
453*22dd0cc4SXianjun Jiao 	}
454*22dd0cc4SXianjun Jiao 
455*22dd0cc4SXianjun Jiao 	skb_out = nlmsg_new(msg_size,0);
456*22dd0cc4SXianjun Jiao 	if(!skb_out)
457*22dd0cc4SXianjun Jiao 	{
458*22dd0cc4SXianjun Jiao 		printk(KERN_ERR "Failed to allocate new skb\n");
459*22dd0cc4SXianjun Jiao 		return;
460*22dd0cc4SXianjun Jiao 	}
461*22dd0cc4SXianjun Jiao 	nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0);
462*22dd0cc4SXianjun Jiao 	NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
463*22dd0cc4SXianjun Jiao 
464*22dd0cc4SXianjun Jiao 	memcpy(nlmsg_data(nlh),msg,msg_size);
465*22dd0cc4SXianjun Jiao 
466*22dd0cc4SXianjun Jiao 	res=nlmsg_unicast(nl_sk,skb_out,pid);
467*22dd0cc4SXianjun Jiao 
468*22dd0cc4SXianjun Jiao 	if(res<0)
469*22dd0cc4SXianjun Jiao 		printk(KERN_INFO "Error while sending bak to user\n");
470*22dd0cc4SXianjun Jiao }
471*22dd0cc4SXianjun Jiao 
472*22dd0cc4SXianjun Jiao static int dev_probe(struct platform_device *pdev) {
473*22dd0cc4SXianjun Jiao 	struct netlink_kernel_cfg cfg = {
474*22dd0cc4SXianjun Jiao 		.input = side_ch_nl_recv_msg,
475*22dd0cc4SXianjun Jiao 	};
476*22dd0cc4SXianjun Jiao 
477*22dd0cc4SXianjun Jiao 	struct device_node *np = pdev->dev.of_node;
478*22dd0cc4SXianjun Jiao 	struct resource *io;
479*22dd0cc4SXianjun Jiao 	int err=1, i;
480*22dd0cc4SXianjun Jiao 
481*22dd0cc4SXianjun Jiao 	printk("\n");
482*22dd0cc4SXianjun Jiao 
483*22dd0cc4SXianjun Jiao 	if (np) {
484*22dd0cc4SXianjun Jiao 		const struct of_device_id *match;
485*22dd0cc4SXianjun Jiao 
486*22dd0cc4SXianjun Jiao 		match = of_match_node(dev_of_ids, np);
487*22dd0cc4SXianjun Jiao 		if (match) {
488*22dd0cc4SXianjun Jiao 			printk("%s dev_probe: match!\n", side_ch_compatible_str);
489*22dd0cc4SXianjun Jiao 			err = 0;
490*22dd0cc4SXianjun Jiao 		}
491*22dd0cc4SXianjun Jiao 	}
492*22dd0cc4SXianjun Jiao 
493*22dd0cc4SXianjun Jiao 	if (err)
494*22dd0cc4SXianjun Jiao 		return err;
495*22dd0cc4SXianjun Jiao 
496*22dd0cc4SXianjun Jiao 	/* Request and map I/O memory */
497*22dd0cc4SXianjun Jiao 	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
498*22dd0cc4SXianjun Jiao 	base_addr = devm_ioremap_resource(&pdev->dev, io);
499*22dd0cc4SXianjun Jiao 	if (IS_ERR(base_addr))
500*22dd0cc4SXianjun Jiao 		return PTR_ERR(base_addr);
501*22dd0cc4SXianjun Jiao 
502*22dd0cc4SXianjun Jiao 	printk("%s dev_probe: io start 0x%p end 0x%p name %s flags 0x%08x desc %s\n", side_ch_compatible_str, (void*)io->start, (void*)io->end, io->name, (u32)io->flags, (char*)io->desc);
503*22dd0cc4SXianjun Jiao 	printk("%s dev_probe: base_addr 0x%p\n", side_ch_compatible_str, base_addr);
504*22dd0cc4SXianjun Jiao 
505*22dd0cc4SXianjun Jiao 	printk("%s dev_probe: succeed!\n", side_ch_compatible_str);
506*22dd0cc4SXianjun Jiao 
507*22dd0cc4SXianjun Jiao 	// --------------initialize netlink--------------
508*22dd0cc4SXianjun Jiao 	//nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
509*22dd0cc4SXianjun Jiao 	nl_sk = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);
510*22dd0cc4SXianjun Jiao 	if(!nl_sk) {
511*22dd0cc4SXianjun Jiao 		printk(KERN_ALERT "%s dev_probe: Error creating socket.\n", side_ch_compatible_str);
512*22dd0cc4SXianjun Jiao 		return -10;
513*22dd0cc4SXianjun Jiao 	}
514*22dd0cc4SXianjun Jiao 
515*22dd0cc4SXianjun Jiao 	//-----------------initialize fpga----------------
516*22dd0cc4SXianjun Jiao 	//rst
517*22dd0cc4SXianjun Jiao 	for (i=0;i<8;i++)
518*22dd0cc4SXianjun Jiao 		SIDE_CH_REG_MULTI_RST_write(0);
519*22dd0cc4SXianjun Jiao 	for (i=0;i<32;i++)
520*22dd0cc4SXianjun Jiao 		SIDE_CH_REG_MULTI_RST_write(0xFFFFFFFF);
521*22dd0cc4SXianjun Jiao 	for (i=0;i<8;i++)
522*22dd0cc4SXianjun Jiao 		SIDE_CH_REG_MULTI_RST_write(0);
523*22dd0cc4SXianjun Jiao 
524*22dd0cc4SXianjun Jiao 	// chan_to_pl = dma_request_slave_channel(&(pdev->dev), "rx_dma_mm2s");
525*22dd0cc4SXianjun Jiao 	// if (IS_ERR(chan_to_pl)) {
526*22dd0cc4SXianjun Jiao 	// 	err = PTR_ERR(chan_to_pl);
527*22dd0cc4SXianjun Jiao 	// 	pr_err("%s dev_probe: No channel to PL. %d\n",side_ch_compatible_str,err);
528*22dd0cc4SXianjun Jiao 	// 	goto free_chan_to_pl;
529*22dd0cc4SXianjun Jiao 	// }
530*22dd0cc4SXianjun Jiao 
531*22dd0cc4SXianjun Jiao 	chan_to_ps = dma_request_slave_channel(&(pdev->dev), "tx_dma_s2mm");
532*22dd0cc4SXianjun Jiao 	if (IS_ERR(chan_to_ps)) {
533*22dd0cc4SXianjun Jiao 		err = PTR_ERR(chan_to_ps);
534*22dd0cc4SXianjun Jiao 		pr_err("%s dev_probe: No channel to PS. %d\n",side_ch_compatible_str,err);
535*22dd0cc4SXianjun Jiao 		goto free_chan_to_ps;
536*22dd0cc4SXianjun Jiao 	}
537*22dd0cc4SXianjun Jiao 
538*22dd0cc4SXianjun Jiao 	printk("%s dev_probe: DMA channel setup successfully. chan_to_pl 0x%p chan_to_ps 0x%p\n",side_ch_compatible_str, chan_to_pl, chan_to_ps);
539*22dd0cc4SXianjun Jiao 
540*22dd0cc4SXianjun Jiao 	// res = dma_loopback_test(3, 512);
541*22dd0cc4SXianjun Jiao 	// printk(KERN_INFO "dma_loopback_test(3, 512) res %d\n", res);
542*22dd0cc4SXianjun Jiao 
543*22dd0cc4SXianjun Jiao 	err = init_side_channel();
544*22dd0cc4SXianjun Jiao 	printk("%s dev_probe: init_side_channel() err %d\n",side_ch_compatible_str, err);
545*22dd0cc4SXianjun Jiao 
546*22dd0cc4SXianjun Jiao 	printk("%s dev_probe: num_eq_init %d\n",side_ch_compatible_str, num_eq_init);
547*22dd0cc4SXianjun Jiao 	// SIDE_CH_REG_CONFIG_write(0X6001); // match addr1 and addr2; bit12 FC; bit13 addr1; bit14 addr2
548*22dd0cc4SXianjun Jiao 	SIDE_CH_REG_CONFIG_write(0x0001); // match all packets by default; bit12 FC; bit13 addr1; bit14 addr2
549*22dd0cc4SXianjun Jiao 	SIDE_CH_REG_NUM_EQ_write(num_eq_init);      // capture CSI + 8*equalizer by default
550*22dd0cc4SXianjun Jiao 
551*22dd0cc4SXianjun Jiao 	return(err);
552*22dd0cc4SXianjun Jiao 
553*22dd0cc4SXianjun Jiao 	// err = dma_loopback_test(7, 512);
554*22dd0cc4SXianjun Jiao 	// if (err == 0)
555*22dd0cc4SXianjun Jiao 	// 	return(err);
556*22dd0cc4SXianjun Jiao 	// else
557*22dd0cc4SXianjun Jiao 	// 	dma_release_channel(chan_to_ps);
558*22dd0cc4SXianjun Jiao 
559*22dd0cc4SXianjun Jiao free_chan_to_ps:
560*22dd0cc4SXianjun Jiao 	err = -2;
561*22dd0cc4SXianjun Jiao 	dma_release_channel(chan_to_ps);
562*22dd0cc4SXianjun Jiao 	return err;
563*22dd0cc4SXianjun Jiao 
564*22dd0cc4SXianjun Jiao // free_chan_to_pl:
565*22dd0cc4SXianjun Jiao // 	err = -1;
566*22dd0cc4SXianjun Jiao // 	dma_release_channel(chan_to_pl);
567*22dd0cc4SXianjun Jiao // 	return err;
568*22dd0cc4SXianjun Jiao }
569*22dd0cc4SXianjun Jiao 
570*22dd0cc4SXianjun Jiao static int dev_remove(struct platform_device *pdev)
571*22dd0cc4SXianjun Jiao {
572*22dd0cc4SXianjun Jiao 	printk("\n");
573*22dd0cc4SXianjun Jiao 
574*22dd0cc4SXianjun Jiao 	printk("%s dev_remove: release nl_sk\n", side_ch_compatible_str);
575*22dd0cc4SXianjun Jiao 	netlink_kernel_release(nl_sk);
576*22dd0cc4SXianjun Jiao 
577*22dd0cc4SXianjun Jiao 	pr_info("%s dev_remove: dropped chan_to_pl 0x%p\n", side_ch_compatible_str, chan_to_pl);
578*22dd0cc4SXianjun Jiao 	if (chan_to_pl != NULL) {
579*22dd0cc4SXianjun Jiao 		pr_info("%s dev_remove: dropped channel %s\n", side_ch_compatible_str, dma_chan_name(chan_to_pl));
580*22dd0cc4SXianjun Jiao 		// dmaengine_terminate_all(chan_to_pl); //this also terminate sdr.ko. do not use
581*22dd0cc4SXianjun Jiao 		dma_release_channel(chan_to_pl);
582*22dd0cc4SXianjun Jiao 	}
583*22dd0cc4SXianjun Jiao 
584*22dd0cc4SXianjun Jiao 	pr_info("%s dev_remove: dropped chan_to_ps 0x%p\n", side_ch_compatible_str, chan_to_ps);
585*22dd0cc4SXianjun Jiao 	if (chan_to_pl != NULL) {
586*22dd0cc4SXianjun Jiao 		pr_info("%s dev_remove: dropped channel %s\n", side_ch_compatible_str, dma_chan_name(chan_to_ps));
587*22dd0cc4SXianjun Jiao 		// dmaengine_terminate_all(chan_to_ps); //this also terminate sdr.ko. do not use
588*22dd0cc4SXianjun Jiao 		dma_release_channel(chan_to_ps);
589*22dd0cc4SXianjun Jiao 	}
590*22dd0cc4SXianjun Jiao 
591*22dd0cc4SXianjun Jiao 	if (side_info_buf != NULL)
592*22dd0cc4SXianjun Jiao 		kfree(side_info_buf);
593*22dd0cc4SXianjun Jiao 
594*22dd0cc4SXianjun Jiao 	printk("%s dev_remove: base_addr 0x%p\n", side_ch_compatible_str, base_addr);
595*22dd0cc4SXianjun Jiao 	printk("%s dev_remove: succeed!\n", side_ch_compatible_str);
596*22dd0cc4SXianjun Jiao 	return 0;
597*22dd0cc4SXianjun Jiao }
598*22dd0cc4SXianjun Jiao 
599*22dd0cc4SXianjun Jiao static struct platform_driver dev_driver = {
600*22dd0cc4SXianjun Jiao 	.driver = {
601*22dd0cc4SXianjun Jiao 		.name = "sdr,side_ch",
602*22dd0cc4SXianjun Jiao 		.owner = THIS_MODULE,
603*22dd0cc4SXianjun Jiao 		.of_match_table = dev_of_ids,
604*22dd0cc4SXianjun Jiao 	},
605*22dd0cc4SXianjun Jiao 	.probe = dev_probe,
606*22dd0cc4SXianjun Jiao 	.remove = dev_remove,
607*22dd0cc4SXianjun Jiao };
608*22dd0cc4SXianjun Jiao 
609*22dd0cc4SXianjun Jiao module_platform_driver(dev_driver);
610*22dd0cc4SXianjun Jiao 
611*22dd0cc4SXianjun Jiao MODULE_AUTHOR("Xianjun Jiao");
612*22dd0cc4SXianjun Jiao MODULE_DESCRIPTION("sdr,side_ch");
613*22dd0cc4SXianjun Jiao MODULE_LICENSE("GPL v2");
614