xref: /openwifi/driver/side_ch/side_ch.c (revision a6085186d94dfe08b0e09c18c8d4b1b4fe38ea35)
122dd0cc4SXianjun Jiao /*
222dd0cc4SXianjun Jiao  * openwifi side channel driver
3*a6085186SLina Ceballos  * SPDX-FileCopyrightText: 2019 Jiao Xianjun <[email protected]>
4*a6085186SLina Ceballos  * SPDX-License-Identifier: AGPL-3.0-or-later
522dd0cc4SXianjun Jiao */
622dd0cc4SXianjun Jiao 
722dd0cc4SXianjun Jiao #include <linux/bitops.h>
822dd0cc4SXianjun Jiao #include <linux/dmapool.h>
922dd0cc4SXianjun Jiao #include <linux/dma/xilinx_dma.h>
1022dd0cc4SXianjun Jiao #include <linux/init.h>
1122dd0cc4SXianjun Jiao #include <linux/interrupt.h>
1222dd0cc4SXianjun Jiao #include <linux/io.h>
1322dd0cc4SXianjun Jiao #include <linux/iopoll.h>
1422dd0cc4SXianjun Jiao #include <linux/module.h>
1522dd0cc4SXianjun Jiao #include <linux/of_address.h>
1622dd0cc4SXianjun Jiao #include <linux/of_dma.h>
1722dd0cc4SXianjun Jiao #include <linux/of_platform.h>
1822dd0cc4SXianjun Jiao #include <linux/of_irq.h>
1922dd0cc4SXianjun Jiao #include <linux/slab.h>
2022dd0cc4SXianjun Jiao #include <linux/clk.h>
2122dd0cc4SXianjun Jiao #include <linux/io-64-nonatomic-lo-hi.h>
2222dd0cc4SXianjun Jiao #include <linux/delay.h>
2322dd0cc4SXianjun Jiao #include <linux/dmaengine.h>
2422dd0cc4SXianjun Jiao 
2522dd0cc4SXianjun Jiao #include <net/sock.h>
2622dd0cc4SXianjun Jiao #include <linux/netlink.h>
2722dd0cc4SXianjun Jiao #include <linux/skbuff.h>
2822dd0cc4SXianjun Jiao 
2922dd0cc4SXianjun Jiao #include "side_ch.h"
3022dd0cc4SXianjun Jiao 
3122dd0cc4SXianjun Jiao static int num_eq_init = 8; // should be 0~8
32f71252c5SXianjun Jiao static int iq_len_init = 0; //if iq_len>0, iq capture enabled, csi disabled
3322dd0cc4SXianjun Jiao 
3422dd0cc4SXianjun Jiao module_param(num_eq_init, int, 0);
3522dd0cc4SXianjun Jiao MODULE_PARM_DESC(num_eq_init, "num_eq_init. 0~8. number of equalizer output (52 each) appended to CSI");
3622dd0cc4SXianjun Jiao 
37f71252c5SXianjun Jiao module_param(iq_len_init, int, 0);
38f71252c5SXianjun Jiao MODULE_PARM_DESC(iq_len_init, "iq_len_init. if iq_len_init>0, iq capture enabled, csi disabled");
39f71252c5SXianjun Jiao 
4022dd0cc4SXianjun 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
4122dd0cc4SXianjun Jiao 
4222dd0cc4SXianjun Jiao struct dma_chan *chan_to_pl = NULL;
4322dd0cc4SXianjun Jiao struct dma_chan *chan_to_ps = NULL;
4422dd0cc4SXianjun Jiao u8 *side_info_buf = NULL;
4522dd0cc4SXianjun Jiao dma_cookie_t chan_to_ps_cookie;
4622dd0cc4SXianjun Jiao const int max_side_info_buf_size = MAX_NUM_DMA_SYMBOL*8;
4722dd0cc4SXianjun Jiao 
4822dd0cc4SXianjun Jiao /* IO accessors */
4922dd0cc4SXianjun Jiao static inline u32 reg_read(u32 reg)
5022dd0cc4SXianjun Jiao {
5122dd0cc4SXianjun Jiao 	return ioread32(base_addr + reg);
5222dd0cc4SXianjun Jiao }
5322dd0cc4SXianjun Jiao 
5422dd0cc4SXianjun Jiao static inline void reg_write(u32 reg, u32 value)
5522dd0cc4SXianjun Jiao {
5622dd0cc4SXianjun Jiao 	iowrite32(value, base_addr + reg);
5722dd0cc4SXianjun Jiao }
5822dd0cc4SXianjun Jiao 
5922dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_MULTI_RST_write(u32 Data) {
6022dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_MULTI_RST_ADDR, Data);
6122dd0cc4SXianjun Jiao }
6222dd0cc4SXianjun Jiao 
6322dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_CONFIG_read(void){
6422dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_CONFIG_ADDR);
6522dd0cc4SXianjun Jiao }
6622dd0cc4SXianjun Jiao 
6722dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_CONFIG_write(u32 value){
6822dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_CONFIG_ADDR, value);
6922dd0cc4SXianjun Jiao }
7022dd0cc4SXianjun Jiao 
7122dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_NUM_DMA_SYMBOL_read(void){
7222dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_NUM_DMA_SYMBOL_ADDR);
7322dd0cc4SXianjun Jiao }
7422dd0cc4SXianjun Jiao 
7522dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_NUM_DMA_SYMBOL_write(u32 value){
7622dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_NUM_DMA_SYMBOL_ADDR, value);
7722dd0cc4SXianjun Jiao }
7822dd0cc4SXianjun Jiao 
79f71252c5SXianjun Jiao static inline u32 SIDE_CH_REG_IQ_CAPTURE_read(void){
80f71252c5SXianjun Jiao 	return reg_read(SIDE_CH_REG_IQ_CAPTURE_ADDR);
8122dd0cc4SXianjun Jiao }
8222dd0cc4SXianjun Jiao 
83f71252c5SXianjun Jiao static inline void SIDE_CH_REG_IQ_CAPTURE_write(u32 value){
84f71252c5SXianjun Jiao 	reg_write(SIDE_CH_REG_IQ_CAPTURE_ADDR, value);
8522dd0cc4SXianjun Jiao }
8622dd0cc4SXianjun Jiao 
8722dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_NUM_EQ_read(void){
8822dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_NUM_EQ_ADDR);
8922dd0cc4SXianjun Jiao }
9022dd0cc4SXianjun Jiao 
9122dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_NUM_EQ_write(u32 value){
9222dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_NUM_EQ_ADDR, value);
9322dd0cc4SXianjun Jiao }
9422dd0cc4SXianjun Jiao 
9522dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_FC_TARGET_read(void){
9622dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_FC_TARGET_ADDR);
9722dd0cc4SXianjun Jiao }
9822dd0cc4SXianjun Jiao 
9922dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_FC_TARGET_write(u32 value){
10022dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_FC_TARGET_ADDR, value);
10122dd0cc4SXianjun Jiao }
10222dd0cc4SXianjun Jiao 
10322dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_ADDR1_TARGET_read(void){
10422dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_ADDR1_TARGET_ADDR);
10522dd0cc4SXianjun Jiao }
10622dd0cc4SXianjun Jiao 
10722dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_ADDR1_TARGET_write(u32 value){
10822dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_ADDR1_TARGET_ADDR, value);
10922dd0cc4SXianjun Jiao }
11022dd0cc4SXianjun Jiao 
11122dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_ADDR2_TARGET_read(void){
11222dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_ADDR2_TARGET_ADDR);
11322dd0cc4SXianjun Jiao }
11422dd0cc4SXianjun Jiao 
11522dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_ADDR2_TARGET_write(u32 value){
11622dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_ADDR2_TARGET_ADDR, value);
11722dd0cc4SXianjun Jiao }
11822dd0cc4SXianjun Jiao 
119f71252c5SXianjun Jiao static inline u32 SIDE_CH_REG_IQ_TRIGGER_read(void){
120f71252c5SXianjun Jiao 	return reg_read(SIDE_CH_REG_IQ_TRIGGER_ADDR);
121f71252c5SXianjun Jiao }
122f71252c5SXianjun Jiao 
123f71252c5SXianjun Jiao static inline void SIDE_CH_REG_IQ_TRIGGER_write(u32 value){
124f71252c5SXianjun Jiao 	reg_write(SIDE_CH_REG_IQ_TRIGGER_ADDR, value);
125f71252c5SXianjun Jiao }
126f71252c5SXianjun Jiao 
127f71252c5SXianjun Jiao static inline u32 SIDE_CH_REG_RSSI_TH_read(void){
128f71252c5SXianjun Jiao 	return reg_read(SIDE_CH_REG_RSSI_TH_ADDR);
129f71252c5SXianjun Jiao }
130f71252c5SXianjun Jiao 
131f71252c5SXianjun Jiao static inline void SIDE_CH_REG_RSSI_TH_write(u32 value){
132f71252c5SXianjun Jiao 	reg_write(SIDE_CH_REG_RSSI_TH_ADDR, value);
133f71252c5SXianjun Jiao }
134f71252c5SXianjun Jiao 
135f71252c5SXianjun Jiao static inline u32 SIDE_CH_REG_GAIN_TH_read(void){
136f71252c5SXianjun Jiao 	return reg_read(SIDE_CH_REG_GAIN_TH_ADDR);
137f71252c5SXianjun Jiao }
138f71252c5SXianjun Jiao 
139f71252c5SXianjun Jiao static inline void SIDE_CH_REG_GAIN_TH_write(u32 value){
140f71252c5SXianjun Jiao 	reg_write(SIDE_CH_REG_GAIN_TH_ADDR, value);
141f71252c5SXianjun Jiao }
142f71252c5SXianjun Jiao 
143f71252c5SXianjun Jiao static inline u32 SIDE_CH_REG_PRE_TRIGGER_LEN_read(void){
144f71252c5SXianjun Jiao 	return reg_read(SIDE_CH_REG_PRE_TRIGGER_LEN_ADDR);
145f71252c5SXianjun Jiao }
146f71252c5SXianjun Jiao 
147f71252c5SXianjun Jiao static inline void SIDE_CH_REG_PRE_TRIGGER_LEN_write(u32 value){
148f71252c5SXianjun Jiao 	reg_write(SIDE_CH_REG_PRE_TRIGGER_LEN_ADDR, value);
149f71252c5SXianjun Jiao }
150f71252c5SXianjun Jiao 
151f71252c5SXianjun Jiao static inline u32 SIDE_CH_REG_IQ_LEN_read(void){
152f71252c5SXianjun Jiao 	return reg_read(SIDE_CH_REG_IQ_LEN_ADDR);
153f71252c5SXianjun Jiao }
154f71252c5SXianjun Jiao 
155f71252c5SXianjun Jiao static inline void SIDE_CH_REG_IQ_LEN_write(u32 value){
156f71252c5SXianjun Jiao 	reg_write(SIDE_CH_REG_IQ_LEN_ADDR, value);
157f71252c5SXianjun Jiao }
158f71252c5SXianjun Jiao 
15922dd0cc4SXianjun Jiao static inline u32 SIDE_CH_REG_M_AXIS_DATA_COUNT_read(void){
16022dd0cc4SXianjun Jiao 	return reg_read(SIDE_CH_REG_M_AXIS_DATA_COUNT_ADDR);
16122dd0cc4SXianjun Jiao }
16222dd0cc4SXianjun Jiao 
16322dd0cc4SXianjun Jiao static inline void SIDE_CH_REG_M_AXIS_DATA_COUNT_write(u32 value){
16422dd0cc4SXianjun Jiao 	reg_write(SIDE_CH_REG_M_AXIS_DATA_COUNT_ADDR, value);
16522dd0cc4SXianjun Jiao }
16622dd0cc4SXianjun Jiao 
16722dd0cc4SXianjun Jiao static const struct of_device_id dev_of_ids[] = {
16822dd0cc4SXianjun Jiao 	{ .compatible = "sdr,side_ch", },
16922dd0cc4SXianjun Jiao 	{}
17022dd0cc4SXianjun Jiao };
17122dd0cc4SXianjun Jiao MODULE_DEVICE_TABLE(of, dev_of_ids);
17222dd0cc4SXianjun Jiao 
17322dd0cc4SXianjun Jiao static void chan_to_ps_callback(void *completion)
17422dd0cc4SXianjun Jiao {
17522dd0cc4SXianjun Jiao 	complete(completion);
17622dd0cc4SXianjun Jiao }
17722dd0cc4SXianjun Jiao 
17822dd0cc4SXianjun Jiao #if 0
17922dd0cc4SXianjun Jiao static void chan_to_pl_callback(void *completion)
18022dd0cc4SXianjun Jiao {
18122dd0cc4SXianjun Jiao 	complete(completion);
18222dd0cc4SXianjun Jiao }
18322dd0cc4SXianjun Jiao 
18422dd0cc4SXianjun Jiao static int dma_loopback_test(int num_test, int num_dma_symbol) {
18522dd0cc4SXianjun Jiao 	int i, err = 0;
18622dd0cc4SXianjun Jiao 
18722dd0cc4SXianjun Jiao 	// -----------dma loop back test-------------------------
18822dd0cc4SXianjun Jiao 	enum dma_status status;
18922dd0cc4SXianjun Jiao 	enum dma_ctrl_flags flags;
19022dd0cc4SXianjun Jiao 	u8 *src_buf, *dst_buf;
19122dd0cc4SXianjun Jiao 	// int num_dma_symbol = 16;
19222dd0cc4SXianjun Jiao 	int test_buf_size = num_dma_symbol*8;
19322dd0cc4SXianjun Jiao 	dma_addr_t src_buf_dma;
19422dd0cc4SXianjun Jiao 	dma_addr_t dst_buf_dma;
19522dd0cc4SXianjun Jiao 	struct dma_device *chan_to_pl_dev = chan_to_pl->device;
19622dd0cc4SXianjun Jiao 	struct dma_device *chan_to_ps_dev = chan_to_ps->device;
19722dd0cc4SXianjun Jiao 	struct scatterlist chan_to_pl_sg[1];
19822dd0cc4SXianjun Jiao 	struct scatterlist chan_to_ps_sg[1];
19922dd0cc4SXianjun Jiao 	dma_cookie_t chan_to_pl_cookie;
20022dd0cc4SXianjun Jiao 	dma_cookie_t chan_to_ps_cookie;
20122dd0cc4SXianjun Jiao 	struct completion chan_to_pl_cmp;
20222dd0cc4SXianjun Jiao 	struct completion chan_to_ps_cmp;
20322dd0cc4SXianjun Jiao 	struct dma_async_tx_descriptor *chan_to_pl_d = NULL;
20422dd0cc4SXianjun Jiao 	struct dma_async_tx_descriptor *chan_to_ps_d = NULL;
20522dd0cc4SXianjun Jiao 	unsigned long chan_to_ps_tmo =	msecs_to_jiffies(300000);
20622dd0cc4SXianjun Jiao 	unsigned long chan_to_pl_tmo =  msecs_to_jiffies(30000);
20722dd0cc4SXianjun Jiao 	int test_idx;
20822dd0cc4SXianjun Jiao 
20922dd0cc4SXianjun Jiao 	for (test_idx=0; test_idx<num_test; test_idx++) {
21022dd0cc4SXianjun Jiao 		printk("%s test_idx %d\n", side_ch_compatible_str, test_idx);
21122dd0cc4SXianjun Jiao 		//set number of dma symbols expected to pl and ps
21222dd0cc4SXianjun Jiao 		SIDE_CH_REG_NUM_DMA_SYMBOL_write((num_dma_symbol<<16)|num_dma_symbol);
21322dd0cc4SXianjun Jiao 
21422dd0cc4SXianjun Jiao 		src_buf = kmalloc(test_buf_size, GFP_KERNEL);
21522dd0cc4SXianjun Jiao 		if (!src_buf)
21622dd0cc4SXianjun Jiao 			goto err_src_buf;
21722dd0cc4SXianjun Jiao 
21822dd0cc4SXianjun Jiao 		dst_buf = kmalloc(test_buf_size, GFP_KERNEL);
21922dd0cc4SXianjun Jiao 		if (!dst_buf)
22022dd0cc4SXianjun Jiao 			goto err_dst_buf;
22122dd0cc4SXianjun Jiao 
22222dd0cc4SXianjun Jiao 		// test buf init
22322dd0cc4SXianjun Jiao 		for (i=0; i<test_buf_size; i++) {
22422dd0cc4SXianjun Jiao 			src_buf[i] = (test_idx+test_buf_size-i-1);
22522dd0cc4SXianjun Jiao 			dst_buf[i] = 0;
22622dd0cc4SXianjun Jiao 		}
22722dd0cc4SXianjun Jiao 
22822dd0cc4SXianjun Jiao 		set_user_nice(current, 10);
22922dd0cc4SXianjun Jiao 		flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
23022dd0cc4SXianjun Jiao 
23122dd0cc4SXianjun Jiao 		src_buf_dma = dma_map_single(chan_to_pl_dev->dev, src_buf, test_buf_size, DMA_MEM_TO_DEV);
23222dd0cc4SXianjun Jiao 		if (dma_mapping_error(chan_to_pl_dev->dev, src_buf_dma)) {
23322dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test WARNING chan_to_pl_dev DMA mapping error\n", side_ch_compatible_str);
23422dd0cc4SXianjun Jiao 			goto err_src_buf_dma_mapping;
23522dd0cc4SXianjun Jiao 		}
23622dd0cc4SXianjun Jiao 
23722dd0cc4SXianjun Jiao 		dst_buf_dma = dma_map_single(chan_to_ps_dev->dev, dst_buf, test_buf_size, DMA_DEV_TO_MEM);
23822dd0cc4SXianjun Jiao 		if (dma_mapping_error(chan_to_ps_dev->dev, dst_buf_dma)) {
23922dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test WARNING chan_to_ps_dev DMA mapping error\n", side_ch_compatible_str);
24022dd0cc4SXianjun Jiao 			goto err_dst_buf_dma_mapping;
24122dd0cc4SXianjun Jiao 		}
24222dd0cc4SXianjun Jiao 
24322dd0cc4SXianjun Jiao 		sg_init_table(chan_to_ps_sg, 1);
24422dd0cc4SXianjun Jiao 		sg_init_table(chan_to_pl_sg, 1);
24522dd0cc4SXianjun Jiao 
24622dd0cc4SXianjun Jiao 		sg_dma_address(&chan_to_ps_sg[0]) = dst_buf_dma;
24722dd0cc4SXianjun Jiao 		sg_dma_address(&chan_to_pl_sg[0]) = src_buf_dma;
24822dd0cc4SXianjun Jiao 
24922dd0cc4SXianjun Jiao 		sg_dma_len(&chan_to_ps_sg[0]) = test_buf_size;
25022dd0cc4SXianjun Jiao 		sg_dma_len(&chan_to_pl_sg[0]) = test_buf_size;
25122dd0cc4SXianjun Jiao 
25222dd0cc4SXianjun 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);
25322dd0cc4SXianjun 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);
25422dd0cc4SXianjun Jiao 
25522dd0cc4SXianjun Jiao 		if (!chan_to_ps_d || !chan_to_pl_d) {
25622dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test WARNING !chan_to_ps_d || !chan_to_pl_d\n", side_ch_compatible_str);
25722dd0cc4SXianjun Jiao 			goto err_dst_buf_with_unmap;
25822dd0cc4SXianjun Jiao 		}
25922dd0cc4SXianjun Jiao 
26022dd0cc4SXianjun Jiao 		init_completion(&chan_to_pl_cmp);
26122dd0cc4SXianjun Jiao 		chan_to_pl_d->callback = chan_to_pl_callback;
26222dd0cc4SXianjun Jiao 		chan_to_pl_d->callback_param = &chan_to_pl_cmp;
26322dd0cc4SXianjun Jiao 		chan_to_pl_cookie = chan_to_pl_d->tx_submit(chan_to_pl_d);
26422dd0cc4SXianjun Jiao 
26522dd0cc4SXianjun Jiao 		init_completion(&chan_to_ps_cmp);
26622dd0cc4SXianjun Jiao 		chan_to_ps_d->callback = chan_to_ps_callback;
26722dd0cc4SXianjun Jiao 		chan_to_ps_d->callback_param = &chan_to_ps_cmp;
26822dd0cc4SXianjun Jiao 		chan_to_ps_cookie = chan_to_ps_d->tx_submit(chan_to_ps_d);
26922dd0cc4SXianjun Jiao 
27022dd0cc4SXianjun Jiao 		if (dma_submit_error(chan_to_pl_cookie) ||	dma_submit_error(chan_to_ps_cookie)) {
27122dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test WARNING dma_submit_error\n", side_ch_compatible_str);
27222dd0cc4SXianjun Jiao 			goto err_dst_buf_with_unmap;
27322dd0cc4SXianjun Jiao 		}
27422dd0cc4SXianjun Jiao 
27522dd0cc4SXianjun Jiao 		dma_async_issue_pending(chan_to_pl);
27622dd0cc4SXianjun Jiao 		dma_async_issue_pending(chan_to_ps);
27722dd0cc4SXianjun Jiao 
27822dd0cc4SXianjun Jiao 		chan_to_pl_tmo = wait_for_completion_timeout(&chan_to_pl_cmp, chan_to_pl_tmo);
27922dd0cc4SXianjun Jiao 
28022dd0cc4SXianjun Jiao 		status = dma_async_is_tx_complete(chan_to_pl, chan_to_pl_cookie, NULL, NULL);
28122dd0cc4SXianjun Jiao 		if (chan_to_pl_tmo == 0) {
28222dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test chan_to_pl_tmo == 0\n", side_ch_compatible_str);
28322dd0cc4SXianjun Jiao 			goto err_dst_buf_with_unmap;
28422dd0cc4SXianjun Jiao 		} else if (status != DMA_COMPLETE) {
28522dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test chan_to_pl status != DMA_COMPLETE\n", side_ch_compatible_str);
28622dd0cc4SXianjun Jiao 			goto err_dst_buf_with_unmap;
28722dd0cc4SXianjun Jiao 		}
28822dd0cc4SXianjun Jiao 
28922dd0cc4SXianjun Jiao 		chan_to_ps_tmo = wait_for_completion_timeout(&chan_to_ps_cmp, chan_to_ps_tmo);
29022dd0cc4SXianjun Jiao 		status = dma_async_is_tx_complete(chan_to_ps, chan_to_ps_cookie, NULL, NULL);
29122dd0cc4SXianjun Jiao 		if (chan_to_ps_tmo == 0) {
29222dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test chan_to_ps_tmo == 0\n", side_ch_compatible_str);
29322dd0cc4SXianjun Jiao 			goto err_dst_buf_with_unmap;
29422dd0cc4SXianjun Jiao 		} else if (status != DMA_COMPLETE) {
29522dd0cc4SXianjun Jiao 			printk("%s dma_loopback_test chan_to_ps status != DMA_COMPLETE\n", side_ch_compatible_str);
29622dd0cc4SXianjun Jiao 			goto err_dst_buf_with_unmap;
29722dd0cc4SXianjun Jiao 		}
29822dd0cc4SXianjun Jiao 
29922dd0cc4SXianjun Jiao 		dma_unmap_single(chan_to_pl_dev->dev, src_buf_dma, test_buf_size, DMA_MEM_TO_DEV);
30022dd0cc4SXianjun Jiao 		dma_unmap_single(chan_to_ps_dev->dev, dst_buf_dma, test_buf_size, DMA_DEV_TO_MEM);
30122dd0cc4SXianjun Jiao 
30222dd0cc4SXianjun Jiao 		// test buf verification
30322dd0cc4SXianjun Jiao 		for (i=0; i<test_buf_size; i++) {
30422dd0cc4SXianjun Jiao 			//printk("%d ", dst_buf[i]);
30522dd0cc4SXianjun Jiao 			if ( dst_buf[i] != ((test_idx+test_buf_size-i-1)%256) )
30622dd0cc4SXianjun Jiao 				break;
30722dd0cc4SXianjun Jiao 		}
30822dd0cc4SXianjun Jiao 		printk("\n");
30922dd0cc4SXianjun Jiao 		printk("%s dma_loopback_test buf verification end idx %d (test_buf_size %d)\n", side_ch_compatible_str, i, test_buf_size);
31022dd0cc4SXianjun Jiao 
31122dd0cc4SXianjun Jiao 		kfree(src_buf);
31222dd0cc4SXianjun Jiao 		kfree(dst_buf);
31322dd0cc4SXianjun Jiao 	}
31422dd0cc4SXianjun Jiao 
31522dd0cc4SXianjun Jiao 	printk("%s dma_loopback_test err %d\n", side_ch_compatible_str, err);
31622dd0cc4SXianjun Jiao 	return(err);
31722dd0cc4SXianjun Jiao 
31822dd0cc4SXianjun Jiao err_dst_buf_with_unmap:
31922dd0cc4SXianjun Jiao 	dma_unmap_single(chan_to_ps_dev->dev, dst_buf_dma, test_buf_size, DMA_DEV_TO_MEM);
32022dd0cc4SXianjun Jiao 
32122dd0cc4SXianjun Jiao err_dst_buf_dma_mapping:
32222dd0cc4SXianjun Jiao 	dma_unmap_single(chan_to_pl_dev->dev, src_buf_dma, test_buf_size, DMA_MEM_TO_DEV);
32322dd0cc4SXianjun Jiao 
32422dd0cc4SXianjun Jiao err_src_buf_dma_mapping:
32522dd0cc4SXianjun Jiao 
32622dd0cc4SXianjun Jiao err_dst_buf:
32722dd0cc4SXianjun Jiao 	err = -4;
32822dd0cc4SXianjun Jiao 	kfree((void*)dst_buf);
32922dd0cc4SXianjun Jiao 
33022dd0cc4SXianjun Jiao err_src_buf:
33122dd0cc4SXianjun Jiao 	err = -3;
33222dd0cc4SXianjun Jiao 	kfree(src_buf);
33322dd0cc4SXianjun Jiao 
33422dd0cc4SXianjun Jiao 	return(err);
33522dd0cc4SXianjun Jiao }
33622dd0cc4SXianjun Jiao #endif
33722dd0cc4SXianjun Jiao 
33822dd0cc4SXianjun Jiao static int init_side_channel(void) {
33922dd0cc4SXianjun Jiao 	side_info_buf = kmalloc(max_side_info_buf_size, GFP_KERNEL);
34022dd0cc4SXianjun Jiao 	if (!side_info_buf)
34122dd0cc4SXianjun Jiao 		return(-1);
34222dd0cc4SXianjun Jiao 
34322dd0cc4SXianjun Jiao 	return(0);
34422dd0cc4SXianjun Jiao }
34522dd0cc4SXianjun Jiao 
346f71252c5SXianjun Jiao static int get_side_info(int num_eq, int iq_len) {
34722dd0cc4SXianjun Jiao 	// int err = 0;//, i;
34822dd0cc4SXianjun Jiao 	struct scatterlist chan_to_ps_sg[1];
34922dd0cc4SXianjun Jiao 	enum dma_status status;
35022dd0cc4SXianjun Jiao 	enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
35122dd0cc4SXianjun Jiao 	int num_dma_symbol, num_dma_symbol_per_trans, side_info_buf_size;
35222dd0cc4SXianjun Jiao 	dma_addr_t side_info_buf_dma;
35322dd0cc4SXianjun Jiao 	struct dma_device *chan_to_ps_dev = chan_to_ps->device;
35422dd0cc4SXianjun Jiao 	struct completion chan_to_ps_cmp;
35522dd0cc4SXianjun Jiao 	struct dma_async_tx_descriptor *chan_to_ps_d = NULL;
35622dd0cc4SXianjun Jiao 	unsigned long chan_to_ps_tmo =	msecs_to_jiffies(100);
35722dd0cc4SXianjun Jiao 
35822dd0cc4SXianjun Jiao 	if (side_info_buf==NULL) {
35922dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING side_info_buf==NULL\n", side_ch_compatible_str);
36022dd0cc4SXianjun Jiao 		return(-1);
36122dd0cc4SXianjun Jiao 	}
36222dd0cc4SXianjun Jiao 
36322dd0cc4SXianjun Jiao 	status = dma_async_is_tx_complete(chan_to_ps, chan_to_ps_cookie, NULL, NULL);
36422dd0cc4SXianjun Jiao 	if (status!=DMA_COMPLETE) {
36522dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING status!=DMA_COMPLETE\n", side_ch_compatible_str);
36622dd0cc4SXianjun Jiao 		return(-1);
36722dd0cc4SXianjun Jiao 	}
36822dd0cc4SXianjun Jiao 
36922dd0cc4SXianjun Jiao 	set_user_nice(current, 10);
37022dd0cc4SXianjun Jiao 
371f71252c5SXianjun Jiao 	if (iq_len>0)
372f71252c5SXianjun Jiao 		num_dma_symbol_per_trans = 1+iq_len;
373f71252c5SXianjun Jiao 	else
37422dd0cc4SXianjun Jiao 		num_dma_symbol_per_trans = HEADER_LEN + CSI_LEN + num_eq*EQUALIZER_LEN;
37522dd0cc4SXianjun Jiao 	//set number of dma symbols expected to ps
37622dd0cc4SXianjun Jiao 	num_dma_symbol = SIDE_CH_REG_M_AXIS_DATA_COUNT_read();
37722dd0cc4SXianjun 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);
37822dd0cc4SXianjun Jiao 	num_dma_symbol = num_dma_symbol_per_trans*(num_dma_symbol/num_dma_symbol_per_trans);
37922dd0cc4SXianjun Jiao 	printk("%s get_side_info actual num dma symbol %d\n", side_ch_compatible_str, num_dma_symbol);
38022dd0cc4SXianjun Jiao 	if (num_dma_symbol == 0)
38122dd0cc4SXianjun Jiao 		return(-2);
38222dd0cc4SXianjun Jiao 
38322dd0cc4SXianjun Jiao 	side_info_buf_size = num_dma_symbol*8;
38422dd0cc4SXianjun Jiao 	side_info_buf_dma = dma_map_single(chan_to_ps_dev->dev, side_info_buf, side_info_buf_size, DMA_DEV_TO_MEM);
38522dd0cc4SXianjun Jiao 	if (dma_mapping_error(chan_to_ps_dev->dev, side_info_buf_dma)) {
38622dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING chan_to_ps_dev DMA mapping error\n", side_ch_compatible_str);
38722dd0cc4SXianjun Jiao 		return(-3);
38822dd0cc4SXianjun Jiao 	}
38922dd0cc4SXianjun Jiao 
39022dd0cc4SXianjun Jiao 	sg_init_table(chan_to_ps_sg, 1);
39122dd0cc4SXianjun Jiao 	sg_dma_address(&chan_to_ps_sg[0]) = side_info_buf_dma;
39222dd0cc4SXianjun Jiao 	sg_dma_len(&chan_to_ps_sg[0]) = side_info_buf_size;
39322dd0cc4SXianjun Jiao 
39422dd0cc4SXianjun 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);
39522dd0cc4SXianjun Jiao 	if (!chan_to_ps_d) {
39622dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING !chan_to_ps_d\n", side_ch_compatible_str);
39722dd0cc4SXianjun Jiao 		goto err_dst_buf_with_unmap;
39822dd0cc4SXianjun Jiao 	}
39922dd0cc4SXianjun Jiao 
40022dd0cc4SXianjun Jiao 	init_completion(&chan_to_ps_cmp);
40122dd0cc4SXianjun Jiao 	chan_to_ps_d->callback = chan_to_ps_callback;
40222dd0cc4SXianjun Jiao 	chan_to_ps_d->callback_param = &chan_to_ps_cmp;
40322dd0cc4SXianjun Jiao 
40422dd0cc4SXianjun Jiao 	chan_to_ps_cookie = chan_to_ps_d->tx_submit(chan_to_ps_d);
40522dd0cc4SXianjun Jiao 	if (dma_submit_error(chan_to_ps_cookie)) {
40622dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING dma_submit_error\n", side_ch_compatible_str);
40722dd0cc4SXianjun Jiao 		goto err_dst_buf_with_unmap;
40822dd0cc4SXianjun Jiao 	}
40922dd0cc4SXianjun Jiao 
41022dd0cc4SXianjun Jiao 	SIDE_CH_REG_NUM_DMA_SYMBOL_write(num_dma_symbol); //dma from fpga will start automatically
41122dd0cc4SXianjun Jiao 
41222dd0cc4SXianjun Jiao 	dma_async_issue_pending(chan_to_ps);
41322dd0cc4SXianjun Jiao 
41422dd0cc4SXianjun Jiao 	chan_to_ps_tmo = wait_for_completion_timeout(&chan_to_ps_cmp, chan_to_ps_tmo);
41522dd0cc4SXianjun Jiao 	status = dma_async_is_tx_complete(chan_to_ps, chan_to_ps_cookie, NULL, NULL);
41622dd0cc4SXianjun Jiao 	if (chan_to_ps_tmo == 0) {
41722dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING chan_to_ps_tmo == 0\n", side_ch_compatible_str);
41822dd0cc4SXianjun Jiao 		goto err_dst_buf_with_unmap;
41922dd0cc4SXianjun Jiao 	} else if (status != DMA_COMPLETE) {
42022dd0cc4SXianjun Jiao 		printk("%s get_side_info WARNING chan_to_ps status != DMA_COMPLETE\n", side_ch_compatible_str);
42122dd0cc4SXianjun Jiao 		goto err_dst_buf_with_unmap;
42222dd0cc4SXianjun Jiao 	}
42322dd0cc4SXianjun Jiao 
42422dd0cc4SXianjun Jiao 	dma_unmap_single(chan_to_ps_dev->dev, side_info_buf_dma, side_info_buf_size, DMA_DEV_TO_MEM);
42522dd0cc4SXianjun Jiao 	return(side_info_buf_size);
42622dd0cc4SXianjun Jiao 
42722dd0cc4SXianjun Jiao err_dst_buf_with_unmap:
42822dd0cc4SXianjun Jiao 	dma_unmap_single(chan_to_ps_dev->dev, side_info_buf_dma, side_info_buf_size, DMA_DEV_TO_MEM);
42922dd0cc4SXianjun Jiao 	return(-100);
43022dd0cc4SXianjun Jiao }
43122dd0cc4SXianjun Jiao 
43222dd0cc4SXianjun Jiao // -----------------netlink recv and send-----------------
43322dd0cc4SXianjun Jiao // should align with side_ch_ctl.c in user_space
43422dd0cc4SXianjun Jiao #define ACTION_INVALID       0
43522dd0cc4SXianjun Jiao #define ACTION_REG_WRITE     1
43622dd0cc4SXianjun Jiao #define ACTION_REG_READ      2
43722dd0cc4SXianjun Jiao #define ACTION_SIDE_INFO_GET 3
43822dd0cc4SXianjun Jiao 
43922dd0cc4SXianjun Jiao #define REG_TYPE_INVALID     0
44022dd0cc4SXianjun Jiao #define REG_TYPE_HARDWARE    1
44122dd0cc4SXianjun Jiao #define REG_TYPE_SOFTWARE    2
44222dd0cc4SXianjun Jiao 
44322dd0cc4SXianjun Jiao // #define NETLINK_USER 31
44422dd0cc4SXianjun Jiao struct sock *nl_sk = NULL;
44522dd0cc4SXianjun Jiao static void side_ch_nl_recv_msg(struct sk_buff *skb) {
44622dd0cc4SXianjun Jiao 	struct nlmsghdr *nlh;
44722dd0cc4SXianjun Jiao 	int pid;
44822dd0cc4SXianjun Jiao 	struct sk_buff *skb_out;
44922dd0cc4SXianjun Jiao 	int msg_size;
45022dd0cc4SXianjun Jiao 	int *msg=(int*)side_info_buf;
45122dd0cc4SXianjun Jiao 	int action_flag, reg_type, reg_idx;
45222dd0cc4SXianjun Jiao 	u32 reg_val, *cmd_buf;
45322dd0cc4SXianjun Jiao 	int res;
45422dd0cc4SXianjun Jiao 
45522dd0cc4SXianjun Jiao 	// printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
45622dd0cc4SXianjun Jiao 
45722dd0cc4SXianjun Jiao 	// msg_size=strlen(msg);
45822dd0cc4SXianjun Jiao 
45922dd0cc4SXianjun Jiao 	nlh=(struct nlmsghdr*)skb->data;
46022dd0cc4SXianjun Jiao 	cmd_buf = (u32*)nlmsg_data(nlh);
46122dd0cc4SXianjun Jiao 	// printk(KERN_INFO "Netlink received msg payload:%s\n",(char*)nlmsg_data(nlh));
46222dd0cc4SXianjun Jiao 	action_flag = cmd_buf[0];
46322dd0cc4SXianjun Jiao     reg_type = cmd_buf[1];
46422dd0cc4SXianjun Jiao     reg_idx = cmd_buf[2];
46522dd0cc4SXianjun Jiao     reg_val = cmd_buf[3];
46622dd0cc4SXianjun 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);
46722dd0cc4SXianjun Jiao 
46822dd0cc4SXianjun Jiao 	pid = nlh->nlmsg_pid; /*pid of sending process */
46922dd0cc4SXianjun Jiao 
47022dd0cc4SXianjun Jiao 	if (action_flag==ACTION_SIDE_INFO_GET) {
471f71252c5SXianjun Jiao 		res = get_side_info(num_eq_init, iq_len_init);
472f71252c5SXianjun Jiao 		printk(KERN_INFO "%s recv msg: get_side_info(%d,%d) res %d\n", side_ch_compatible_str, num_eq_init, iq_len_init, res);
47322dd0cc4SXianjun Jiao 		if (res>0) {
47422dd0cc4SXianjun Jiao 			msg_size = res;
47522dd0cc4SXianjun 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]);
47622dd0cc4SXianjun Jiao 		} else {
47722dd0cc4SXianjun Jiao 			msg_size = 4;
47822dd0cc4SXianjun Jiao 			msg[0] = -2;
47922dd0cc4SXianjun Jiao 		}
48022dd0cc4SXianjun Jiao 	} else if (action_flag==ACTION_REG_READ) {
48122dd0cc4SXianjun Jiao 		msg_size = 4;
48222dd0cc4SXianjun Jiao 		// if (reg_idx<0 || reg_idx>31) {
48322dd0cc4SXianjun Jiao 		// 	msg[0] = -3;
48422dd0cc4SXianjun Jiao 		// 	printk("%s recv msg: invalid reg_idx\n", side_ch_compatible_str);
48522dd0cc4SXianjun Jiao 		// } else {
48622dd0cc4SXianjun Jiao 			msg[0] = reg_read(reg_idx*4);
48722dd0cc4SXianjun Jiao 		// }
48822dd0cc4SXianjun Jiao 	} else if (action_flag==ACTION_REG_WRITE) {
48922dd0cc4SXianjun Jiao 		msg_size = 4;
49022dd0cc4SXianjun Jiao 		// if (reg_idx<0 || reg_idx>31) {
49122dd0cc4SXianjun Jiao 		// 	msg[0] = -4;
49222dd0cc4SXianjun Jiao 		// 	printk("%s recv msg: invalid reg_idx\n", side_ch_compatible_str);
49322dd0cc4SXianjun Jiao 		// } else {
49422dd0cc4SXianjun Jiao 			msg[0] = 0;
49522dd0cc4SXianjun Jiao 			reg_write(reg_idx*4, reg_val);
49622dd0cc4SXianjun Jiao 		// }
49722dd0cc4SXianjun Jiao 	} else {
49822dd0cc4SXianjun Jiao 		msg_size = 4;
49922dd0cc4SXianjun Jiao 		msg[0] = -1;
50022dd0cc4SXianjun Jiao 		printk("%s recv msg: invalid action_flag\n", side_ch_compatible_str);
50122dd0cc4SXianjun Jiao 	}
50222dd0cc4SXianjun Jiao 
50322dd0cc4SXianjun Jiao 	skb_out = nlmsg_new(msg_size,0);
50422dd0cc4SXianjun Jiao 	if(!skb_out)
50522dd0cc4SXianjun Jiao 	{
50622dd0cc4SXianjun Jiao 		printk(KERN_ERR "Failed to allocate new skb\n");
50722dd0cc4SXianjun Jiao 		return;
50822dd0cc4SXianjun Jiao 	}
50922dd0cc4SXianjun Jiao 	nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0);
51022dd0cc4SXianjun Jiao 	NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
51122dd0cc4SXianjun Jiao 
51222dd0cc4SXianjun Jiao 	memcpy(nlmsg_data(nlh),msg,msg_size);
51322dd0cc4SXianjun Jiao 
51422dd0cc4SXianjun Jiao 	res=nlmsg_unicast(nl_sk,skb_out,pid);
51522dd0cc4SXianjun Jiao 
51622dd0cc4SXianjun Jiao 	if(res<0)
51722dd0cc4SXianjun Jiao 		printk(KERN_INFO "Error while sending bak to user\n");
51822dd0cc4SXianjun Jiao }
51922dd0cc4SXianjun Jiao 
52022dd0cc4SXianjun Jiao static int dev_probe(struct platform_device *pdev) {
52122dd0cc4SXianjun Jiao 	struct netlink_kernel_cfg cfg = {
52222dd0cc4SXianjun Jiao 		.input = side_ch_nl_recv_msg,
52322dd0cc4SXianjun Jiao 	};
52422dd0cc4SXianjun Jiao 
52522dd0cc4SXianjun Jiao 	struct device_node *np = pdev->dev.of_node;
52622dd0cc4SXianjun Jiao 	struct resource *io;
52722dd0cc4SXianjun Jiao 	int err=1, i;
52822dd0cc4SXianjun Jiao 
52922dd0cc4SXianjun Jiao 	printk("\n");
53022dd0cc4SXianjun Jiao 
53122dd0cc4SXianjun Jiao 	if (np) {
53222dd0cc4SXianjun Jiao 		const struct of_device_id *match;
53322dd0cc4SXianjun Jiao 
53422dd0cc4SXianjun Jiao 		match = of_match_node(dev_of_ids, np);
53522dd0cc4SXianjun Jiao 		if (match) {
53622dd0cc4SXianjun Jiao 			printk("%s dev_probe: match!\n", side_ch_compatible_str);
53722dd0cc4SXianjun Jiao 			err = 0;
53822dd0cc4SXianjun Jiao 		}
53922dd0cc4SXianjun Jiao 	}
54022dd0cc4SXianjun Jiao 
54122dd0cc4SXianjun Jiao 	if (err)
54222dd0cc4SXianjun Jiao 		return err;
54322dd0cc4SXianjun Jiao 
54422dd0cc4SXianjun Jiao 	/* Request and map I/O memory */
54522dd0cc4SXianjun Jiao 	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
54622dd0cc4SXianjun Jiao 	base_addr = devm_ioremap_resource(&pdev->dev, io);
54722dd0cc4SXianjun Jiao 	if (IS_ERR(base_addr))
54822dd0cc4SXianjun Jiao 		return PTR_ERR(base_addr);
54922dd0cc4SXianjun Jiao 
55022dd0cc4SXianjun 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);
55122dd0cc4SXianjun Jiao 	printk("%s dev_probe: base_addr 0x%p\n", side_ch_compatible_str, base_addr);
55222dd0cc4SXianjun Jiao 
55322dd0cc4SXianjun Jiao 	printk("%s dev_probe: succeed!\n", side_ch_compatible_str);
55422dd0cc4SXianjun Jiao 
55522dd0cc4SXianjun Jiao 	// --------------initialize netlink--------------
55622dd0cc4SXianjun Jiao 	//nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
55722dd0cc4SXianjun Jiao 	nl_sk = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);
55822dd0cc4SXianjun Jiao 	if(!nl_sk) {
55922dd0cc4SXianjun Jiao 		printk(KERN_ALERT "%s dev_probe: Error creating socket.\n", side_ch_compatible_str);
56022dd0cc4SXianjun Jiao 		return -10;
56122dd0cc4SXianjun Jiao 	}
56222dd0cc4SXianjun Jiao 
56322dd0cc4SXianjun Jiao 	//-----------------initialize fpga----------------
564f71252c5SXianjun Jiao 	printk("%s dev_probe: num_eq_init %d iq_len_init %d\n",side_ch_compatible_str, num_eq_init, iq_len_init);
565f71252c5SXianjun Jiao 
566f71252c5SXianjun Jiao 	// disable potential any action from side channel
567f71252c5SXianjun Jiao 	SIDE_CH_REG_MULTI_RST_write(4);
568f71252c5SXianjun Jiao 	// SIDE_CH_REG_CONFIG_write(0X6001); // match addr1 and addr2; bit12 FC; bit13 addr1; bit14 addr2
569f71252c5SXianjun Jiao 	SIDE_CH_REG_CONFIG_write(0x7001); // the most strict condition to prevent side channel action
570f71252c5SXianjun Jiao 	SIDE_CH_REG_IQ_TRIGGER_write(10); // set iq trigger to rssi, which will never happen when rssi_th is 0
571f71252c5SXianjun Jiao 	SIDE_CH_REG_NUM_EQ_write(num_eq_init);      // capture CSI + 8*equalizer by default
572f71252c5SXianjun Jiao 	if (iq_len_init>0) {//initialize the side channel into iq capture mode
573f71252c5SXianjun Jiao 		//Max UDP 65507 bytes; (65507/8)-1 = 8187
574f71252c5SXianjun Jiao 		if (iq_len_init>8187) {
575f71252c5SXianjun Jiao 			iq_len_init = 8187;
576f71252c5SXianjun Jiao 			printk("%s dev_probe: limit iq_len_init to 8187!\n",side_ch_compatible_str);
577f71252c5SXianjun Jiao 		}
578f71252c5SXianjun Jiao 		SIDE_CH_REG_IQ_CAPTURE_write(1);
579f71252c5SXianjun Jiao 		SIDE_CH_REG_PRE_TRIGGER_LEN_write(8190);
580f71252c5SXianjun Jiao 		SIDE_CH_REG_IQ_LEN_write(iq_len_init);
581f71252c5SXianjun Jiao 		SIDE_CH_REG_IQ_TRIGGER_write(0); // trigger is set to fcs ok/nok (both)
582f71252c5SXianjun Jiao 	}
583f71252c5SXianjun Jiao 
584f71252c5SXianjun Jiao 	SIDE_CH_REG_CONFIG_write(0x0001); // allow all packets by default; bit12 FC; bit13 addr1; bit14 addr2
585f71252c5SXianjun Jiao 
58622dd0cc4SXianjun Jiao 	//rst
58722dd0cc4SXianjun Jiao 	for (i=0;i<8;i++)
58822dd0cc4SXianjun Jiao 		SIDE_CH_REG_MULTI_RST_write(0);
58922dd0cc4SXianjun Jiao 	for (i=0;i<32;i++)
59022dd0cc4SXianjun Jiao 		SIDE_CH_REG_MULTI_RST_write(0xFFFFFFFF);
59122dd0cc4SXianjun Jiao 	for (i=0;i<8;i++)
59222dd0cc4SXianjun Jiao 		SIDE_CH_REG_MULTI_RST_write(0);
59322dd0cc4SXianjun Jiao 
59422dd0cc4SXianjun Jiao 	// chan_to_pl = dma_request_slave_channel(&(pdev->dev), "rx_dma_mm2s");
59522dd0cc4SXianjun Jiao 	// if (IS_ERR(chan_to_pl)) {
59622dd0cc4SXianjun Jiao 	// 	err = PTR_ERR(chan_to_pl);
59722dd0cc4SXianjun Jiao 	// 	pr_err("%s dev_probe: No channel to PL. %d\n",side_ch_compatible_str,err);
59822dd0cc4SXianjun Jiao 	// 	goto free_chan_to_pl;
59922dd0cc4SXianjun Jiao 	// }
60022dd0cc4SXianjun Jiao 
60122dd0cc4SXianjun Jiao 	chan_to_ps = dma_request_slave_channel(&(pdev->dev), "tx_dma_s2mm");
60222dd0cc4SXianjun Jiao 	if (IS_ERR(chan_to_ps)) {
60322dd0cc4SXianjun Jiao 		err = PTR_ERR(chan_to_ps);
60422dd0cc4SXianjun Jiao 		pr_err("%s dev_probe: No channel to PS. %d\n",side_ch_compatible_str,err);
60522dd0cc4SXianjun Jiao 		goto free_chan_to_ps;
60622dd0cc4SXianjun Jiao 	}
60722dd0cc4SXianjun Jiao 
60822dd0cc4SXianjun 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);
60922dd0cc4SXianjun Jiao 
61022dd0cc4SXianjun Jiao 	// res = dma_loopback_test(3, 512);
61122dd0cc4SXianjun Jiao 	// printk(KERN_INFO "dma_loopback_test(3, 512) res %d\n", res);
61222dd0cc4SXianjun Jiao 
61322dd0cc4SXianjun Jiao 	err = init_side_channel();
61422dd0cc4SXianjun Jiao 	printk("%s dev_probe: init_side_channel() err %d\n",side_ch_compatible_str, err);
61522dd0cc4SXianjun Jiao 
61622dd0cc4SXianjun Jiao 	return(err);
61722dd0cc4SXianjun Jiao 
61822dd0cc4SXianjun Jiao 	// err = dma_loopback_test(7, 512);
61922dd0cc4SXianjun Jiao 	// if (err == 0)
62022dd0cc4SXianjun Jiao 	// 	return(err);
62122dd0cc4SXianjun Jiao 	// else
62222dd0cc4SXianjun Jiao 	// 	dma_release_channel(chan_to_ps);
62322dd0cc4SXianjun Jiao 
62422dd0cc4SXianjun Jiao free_chan_to_ps:
62522dd0cc4SXianjun Jiao 	err = -2;
62622dd0cc4SXianjun Jiao 	dma_release_channel(chan_to_ps);
62722dd0cc4SXianjun Jiao 	return err;
62822dd0cc4SXianjun Jiao 
62922dd0cc4SXianjun Jiao // free_chan_to_pl:
63022dd0cc4SXianjun Jiao // 	err = -1;
63122dd0cc4SXianjun Jiao // 	dma_release_channel(chan_to_pl);
63222dd0cc4SXianjun Jiao // 	return err;
63322dd0cc4SXianjun Jiao }
63422dd0cc4SXianjun Jiao 
63522dd0cc4SXianjun Jiao static int dev_remove(struct platform_device *pdev)
63622dd0cc4SXianjun Jiao {
63722dd0cc4SXianjun Jiao 	printk("\n");
63822dd0cc4SXianjun Jiao 
63922dd0cc4SXianjun Jiao 	printk("%s dev_remove: release nl_sk\n", side_ch_compatible_str);
64022dd0cc4SXianjun Jiao 	netlink_kernel_release(nl_sk);
64122dd0cc4SXianjun Jiao 
64222dd0cc4SXianjun Jiao 	pr_info("%s dev_remove: dropped chan_to_pl 0x%p\n", side_ch_compatible_str, chan_to_pl);
64322dd0cc4SXianjun Jiao 	if (chan_to_pl != NULL) {
64422dd0cc4SXianjun Jiao 		pr_info("%s dev_remove: dropped channel %s\n", side_ch_compatible_str, dma_chan_name(chan_to_pl));
64522dd0cc4SXianjun Jiao 		// dmaengine_terminate_all(chan_to_pl); //this also terminate sdr.ko. do not use
64622dd0cc4SXianjun Jiao 		dma_release_channel(chan_to_pl);
64722dd0cc4SXianjun Jiao 	}
64822dd0cc4SXianjun Jiao 
64922dd0cc4SXianjun Jiao 	pr_info("%s dev_remove: dropped chan_to_ps 0x%p\n", side_ch_compatible_str, chan_to_ps);
65022dd0cc4SXianjun Jiao 	if (chan_to_pl != NULL) {
65122dd0cc4SXianjun Jiao 		pr_info("%s dev_remove: dropped channel %s\n", side_ch_compatible_str, dma_chan_name(chan_to_ps));
65222dd0cc4SXianjun Jiao 		// dmaengine_terminate_all(chan_to_ps); //this also terminate sdr.ko. do not use
65322dd0cc4SXianjun Jiao 		dma_release_channel(chan_to_ps);
65422dd0cc4SXianjun Jiao 	}
65522dd0cc4SXianjun Jiao 
65622dd0cc4SXianjun Jiao 	if (side_info_buf != NULL)
65722dd0cc4SXianjun Jiao 		kfree(side_info_buf);
65822dd0cc4SXianjun Jiao 
65922dd0cc4SXianjun Jiao 	printk("%s dev_remove: base_addr 0x%p\n", side_ch_compatible_str, base_addr);
66022dd0cc4SXianjun Jiao 	printk("%s dev_remove: succeed!\n", side_ch_compatible_str);
66122dd0cc4SXianjun Jiao 	return 0;
66222dd0cc4SXianjun Jiao }
66322dd0cc4SXianjun Jiao 
66422dd0cc4SXianjun Jiao static struct platform_driver dev_driver = {
66522dd0cc4SXianjun Jiao 	.driver = {
66622dd0cc4SXianjun Jiao 		.name = "sdr,side_ch",
66722dd0cc4SXianjun Jiao 		.owner = THIS_MODULE,
66822dd0cc4SXianjun Jiao 		.of_match_table = dev_of_ids,
66922dd0cc4SXianjun Jiao 	},
67022dd0cc4SXianjun Jiao 	.probe = dev_probe,
67122dd0cc4SXianjun Jiao 	.remove = dev_remove,
67222dd0cc4SXianjun Jiao };
67322dd0cc4SXianjun Jiao 
67422dd0cc4SXianjun Jiao module_platform_driver(dev_driver);
67522dd0cc4SXianjun Jiao 
67622dd0cc4SXianjun Jiao MODULE_AUTHOR("Xianjun Jiao");
67722dd0cc4SXianjun Jiao MODULE_DESCRIPTION("sdr,side_ch");
67822dd0cc4SXianjun Jiao MODULE_LICENSE("GPL v2");
679