/* * GigaSpaceWire switch driver for MC-30SF6EM-6U evaluation kit * * Copyright (c) 2019 Elvees (support@elvees.com) * Author: Dmitry Evtushenko * */ #include #include #include #include #include #include #include #include #include #include #include #include "ctl.h" #include "reg.h" #include "gspwsw.h" #include "test.h" #include "../ua_mem.h" #define VAL_MSK_DFLT 0xFFFFFFFF //- defaulte value mask #define VAL_OFS_DFLT 0 //- defaulte value offset // address complementation: #define COMPL_ADDR( addr) \ if( !(addr & 0xFFFF0000)) \ addr |= MC_BASE_ADDR; \ if( !(addr & 0xF000)) \ addr |= GSPW_ADDR_OFS; #define GET_REG( addr) (*(volatile unsigned *)addr) #define SET_REG( addr, val) *(volatile unsigned *)addr = val // 1 - connected, 0 - not connected, -1 - errors static int swic_is_connected( unsigned int port) { u32 bds_stat; if( port >= MAX_SPW_PORT_QNT) return -1; bds_stat = (GSPW_SPW_STAT_REG(port) >> GSPW_SPW_STAT_BDS_OFS) & GSPW_SPW_STAT_BDS_MSK; return (bds_stat == BDS_STAT_RUN) ? 1 : 0; } // 1 - set speed, 0 - no, -1 - errors int swic_set_tx_speed( unsigned port, unsigned speed) { unsigned rem = (((speed % 5) > 2) ? 1 : 0); //- remainder if( port >= MAX_SPW_PORT_QNT) return -1; if( speed < 5) speed = 5; if( speed > 400) speed = 400; GSPW_TX_SPEED_REG( port) &= ~GSPW_TX_SPEED_COEF_MSK; GSPW_TX_SPEED_REG(port) |= ((((speed / 5) + rem) & GSPW_TX_SPEED_COEF_MSK) << GSPW_TX_SPEED_COEF_OFS); mdelay( 100); pr_info( "swic_set_tx_speed: port=%u, speed=%u, TX_SPEED=%Xh\n", port, speed, GSPW_TX_SPEED_REG(port)); return swic_is_connected( port); } /*static int swic_get_rx_speed( unsigned port) { if( port >= MAX_SPW_PORT_QNT) return -1; return (int )(GSPW_RX_SPEED_REG(port) & GSPW_SPW_RX_SPEED_MSK); }*/ static void gspw_print_dbg_stat( void) { gspw_ctrl_t *pgsc; int i; pr_info("Print debug statistic:\n"); for( i=0; (iport.name, pgsc->cnt_int_con); } } void gspw_mem_test( void) { // ... } static void gspw_reset_tx_rx( gspw_cfg_ctrl_t *pcfg) { pcfg->is_reset_io = 1; wake_up_interruptible( &pcfg->wq_txdata); wake_up_interruptible( &pcfg->wq_txdesc); //wake_up_interruptible( &pcfg->wq_txjob); //wake_up_interruptible( &pcfg->wq_rx); gspw_wake_up_all_rx_thread(); fifo_reset( &pcfg->dch_tx_desc.ff); fifo_reset( &pcfg->dch_tx_data.ff); fifo_reset( &pcfg->ff_tx_job); fifo_reset( &pcfg->dch_rx_desc.ff); fifo_reset( &pcfg->dch_rx_data.ff); pcfg->is_reset_io = 0; } static int thread_stop_work_mode( void *pv) { gspw_cfg_ctrl_t *pcfg = (gspw_cfg_ctrl_t *)pv; u32 tm_wait = 1000; u32 delay = 100; u32 i, cnt = (tm_wait / delay); int rc = RC_SPW_SUCCESS; for( i=0; (i < cnt); ++i) { if( (gspw_sw.is_rx_stop == MAX_ALL_SPW_MSK) && (gspw_sw.is_tx_stop == MAX_ALL_SPW_MSK) && gspw_sw.is_tx_job_stop) { gspw_sw.mode = GSPW_MODE_CONFIG; pr_info( "Spaceware interfaces have been stopped\n"); pr_info( "GigaSpaceware switch is under the configure mode\n"); goto l_end; } mdelay( delay); } pr_info( "Spaceware interfaces will be forced stopped now\n"); gspw_sw.mode = GSPW_MODE_FORCE_STOP; gspw_wake_up_all_rx_thread(); wake_up_interruptible( &pcfg->wq_txdata); wake_up_interruptible( &pcfg->wq_txdesc); wake_up_interruptible( &pcfg->wq_txjob); mdelay( 200); if( !gspw_sw.is_tx_job_stop && pcfg->p_task_tx_dma_job) { if( (rc = kthread_stop( pcfg->p_task_tx_dma_job))==-EINTR ) { pr_info("kthread_stop: ERROR(%i)\n", rc); } } if( (gspw_sw.is_rx_stop != MAX_ALL_SPW_MSK) || (gspw_sw.is_tx_stop != MAX_ALL_SPW_MSK) || !gspw_sw.is_tx_job_stop) { pr_info( "Not all spaceware interfaces were stopped\n"); if( rc == RC_SPW_SUCCESS) rc = EBUSY; } l_end:; gspw_sw.mode = GSPW_MODE_CONFIG; for( i=0; (i < MAX_SPW_PORT_QNT); ++i) GSPW_MODE_REG(i) |= (GSPW_MODE_LINK_DISA | GSPW_MODE_BDS_RST); return rc; } int set_configure_mode( void) { gspw_cfg_ctrl_t *pcfg = &gspw_sw.cfg_ctrl; int i; if( gspw_sw.mode != GSPW_MODE_WORK) return -EPERM; pr_info( "Spaceware interfaces will be stopped now\n"); gspw_sw.is_rx_stop = 0; gspw_sw.is_tx_stop = 0; gspw_sw.is_tx_job_stop = 0; for( i=0; (i < MAX_SPW_PORT_QNT); ++i) { if( gspw_sw.a_gspwc[i].port.open == 0) { gspw_sw.is_rx_stop |= (1 << i); gspw_sw.is_tx_stop |= (1 << i); } } gspw_sw.mode = GSPW_MODE_STOP; gspw_wake_up_all_rx_thread(); wake_up_interruptible( &pcfg->wq_txdata); wake_up_interruptible( &pcfg->wq_txdesc); wake_up_interruptible( &pcfg->wq_txjob); pcfg->p_task_stop_work_mode = kthread_run( &thread_stop_work_mode, pcfg, "thread_stop_work_mode"); if( pcfg->p_task_stop_work_mode==NULL && IS_ERR( pcfg->p_task_stop_work_mode)) { pr_info( "Could not create 'thread_stop_work_mode' thread\n"); return -ENOMEM; } return RC_SPW_SUCCESS; } static int set_work_mode( void) { gspw_cfg_ctrl_t *pcfg = &gspw_sw.cfg_ctrl; int i, rc; u32 k10 = XTI125_FREQ / 10; if( gspw_sw.mode != GSPW_MODE_CONFIG) return -1; gspw_sw.is_rx_stop = 0; gspw_sw.is_tx_stop = 0; gspw_sw.is_tx_job_stop = 0; /* if( (rc=dma_rx_chain_init( pcfg)) ) return rc; if( (rc=dma_tx_chain_init( pcfg)) ) return rc; */ init_waitqueue_head( &pcfg->wq_st); init_waitqueue_head( &pcfg->wq_txdesc); init_waitqueue_head( &pcfg->wq_txdata); init_waitqueue_head( &pcfg->wq_txjob); if( (rc=gspw_cfg_ctrl_init_job_task( pcfg)) != RC_SPW_SUCCESS) return rc; gspw_sw.mode = GSPW_MODE_WORK; for( i=0; (i < MAX_SPW_PORT_QNT); ++i) { GSPW_MODE_REG(i) &= ~GSPW_MODE_LINK_DISA; GSPW_MODE_REG(i) |= (GSPW_MODE_AUTOSTART | GSPW_MODE_LINKSTART | ((k10 & GSPW_MODE_K10_LOCAL_MSK) << GSPW_MODE_K10_LOCAL_OFS)); } pr_info( "Spaceware interfaces will be started now\n"); return RC_SPW_SUCCESS; } int apply_param_changes( void) { gspw_cfg_ctrl_t *pcfg = &gspw_sw.cfg_ctrl; gspw_sw_set_t *ps = &gspw_sw.set_new; gspw_ctrl_t *pspw; spw_set_t *pspws; int i, rc; u32 change_tx = 0; u32 change_rx = 0; if( gspw_sw.mode != GSPW_MODE_CONFIG) return -1; if( ps->tx.dma.qnt_desc != pcfg->qnt_tx_desc) { pcfg->qnt_tx_desc = ps->tx.dma.qnt_desc; ++change_tx; } if( ps->tx.dma.qnt_data != pcfg->qnt_tx_data) { pcfg->qnt_tx_data = ps->tx.dma.qnt_data; ++change_tx; } if( ps->tx.dma.sz_data_buf != pcfg->sz_tx_data_buf) { pcfg->sz_tx_data_buf = ps->tx.dma.sz_data_buf; ++change_tx; } if( ps->tx.max_sz_pack != pcfg->max_sz_tx_pack) pcfg->max_sz_tx_pack = ps->tx.max_sz_pack; if( change_tx) { dma_tx_chain_free( pcfg); if( ((rc=dma_tx_chain_init( pcfg)) != RC_SPW_SUCCESS) /*|| ((rc=gspw_cfg_ctrl_init_job_task( pcfg)) != RC_SPW_SUCCESS)*/ ) { pcfg->qnt_tx_desc = 0; pcfg->qnt_tx_data = 0; pcfg->sz_tx_data_buf = 0; return rc; } } if( ps->rx.dma.qnt_desc != pcfg->qnt_rx_desc) { pcfg->qnt_rx_desc = ps->rx.dma.qnt_desc; ++change_rx; } if( ps->rx.dma.qnt_data != pcfg->qnt_rx_data) { pcfg->qnt_rx_data = ps->rx.dma.qnt_data; ++change_rx; } if( ps->rx.dma.sz_data_buf != pcfg->sz_rx_data_buf) { pcfg->sz_rx_data_buf = ps->rx.dma.sz_data_buf; ++change_rx; } if( change_rx) { dma_rx_chain_free( pcfg); if( (rc=dma_rx_chain_init( pcfg)) != RC_SPW_SUCCESS ) { pcfg->qnt_rx_desc = 0; pcfg->qnt_rx_data = 0; pcfg->sz_rx_data_buf = 0; return rc; } } for(i=0; (i < MAX_SPW_PORT_QNT); ++i) { pspw = &gspw_sw.a_gspwc[i]; pspws = &ps->a_spw[i]; if( pspws->max_qnt_send_desc != pspw->max_qnt_send_desc) pspw->max_qnt_send_desc = pspws->max_qnt_send_desc; if( pspws->tx_speed != pspw->speed) { if( swic_set_tx_speed( pspw->port.num, pspw->speed) >= 0) pspw->speed = pspws->tx_speed; } } memcpy( ps->a_rt, gspw_sw.rt.a_rt, sizeof(ps->a_rt)); return RC_SPW_SUCCESS; } // // Функция-обработчик команд пользователя ioctl // long drv_gspw_ioctl( struct file *file, unsigned int cmd, unsigned long arg) { const char *drv_name = GSPW_DEV_NAME; int ret = RC_SPW_SUCCESS; unsigned int drv_chan_num = iminor( file->f_dentry->d_inode); //-[0,2] gspw_cfg_ctrl_t *pcfg = &gspw_sw.cfg_ctrl; gspw_sw_set_t *pset = &gspw_sw.set_new; spw_set_t *pset_spw; unsigned spw_port; //-[0,1] gspw_ctrl_t *pspw; //unsigned freq_mult_mhz; //u32 v4; //u32 reg; u32 addr=0; u32 val; //pr_info("drv_gspw_ioctl: chan_num=%u cmd=%Xh\n", drv_chan_num, cmd); if( drv_chan_num >= GSPW_DRV_PORT_QNT) return -ENODEV; // common commands: switch (cmd) { // Actions: case GSPW_IO_APPLY_CHANGES: break; // GETs: // Получение значения регистра по адресу: case GSPW_GET_REG_VAL: { u32 addr=0; //addr = *((u32 *)arg); GET_USER( GSPW_GET_REG_VAL, addr, arg, __u32) //pr_info( "drv_gspw_ioctl: GSPW_GET_REG_VAL: addr=%Xh\n", addr); //*((u32 *)arg) = XPCIe_Get( addr); //reg = XPCIe_Get( addr); COMPL_ADDR( addr) PUT_USER( GSPW_GET_REG_VAL, GET_REG( addr), arg, __u32) //pr_info( "drv_gspw_ioctl: GET_REG_VAL: val=%Xh\n", GET_REG( addr)); return ret; } // Получение значения CP0 регистра по адресу: case GSPW_GET_CP0_REG_VAL: { GET_USER( GSPW_GET_CP0_REG_VAL, addr, arg, __u32) //pr_info( "drv_gspw_ioctl: GSPW_GET_REG_VAL: addr=%Xh\n", addr); if( (addr > SYS_CP0_LAST_REG) || (addr < SYS_CP0_FIRST_REG) ) { pr_info("CP0 register address ia out of range\n"); return -EINVAL; } val = read_cp0_reg( addr); /*{ addr = 0; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 0), mips_read_c0_reg( addr)); addr = 1; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 1), mips_read_c0_reg( addr)); addr = 2; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 2), mips_read_c0_reg( addr)); addr = 3; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 3), mips_read_c0_reg( addr)); addr = 4; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 4), mips_read_c0_reg( addr)); addr = 5; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 5), mips_read_c0_reg( addr)); addr = 6; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 6), mips_read_c0_reg( addr)); addr = 7; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 7), mips_read_c0_reg( addr)); addr = 8; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 8), mips_read_c0_reg( addr)); addr = 9; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 9), mips_read_c0_reg( addr)); addr = 10; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 10), mips_read_c0_reg( addr)); addr = 11; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 11), mips_read_c0_reg( addr)); addr = 12; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 12), mips_read_c0_reg( addr)); addr = 13; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 13), mips_read_c0_reg( addr)); addr = 14; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 14), mips_read_c0_reg( addr)); addr = 15; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 15), mips_read_c0_reg( addr)); addr = 16; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 16), mips_read_c0_reg( addr)); addr = 17; pr_info( "reg=%Xh %Xh\n", mips_read_c0_register( 17), mips_read_c0_reg( addr)); }*/ //val = mips_read_c0_register(12); //val = mips_read_c0_register( addr); //val = mips_read_c0_register( 12); PUT_USER( GSPW_GET_CP0_REG_VAL, val, arg, __u32) //pr_info( "drv_gspw_ioctl: GET_REG_VAL: val=%Xh\n", GET_REG( addr)); return ret; } // SETs: // Установка значения регистра по адресу: case GSPW_SET_REG_VAL: { /*struct s_reg_val *p_rv = (struct s_reg_val *)arg; #ifndef USE_FREE_USER_MEM_ACCESS struct s_reg_val rv; #endif //- !USE_FREE_USER_MEM_ACCESS*/ struct s_reg_val_ext *p_rv = (struct s_reg_val_ext *)arg; #ifndef USE_FREE_USER_MEM_ACCESS struct s_reg_val_ext rv; #endif //- !USE_FREE_USER_MEM_ACCESS if( p_rv==NULL) return -EINVAL; SET_PNTR( p_rv, rv) COPY_FROM_USER( GSPW_SET_REG_VAL, p_rv, (void *)arg, sizeof(*p_rv)) if( p_rv) { COMPL_ADDR( p_rv->addr) if( (p_rv->msk != VAL_MSK_DFLT) || (p_rv->ofs != VAL_OFS_DFLT)) { val = GET_REG( p_rv->addr); val &= ~(p_rv->msk << p_rv->ofs); val |= ((p_rv->val & p_rv->msk) << p_rv->ofs); p_rv->val = val; } SET_REG( p_rv->addr, p_rv->val); //pr_info( "drv_gspw_ioctl: GSPW_SET_REG_VAL: addr=%.8Xh, val=%.8Xh (%.8Xh)\n", // p_rv->addr, p_rv->val, GET_REG( p_rv->addr)); //pr_info( "drv_gspw_ioctl: GSPW_SET_REG_VAL: addr=%.8Xh, val=%.8Xh (%.8Xh) msk=%Xh ofs=%u\n", // p_rv->addr, p_rv->val, GET_REG(p_rv->addr), p_rv->msk, p_rv->ofs); //COPY_TO_USER( GSPW_SET_REG_VAL, (void *)arg, p_rv, sizeof(*p_rv)) } return ret; } // Установка значения CP0 регистра по адресу: case GSPW_SET_CP0_REG_VAL: { struct s_reg_val_ext *p_rv = (struct s_reg_val_ext *)arg; #ifndef USE_FREE_USER_MEM_ACCESS struct s_reg_val_ext rv; #endif //- !USE_FREE_USER_MEM_ACCESS if( p_rv==NULL) return -EINVAL; SET_PNTR( p_rv, rv) COPY_FROM_USER( GSPW_SET_REG_VAL, p_rv, (void *)arg, sizeof(*p_rv)) if( (p_rv->addr > SYS_CP0_LAST_REG) || (p_rv->addr < SYS_CP0_FIRST_REG) ) { pr_info("CP0 register address ia out of range\n"); return -EINVAL; } if( p_rv) { if( (p_rv->msk != VAL_MSK_DFLT) || (p_rv->ofs != VAL_OFS_DFLT)) { //val = GET_REG( p_rv->addr); //val = mips_read_c0_register( p_rv->addr); val = read_cp0_reg( p_rv->addr); val &= ~(p_rv->msk << p_rv->ofs); val |= ((p_rv->val & p_rv->msk) << p_rv->ofs); p_rv->val = val; } //SET_REG( p_rv->addr, p_rv->val); //mips_write_c0_register( p_rv->addr, p_rv->val); write_cp0_reg( p_rv->addr, p_rv->val); //pr_info( "drv_gspw_ioctl: GSPW_SET_REG_VAL: addr=%.8Xh, val=%.8Xh (%.8Xh)\n", // p_rv->addr, p_rv->val, GET_REG( p_rv->addr)); //pr_info( "drv_gspw_ioctl: GSPW_SET_REG_VAL: addr=%.8Xh, val=%.8Xh (%.8Xh) msk=%Xh ofs=%u\n", // p_rv->addr, p_rv->val, GET_REG(p_rv->addr), p_rv->msk, p_rv->ofs); //COPY_TO_USER( GSPW_SET_REG_VAL, (void *)arg, p_rv, sizeof(*p_rv)) } return ret; } } if (drv_chan_num ==GSPW_CFG_PORT_NUM) { switch (cmd) { // Actions: case GSPW_IO_START: //gspw_sw.mode_msk |= (1 << drv_chan_num); ret = set_work_mode(); break; case GSPW_IO_STOP: //gspw_sw.mode_msk &= ~(1 << drv_chan_num); ret = set_configure_mode(); break; case GSPW_IO_APPLY_CHANGES: if( gspw_sw.mode != GSPW_MODE_CONFIG) return -ECANCELED; apply_param_changes(); break; case GSPW_IO_RESET_TX_RX: gspw_reset_tx_rx( pcfg); break; // Сброс статистики: case GSPW_IO_RESET_STAT: pcfg->rx_eop = 0; pcfg->rx_eep = 0; pcfg->rx_bytes = 0; pcfg->rx_drop_pack = 0; pcfg->rx_drop_bytes = 0; pcfg->tx_packets = 0; pcfg->tx_bytes = 0; //pcfg->txdma_waits = 0; break; // print debug statistic: case GSPW_IO_PRINT_DBG_STAT: gspw_print_dbg_stat(); break; #ifdef USE_DMA_TEST case GSPW_IO_INERN_DMA_TEST: if( arg==IOCTL_ARG__INERN_DMA_TEST_PRINT) { pcfg->test.tm_end = get_time_of_day(); gspw_dma_internal_test_print( &pcfg->test); } else if( arg==IOCTL_ARG__INERN_DMA_TEST_START) gspw_dma_internal_test_start( pcfg); else if( arg==IOCTL_ARG__INERN_DMA_TEST_STOP) gspw_dma_internal_test_stop( pcfg); break; #endif //USE_DMA_TEST case GSPW_IO_MEM_TEST: gspw_mem_test(); break; // GETs: // Получение текущего режима работы: case GSPW_GET_MODE: PUT_USER( GSPW_GET_MODE, gspw_sw.mode, arg, __u32) break; // Получение количества TX DMA дескрипторов: case GSPW_GET_DMA_TX_DESC_QNT: PUT_USER( GSPW_GET_DMA_TX_DESC_QNT, pcfg->qnt_tx_desc, arg, __u32) break; // Получение количества TX DMA буферов данных: case GSPW_GET_DMA_TX_DATA_QNT: PUT_USER( GSPW_GET_DMA_TX_DATA_QNT, pcfg->qnt_tx_data, arg, __u32) break; // Получение размера TX DMA буфера данных: case GSPW_GET_DMA_TX_DATA_BUF_SIZE: PUT_USER( GSPW_GET_DMA_TX_DATA_BUF_SIZE, pcfg->sz_tx_data_buf, arg, __u32) break; // Получение максимального размера TX пакета данных: case GSPW_GET_DMA_TX_PACK_SIZE: PUT_USER( GSPW_GET_DMA_TX_PACK_SIZE, pcfg->max_sz_tx_pack, arg, __u32) break; // Получение количества RX DMA дескрипторов: case GSPW_GET_DMA_RX_DESC_QNT: PUT_USER( GSPW_GET_DMA_RX_DESC_QNT, pcfg->qnt_rx_desc, arg, __u32) break; // Получение количества RX DMA буферов данных: case GSPW_GET_DMA_RX_DATA_QNT: PUT_USER( GSPW_GET_DMA_RX_DATA_QNT, pcfg->qnt_rx_data, arg, __u32) break; // Получение размера RX DMA буфера данных: case GSPW_GET_DMA_RX_DATA_BUF_SIZE: PUT_USER( GSPW_GET_DMA_RX_DATA_BUF_SIZE, pcfg->sz_rx_data_buf, arg, __u32) break; // Settings (еще неустановленные параметры): // Получение количества TX DMA дескрипторов: case GSPW_GET_DMA_TX_DESC_QNT_NEW: PUT_USER( GSPW_GET_DMA_TX_DESC_QNT, pset->tx.dma.qnt_desc, arg, __u32) break; // Получение количества TX DMA буферов данных: case GSPW_GET_DMA_TX_DATA_QNT_NEW: PUT_USER( GSPW_GET_DMA_TX_DATA_QNT, pset->tx.dma.qnt_data, arg, __u32) break; // Получение размера TX DMA буфера данных: case GSPW_GET_DMA_TX_DATA_BUF_SIZE_NEW: PUT_USER( GSPW_GET_DMA_TX_DATA_BUF_SIZE, pset->tx.dma.sz_data_buf, arg, __u32) break; // Получение максимального размера TX пакета данных: case GSPW_GET_DMA_TX_PACK_SIZE_NEW: PUT_USER( GSPW_GET_DMA_TX_PACK_SIZE, pset->tx.max_sz_pack, arg, __u32) break; // Получение количества RX DMA дескрипторов: case GSPW_GET_DMA_RX_DESC_QNT_NEW: PUT_USER( GSPW_GET_DMA_RX_DESC_QNT, pset->rx.dma.qnt_desc, arg, __u32) break; // Получение количества RX DMA буферов данных: case GSPW_GET_DMA_RX_DATA_QNT_NEW: PUT_USER( GSPW_GET_DMA_RX_DATA_QNT, pset->rx.dma.qnt_data, arg, __u32) break; // Получение размера RX DMA буфера данных: case GSPW_GET_DMA_RX_DATA_BUF_SIZE_NEW: PUT_USER( GSPW_GET_DMA_RX_DATA_BUF_SIZE, pset->rx.dma.sz_data_buf, arg, __u32) break; // Statistics: // Получение количества успешно принятых пакетов (EOP): case GSPW_GET_STAT_RX_EOP: PUT_USER( GSPW_GET_STAT_RX_EOP, pcfg->rx_eop, arg, __u32) break; // Получение количества принятых пакетов с ошибкой (EEP): case GSPW_GET_STAT_RX_EEP: PUT_USER( GSPW_GET_STAT_RX_EEP, pcfg->rx_eep, arg, __u32) break; // Получение количества принятых байт: case GSPW_GET_STAT_RX_BYTES: PUT_USER( GSPW_GET_STAT_RX_BYTES, pcfg->rx_bytes, arg, __u32) break; // Получение количества переданных пакетов: case GSPW_GET_STAT_TX_PACKETS: PUT_USER( GSPW_GET_STAT_TX_PACKETS, pcfg->tx_packets, arg, __u32) break; // Получение количества переданных байт: case GSPW_GET_STAT_TX_BYTES: PUT_USER( GSPW_GET_STAT_TX_BYTES, pcfg->tx_bytes, arg, __u32) break; // Получение количества ожиданий освобождения DMA передачи: /*case GSPW_GET_STAT_TX_DMA_WAITS: PUT_USER( GSPW_GET_STAT_TX_DMA_WAITS, pcfg->txdma_waits, arg, __u32) break;*/ // Получение таблицы маршрутизации: case GSPW_GET_ROUTE_TABLE: { spw_rt_exch_t *p_rt = (spw_rt_exch_t *)arg; #ifndef USE_FREE_USER_MEM_ACCESS spw_rt_exch_t rt; #endif //- !USE_FREE_USER_MEM_ACCESS int i, j; if( p_rt==NULL) return EINVAL; SET_PNTR( p_rt, rt) COPY_FROM_USER( GSPW_GET_ROUTE_TABLE, &p_rt->rng, (void *)arg, sizeof(p_rt->rng)) if (p_rt->rng.end < p_rt->rng.beg) { ret = -EINVAL; break; } for( i=p_rt->rng.beg, j=0; (i<=p_rt->rng.end); ++i,++j) { p_rt->a_rt[j] = (u16 )GSPW_RT_REG((i<<2)); } if( j) { COPY_TO_USER(GSPW_GET_ROUTE_TABLE, ((spw_rt_exch_t *)arg)->a_rt, p_rt->a_rt, (j * sizeof(p_rt->a_rt[0]))) } break; } // Получение значений RX DMA descriptor регистров: case GSPW_GET_DMA_DESC_RX: { dma_params_t *pdma = (dma_params_t *)arg; #ifndef USE_FREE_USER_MEM_ACCESS dma_params_t dma; #endif //- !USE_FREE_USER_MEM_ACCESS if( pdma==NULL) return EINVAL; SET_PNTR( pdma, dma) val = MC_RUN_GSPW_RX_DES; COPY_TO_USER( GSPW_GET_DMA_DESC_RX, &((dma_params_t *)arg)->run, &val, 4) val = MC_IR_GSPW_RX_DES; COPY_TO_USER( GSPW_GET_DMA_DESC_RX, &((dma_params_t *)arg)->ir, &val, 4) val = MC_CP_GSPW_RX_DES; COPY_TO_USER( GSPW_GET_DMA_DESC_RX, &((dma_params_t *)arg)->cp, &val, 4) break; } // Получение значений RX DMA data регистров: case GSPW_GET_DMA_DATA_RX: { dma_params_t *pdma = (dma_params_t *)arg; #ifndef USE_FREE_USER_MEM_ACCESS dma_params_t dma; #endif //- !USE_FREE_USER_MEM_ACCESS if( pdma==NULL) return EINVAL; SET_PNTR( pdma, dma) val = MC_RUN_GSPW_RX_DAT; COPY_TO_USER( GSPW_GET_DMA_DATA_RX, &((dma_params_t *)arg)->run, &val, 4) val = MC_IR_GSPW_RX_DAT; COPY_TO_USER( GSPW_GET_DMA_DATA_RX, &((dma_params_t *)arg)->ir, &val, 4) val = MC_CP_GSPW_RX_DAT; COPY_TO_USER( GSPW_GET_DMA_DATA_RX, &((dma_params_t *)arg)->cp, &val, 4) break; } // Получение значений TX DMA descriptor регистров: case GSPW_GET_DMA_DESC_TX: { dma_params_t *pdma = (dma_params_t *)arg; #ifndef USE_FREE_USER_MEM_ACCESS dma_params_t dma; #endif //- !USE_FREE_USER_MEM_ACCESS if( pdma==NULL) return EINVAL; SET_PNTR( pdma, dma) val = MC_RUN_GSPW_TX_DES; COPY_TO_USER( GSPW_GET_DMA_DESC_TX, &((dma_params_t *)arg)->run, &val, 4) val = MC_IR_GSPW_TX_DES; COPY_TO_USER( GSPW_GET_DMA_DESC_TX, &((dma_params_t *)arg)->ir, &val, 4) val = MC_CP_GSPW_TX_DES; COPY_TO_USER( GSPW_GET_DMA_DESC_TX, &((dma_params_t *)arg)->cp, &val, 4) break; } // Получение значений TX DMA data регистров: case GSPW_GET_DMA_DATA_TX: { dma_params_t *pdma = (dma_params_t *)arg; #ifndef USE_FREE_USER_MEM_ACCESS dma_params_t dma; #endif //- !USE_FREE_USER_MEM_ACCESS if( pdma==NULL) return EINVAL; SET_PNTR( pdma, dma) val = MC_RUN_GSPW_TX_DAT; COPY_TO_USER( GSPW_GET_DMA_DATA_TX, &((dma_params_t *)arg)->run, &val, 4) val = MC_IR_GSPW_TX_DAT; COPY_TO_USER( GSPW_GET_DMA_DATA_TX, &((dma_params_t *)arg)->ir, &val, 4) val = MC_CP_GSPW_TX_DAT; COPY_TO_USER( GSPW_GET_DMA_DATA_TX, &((dma_params_t *)arg)->cp, &val, 4) break; } // SETs: // Settings: // Установка количества TX DMA дескрипторов: case GSPW_SET_DMA_TX_DESC_QNT: //GET_USER( GSPW_SET_DMA_TX_DESC_QNT, pset->tx.dma.qnt_desc, arg, __u32) pset->tx.dma.qnt_desc = (u32 )arg; break; // Установка количества TX DMA буферов данных: case GSPW_SET_DMA_TX_DATA_QNT: //GET_USER( GSPW_SET_DMA_TX_DATA_QNT, pset->tx.dma.qnt_data, arg, __u32) pset->tx.dma.qnt_data = (u32 )arg; break; // Установка размера TX DMA буфера данных: case GSPW_SET_DMA_TX_DATA_BUF_SIZE: //GET_USER( GSPW_SET_DMA_TX_DATA_BUF_SIZE, pset->tx.dma.sz_data_buf, arg, __u32) pset->tx.dma.sz_data_buf = (u32 )arg; break; // Установка максимального размера TX пакета данных: case GSPW_SET_DMA_TX_PACK_SIZE: //GET_USER( GSPW_SET_DMA_TX_PACK_SIZE, pset->tx.max_sz_pack, arg, __u32) pset->tx.max_sz_pack = (u32 )arg; break; // Установка количества RX DMA дескрипторов: case GSPW_SET_DMA_RX_DESC_QNT: //GET_USER( GSPW_SET_DMA_RX_DESC_QNT, pset->rx.dma.qnt_desc, arg, __u32) pset->rx.dma.qnt_desc = (u32 )arg; break; // Установка количества RX DMA буферов данных: case GSPW_SET_DMA_RX_DATA_QNT: //GET_USER( GSPW_SET_DMA_RX_DATA_QNT, pset->rx.dma.qnt_data, arg, __u32) pset->rx.dma.qnt_data = (u32 )arg; break; // Установка размера RX DMA буфера данных: case GSPW_SET_DMA_RX_DATA_BUF_SIZE: //T_USER( GSPW_SET_DMA_RX_DATA_BUF_SIZE, pset->rx.dma.sz_data_buf, arg, __u32) pset->rx.dma.sz_data_buf = (u32 )arg; break; default: ret = -EINVAL; break; } } else { spw_port = drv_chan_num - 1; pspw = &gspw_sw.a_gspwc[spw_port]; pset_spw = &pset->a_spw[spw_port]; switch (cmd) { // Actions: // GETs: // Получение значения скорости приема: case GSPW_GET_RX_SPEED: //freq_mult_mhz = mc_frequency_multiplier() * MC_QUARTZ_CLOCK_FREQ; //val = ((MC_GSPW_SPW_RX_SPEED(spw_port) * freq_mult_mhz / 1000000) >> 7); val = MC_GSPW_SPW_RX_SPEED( spw_port); PUT_USER( GSPW_GET_RX_SPEED, val, arg, __u32) break; // Получение значения скорости передачи: case GSPW_GET_TX_SPEED: val = ((GSPW_TX_SPEED_REG(spw_port) >> GSPW_TX_SPEED_COEF_OFS) & GSPW_TX_SPEED_COEF_MSK) * 5; PUT_USER( GSPW_GET_TX_SPEED, val, arg, __u32) break; // Получение максимального количества дескрипторов на отправку (по данному порту): case GSPW_GET_MAX_SEND_DESC_QNT: PUT_USER( GSPW_GET_MAX_SEND_DESC_QNT, pspw->max_qnt_send_desc, arg, __u32) break; // GET new: // Получение значения новой скорости передачи: case GSPW_GET_TX_SPEED_NEW: PUT_USER( GSPW_GET_TX_SPEED_NEW, pset_spw->tx_speed, arg, __u32) break; // Получение максимального количества дескрипторов на отправку (по данному порту): case GSPW_GET_MAX_SEND_DESC_QNT_NEW: PUT_USER( GSPW_GET_MAX_SEND_DESC_QNT_NEW, pset_spw->max_qnt_send_desc, arg, __u32) break; // SETs: // Установка максимального количества дескрипторов на отправку (по данному порту): case GSPW_SET_MAX_SEND_DESC_QNT: pset_spw->max_qnt_send_desc = (u32 )arg; //GET_USER( GSPW_GET_MAX_SEND_DESC_QNT, pset->a_spw[spw_port].max_qnt_send_desc, arg, __u32) break; // Установка значения скорости передачи: case GSPW_SET_TX_SPEED: if( arg < 5 || arg > 400) return (-EINVAL); pset_spw->tx_speed = (u32 )arg; //pgsc->speed = arg; //swic_set_tx_speed( spw_port, arg); break; default: ret = -EINVAL; break; } } return ret; }