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