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