/* * GigaSpaceWire driver for MC-30SF6EM-6U evaluation kit * * Copyright (c) 2019 Elvees (support@elvees.com) * Author: Dmitry Evtushenko * */ #define MULTICORE_DEBUG #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include #include #include #include #include #include #include #include #include //#include #include #include #include #include "gspwsw.h" #include "func.h" #include "reg.h" #include "irq.h" #include "ctl.h" #include "../ua_mem.h" #ifdef USE_ETHOSPW #include "ethospw.h" #endif //USE_ETHOSPW #define GSPW_SW_MAJOR 251 #ifdef USE_ETHOSPW //#define DEV_NET_NAME "ethospw" #endif //USE_ETHOSPW #define INTF_NAME(is_net) (is_net ? ETHOSPW_DEV_NAME : GSPW_DEV_NAME) #define DEV_NAME GSPW_DEV_NAME // DEBUG: #define DEBUG_DMA_RX_DESC #define DEBUG_DMA_RX_DATA #define DEBUG_DMA_TX_DESC #define DEBUG_DMA_TX_DATA // Макросы для вычисления номеров прерываний //-EDN:#define IRQ_SHIFT 3 //+EDN: #ifdef IRQ_SHIFT #undef IRQ_SHIFT #define IRQ_SHIFT 0//3 //1 #endif //IRQ_SHIFT //#define spw_err_irq( port_id) (IRQ_SPW0 + ((port_id) << IRQ_SHIFT)) //#define spw_time_irq( port_id) (IRQ_SPW0 + ((port_id) << IRQ_SHIFT)) //#define spw_link_irq( port_id) (IRQ_SPW0 + ((port_id) << IRQ_SHIFT)) #define spw_change_state_irq( port_id) (IRQ_SPW0 + ((port_id) << IRQ_SHIFT)) #define spw_rx_data_irq() IRQ_SPW_RX_DAT_CH #define spw_rx_desc_irq() IRQ_SPW_RX_DES_CH #define spw_tx_data_irq() IRQ_SPW_TX_DAT_CH #define spw_tx_desc_irq() IRQ_SPW_TX_DES_CH int is_init_gspwsw = 0; //gspw_t gspw_chan[ NB_OF_CHANNELS]; struct class *p_gspwsw_class; // Класс устройств GSPW switch gspw_switch_t gspw_sw; bool is_init_gspw_switch = 0; int is_init_tx_desc_chain = 0; //////////////////// functions: //////////////////// // timeval to time in mks: static inline u64 get_time_mks( struct timeval *pTv) { //printf( "time: %u %u\n", pTv->tv_sec, pTv->tv_usec); return (1000000LL * pTv->tv_sec) + pTv->tv_usec; } // -> time in mks: static inline u64 get_time_of_day( void) { struct timeval tv; do_gettimeofday( &tv); return get_time_mks( &tv); } //////////////////// gspw_desc_t: //////////////////// void gspw_desc_print( gspw_desc_t *pd) { pr_info("DESC: valid=%i sz=%u type=%i msk=%Xh\n", pd->valid, pd->size, pd->type_ep, pd->port_mask); } //////////////////// dma_desc_fi_t: //////////////////// void dma_desc_fi_print( dma_desc_fi_t *pdd) { gspw_desc_print( &pdd->desc); pr_info(" flag=%Xh\n", pdd->flag); } //////////////////// spw_port_t: //////////////////// static int spw_port__init( spw_port_t *p_port, int port_num, const char *port_name) { memset( p_port, 0, sizeof(*p_port)); if( port_name && *port_name) strncpy( p_port->name, port_name, sizeof(p_port->name)); else snprintf( p_port->name, sizeof(p_port->name), "%s%d", DEV_NAME, port_num); p_port->num = port_num; pr_info( "spw_port__init: p_port->name='%s'\n", p_port->name); return 0; } //////////////////// dma_chain_t: //////////////////// static void *dma_fifo_create_desc( void *pv) { //dma_chain_t *p_dch = (dma_chain_t *)pv; dma_desc_fi_t *pchi; if ((pchi = kcalloc( 1, sizeof(*pchi), GFP_DMA)) == NULL) { pr_info("dma_fifo_create_data: Could not allocate memory for dma_desc_fi_t\n"); return NULL; } pchi->reg_init.ir = mips_virt_to_phys( (unsigned )&pchi->desc); pchi->reg_init.csr = MC_DMA_CSR_IM | MC_DMA_CSR_WN(0) | MC_DMA_CSR_WCX(0) | MC_DMA_CSR_RUN | MC_DMA_CSR_CHEN; //pchi->reg_init.cp = ; return pchi; } static void *dma_fifo_create_data( void *pv) { //dma_data_fi_t *pfi = (dma_data_fi_t *)pv; dma_chain_t *p_dch = (dma_chain_t *)pv; dma_data_fi_t *pchi; if ((pchi = kcalloc( 1, sizeof(*pchi), GFP_DMA)) == NULL) { pr_info("dma_fifo_create_data: Could not allocate memory for dma_data_fi_t\n"); return NULL; } if ((pchi->p_buf = kcalloc( p_dch->sz_data_buf, 1, GFP_DMA)) == NULL) { pr_info("dma_fifo_create_data: Could not allocate memory for data buffer\n"); kfree( pchi); return NULL; } return pchi; } static void dma_fifo_delete_data( void *pi) { dma_data_fi_t *pfi = (dma_data_fi_t *)pi; if( pfi->p_buf) kfree( pfi->p_buf); kfree( pfi); } static int dma_chain_init( dma_chain_t *p_dch, u32 qnt, u32 szi, u32 sz_data_buf, pf_create_fitem_t pf_create, pf_delete_fitem_t pf_delete) { bool rc; memset( p_dch, 0, sizeof(*p_dch)); p_dch->qnt = qnt; p_dch->szi = szi; p_dch->sz_data_buf = sz_data_buf; rc = fifo_init( &p_dch->ff, qnt, szi, pf_create, p_dch, pf_delete, FIFO_OPT__DOUBLE_LINK/*FIFO_OPT__NONE*/); if (!rc) { pr_info("dma_chain_init: fifo_init: Could not allocate memory\n"); return -ENOMEM; } /*p_dch->pa_dma_reg_init = (dma_params_t *)kcalloc( sz_dch, sizeof(dma_params_t)); if( p_dch->pa_dma_reg_init == NULL) { pr_info("dma_chain_init: kcalloc: Could not allocate memory\n"); fifo_free( &p_dch->ff); return false; }*/ return RC_SPW_SUCCESS; } /*bool dma_chain_create_data_bufs( dma_chain_t *p_dch, u32 sz_buf) { fifo_t *pff = &p_dch->ff; dma_data_fi_t *pfi = (dma_data_fi_t *)pff->p_begin; p_dch->sz_data_buf = sz_buf; for( ; (pfi); pfi = pfi->p_next) { if( pfi->p_buf) kfree( pfi->p_buf); if ((pfi->p_buf = kcalloc(sz_buf, 1)) == NULL) { for( pfi=(dma_data_fi_t *)pff->p_begin; (pfi); pfi = pfi->p_next) { if( pfi->p_buf) kfree( pfi->p_buf); } pr_info("dma_chain_init_data_bufs: kcalloc: Could not allocate memory\n"); return false; } } return true; }*/ #if 0 static void dma_chain_free( dma_chain_t *p_dch) { //if( p_dch->pa_dma_reg_init) // kfree( p_dch->pa_dma_reg_init); fifo_free( &p_dch->ff); } #endif //0 //////////////////// dma_tx_job_t: //////////////////// //////////////////// gspw_ctrl_t: //////////////////// static int gspw_ctrl_init_struct( gspw_ctrl_t *pctl); static int gspw_ctrl__init( gspw_ctrl_t *pctl, int port_num) { pr_info( "gspw_ctrl__init: %d\n", port_num); memset( pctl, 0, sizeof(*pctl)); spw_port__init( &pctl->port, port_num, NULL); //pctl->speed = CONFIG_MULTICORE_GSPW_SW_DEF_WORK_SPEED; pctl->speed = 400; //50; //240; //400; #ifdef USE_ETHOSPW mutex_init( &pctl->mtx_rx); #endif //USE_ETHOSPW return gspw_ctrl_init_struct( pctl); } static void gspw_ctrl__exit( gspw_ctrl_t *pctl) { #ifdef USE_ETHOSPW mutex_destroy( &pctl->mtx_rx); #endif //USE_ETHOSPW } static void gspw_ctrl_stop( gspw_ctrl_t *pctl) { PDEBUGG( "gspw_ctrl_stop: chan %d\n", pctl->port.num); GSPW_MODE_REG( pctl->port.num) = GSPW_MODE_LINK_DISA | GSPW_MODE_BDS_RST; } static void gspw_ctrl_start( gspw_ctrl_t *pctl) { u32 speed; u32 k10 = XTI125_FREQ / 10; pr_info("gspw_ctrl_start: %u '%s'\n", pctl->port.num, pctl->port.name); // Сброс контроллера: GSPW_MODE_REG( pctl->port.num) = GSPW_MODE_BDS_RST | GSPW_MODE_LINK_DISA | GSPW_MODE_CODEC_LOOPB | GSPW_MODE_LVDS_LOOPB; //- +EDN // Начальные установки и пуск: speed = MC_SWIC_TX_SPEED_PRM( CONFIG_MULTICORE_GSPW_SW_START_SPEED / 5); GSPW_TX_SPEED_REG( pctl->port.num) = ((speed & GSPW_TX_SPEED_COEF_MSK) << GSPW_TX_SPEED_COEF_OFS) | GSPW_TX_SPEED_PLL_TX_ENA | GSPW_TX_SPEED_LVDS_ENA /*| GSPW_TX_SPEED_PLL_TX_ENA_10 | GSPW_TX_SPEED_LVDS_ENA_10 | //+EDN ((0x02 & GSPW_TX_SPEED_10MB_COEF_MSK) << GSPW_TX_SPEED_10MB_COEF_OFS)*/; //+EDN GSPW_MODE_REG( pctl->port.num) = GSPW_MODE_AUTOSTART | GSPW_MODE_LINKSTART | ((k10 & GSPW_MODE_K10_LOCAL_MSK) << GSPW_MODE_K10_LOCAL_OFS); //GSPW_MODE_AUTO_SPEED //mdelay (20); PDEBUG( "gspw_ctrl_start: TX_SPEED(%d) = %08X\n", pctl->port.num, GSPW_TX_SPEED_REG( pctl->port.num)); // Сброс всех признаков прерываний //-EDN: MC_SWIC_STATUS( pctl->port.num) = SWIC_RESET_ALL_IRQS; GSPW_SPW_STAT_REG( pctl->port.num) = GSPW_SPW_STAT_ALL_ERRS; // Сброс счетчиков принятых пакетов //-EDN: MC_SWIC_CNT_RX_PACK(u->port) = 0; //-EDN: MC_SWIC_CNT_RX0_PACK(u->port) = 0; //mdelay( 1000); pctl->cnt_int_con = 0; pr_info( "gspw_ctrl_start: SPW_STAT(%i)=%Xh\n", pctl->port.num, GSPW_SPW_STAT_REG(pctl->port.num)); } static inline void set_dflt_dma_desc( dma_desc_fi_t *pd #if defined(DEBUG_DMA_RX_DESC) || defined(DEBUG_DMA_TX_DESC) , int ind #endif ) { dma_params_t *pdr = &pd->reg_init; pdr->ir = mips_virt_to_phys( (unsigned )&pd->desc); pdr->csr = MC_DMA_CSR_IM | MC_DMA_CSR_WN(0) | MC_DMA_CSR_RUN | MC_DMA_CSR_WCX(0) | MC_DMA_CSR_CHEN; pdr->cp = mips_virt_to_phys( (unsigned )&pd->p_next->reg_init); #if defined(DEBUG_DMA_RX_DESC) || defined(DEBUG_DMA_TX_DESC) pr_info("%i) IR=%Xh, CSR=%Xh, CP=%Xh\n", ind, pdr->ir, pdr->csr, pdr->cp); #endif } static inline void set_dflt_dma_data( dma_data_fi_t *pd, u32 sz_data_buf #if defined(DEBUG_DMA_RX_DATA) || defined(DEBUG_DMA_TX_DATA) , int ind) #endif { dma_params_t *pdr = &pd->reg_init; pdr->ir = mips_virt_to_phys( (unsigned )pd->p_buf); pdr->csr = MC_DMA_CSR_IM | MC_DMA_CSR_WN(0) | MC_DMA_CSR_RUN | MC_DMA_CSR_WCX( (sz_data_buf >> 3) - 1) | MC_DMA_CSR_CHEN /*| MC_DMA_CSR_END | MC_DMA_CSR_DONE*/; pdr->cp = mips_virt_to_phys((unsigned)&pd->p_next->reg_init); //pr_info("%i) IR=%Xh, CSR=%Xh, CP=%Xh\n", ind, pdr->ir, pdr->csr, pdr->cp); #if defined(DEBUG_DMA_RX_DATA) || defined(DEBUG_DMA_TX_DATA) pr_info("%i) IR=%Xh, CSR=%Xh, CP=%Xh\n", ind, pdr->ir, pdr->csr, pdr->cp); #endif //defined(DEBUG_DMA_RX_DATA) || defined(DEBUG_DMA_TX_DATA) } static void dma_rx_desc_chain_set_dflt( dma_chain_t *pch) { dma_desc_fi_t *pd, *pd_beg; int i=0; pr_info("RX_DESC:\n"); pd_beg = (dma_desc_fi_t *)pch->ff.p_begin; for( pd=pd_beg; pd; pd=pd->p_next) { /* if( pd->p_next == pd_beg) pd->reg_init.csr &= ~MC_DMA_CSR_RUN; set_dflt_dma_desc( pd, i++); //pr_info(" dsc=%Xh ir=%Xh csr=%Xh cp=%Xh\n", (unsigned )&pd->desc, pdr->ir, pdr->csr, pdr->cp); if( pd->p_next == pd_beg) break; */ //!! CHECK and COMMIT this !!! : set_dflt_dma_desc( pd, i++); //pr_info(" dsc=%Xh ir=%Xh csr=%Xh cp=%Xh\n", (unsigned )&pd->desc, pdr->ir, pdr->csr, pdr->cp); if( pd->p_next == pd_beg) { pd->reg_init.csr &= ~MC_DMA_CSR_RUN; break; } } /*#ifdef DEBUG_DMA_RX_DESC { int i=0; dma_params_t *pdr; pr_info("RX_DESC:\n"); for( pd=pd_beg; pd; pd=pd->p_next,++i) { pdr = &pd->reg_init; pr_info("%i) CP=%Xh, IR=%Xh, CSR=%Xh\n", i, pdr->cp, pdr->ir, pdr->csr); if( pd->p_next == pd_beg) break; } } #endif //DEBUG_DMA_RX_DESC*/ } static int dma_rx_desc_chain_init( gspw_cfg_ctrl_t *pcfg, const u32 MAX_RX_DESC_QNT) { int rc; dma_chain_t *pch = &pcfg->dch_rx_desc; pr_info("dma_rx_desc_chain_init:\n"); rc = dma_chain_init( pch, MAX_RX_DESC_QNT, sizeof(dma_desc_fi_t), sizeof(gspw_desc_t), &dma_fifo_create_desc, NULL); if( rc != RC_SPW_SUCCESS) return rc; dma_rx_desc_chain_set_dflt( pch); return RC_SPW_SUCCESS; } static void dma_rx_data_chain_set_dflt( dma_chain_t *pch) { dma_data_fi_t *pd, *pd_beg; int i=0; pr_info("RX_DATA:\n"); pd_beg = (dma_data_fi_t *)pch->ff.p_begin; for( pd=pd_beg; pd; pd=pd->p_next) { if( pd->p_next == pd_beg) pd->reg_init.csr &= ~MC_DMA_CSR_RUN; set_dflt_dma_data( pd, pch->sz_data_buf, i++); if( pd->p_next == pd_beg) break; } /*#ifdef DEBUG_DMA_RX_DATA { int i=0; dma_params_t *pdr; pr_info("RX_DATA:\n"); for( pd=pd_beg; pd; pd=pd->p_next,++i) { pdr = &pd->reg_init; pr_info("%i) CP=%Xh, IR=%Xh, CSR=%Xh\n", i, pdr->cp, pdr->ir, pdr->csr); if( pd->p_next == pd_beg) break; } } #endif //DEBUG_DMA_RX_DATA */ } static int dma_rx_data_chain_init( gspw_cfg_ctrl_t *pcfg, const u32 qnt_data_buf, const u32 sz_data_buf) { int rc; dma_chain_t *pch = &pcfg->dch_rx_data; pr_info("dma_rx_data_chain_init:\n"); rc = dma_chain_init( pch, qnt_data_buf, sizeof(dma_data_fi_t), sz_data_buf, &dma_fifo_create_data, &dma_fifo_delete_data); if( rc != RC_SPW_SUCCESS) return rc; dma_rx_data_chain_set_dflt( pch); return RC_SPW_SUCCESS; } static void dma_tx_desc_chain_set_dflt( dma_chain_t *pch) { dma_desc_fi_t *pd, *pd_beg; int i=0; pr_info("TX_DESC:\n"); pd_beg = (dma_desc_fi_t *)pch->ff.p_begin; for( pd=pd_beg; pd; pd=pd->p_next) { set_dflt_dma_desc( pd, i++); //pr_info(" dsc=%Xh ir=%Xh csr=%Xh cp=%Xh\n", (unsigned )&pd->desc, pdr->ir, pdr->csr, pdr->cp); if( pd->p_next == pd_beg) { //pdr->csr &= ~MC_DMA_CSR_CHEN; break; } } /*#ifdef DEBUG_DMA_TX_DESC { int i=0; dma_params_t *pdr; pr_info("TX_DESC:\n"); for( pd=pd_beg; pd; pd=pd->p_next,++i) { pdr = &pd->reg_init; pr_info("%i) CP=%Xh, IR=%Xh, CSR=%Xh\n", i, pdr->cp, pdr->ir, pdr->csr); if( pd->p_next == pd_beg) break; } } #endif //DEBUG_DMA_TX_DESC*/ } static int dma_tx_desc_chain_init( gspw_cfg_ctrl_t *pcfg, const u32 MAX_TX_DESC_QNT) { int rc; dma_chain_t *pch = &pcfg->dch_tx_desc; pr_info("dma_tx_desc_chain_init:\n"); rc = dma_chain_init( pch, MAX_TX_DESC_QNT, sizeof(dma_desc_fi_t), sizeof(gspw_desc_t), &dma_fifo_create_desc, NULL); if( rc != RC_SPW_SUCCESS) return rc; dma_tx_desc_chain_set_dflt( pch); return RC_SPW_SUCCESS; } static void dma_tx_data_chain_set_dflt( dma_chain_t *pch) { dma_data_fi_t *pd, *pd_beg; int i=0; pr_info("TX_DATA:\n"); pd_beg = (dma_data_fi_t *)pch->ff.p_begin; for (pd=pd_beg; pd; pd=pd->p_next) { set_dflt_dma_data( pd, pch->sz_data_buf, i++); /*pdr->ir = mips_virt_to_phys( (unsigned )pd->p_buf); pdr->csr = MC_DMA_CSR_IM | MC_DMA_CSR_WN(0) | MC_DMA_CSR_RUN | MC_DMA_CSR_WCX(0) | MC_DMA_CSR_CHEN; //| MC_DMA_CSR_END | MC_DMA_CSR_DONE | MC_DMA_CSR_WCX((pch->sz_data_buf >> 3) - 1) pdr->cp = mips_virt_to_phys((unsigned)&pd->p_next->reg_init);*/ if( pd->p_next == pd_beg) break; } /*#ifdef DEBUG_DMA_TX_DATA { int i=0; dma_params_t *pdr; pr_info("TX_DATA:\n"); for( pd=pd_beg; pd; pd=pd->p_next,++i) { pdr = &pd->reg_init; pr_info("%i) CP=%Xh, IR=%Xh, CSR=%Xh\n", i, pdr->cp, pdr->ir, pdr->csr); if( pd->p_next == pd_beg) break; } } #endif //DEBUG_DMA_TX_DATA*/ } static int dma_tx_data_chain_init( gspw_cfg_ctrl_t *pcfg, const u32 qnt_data_buf, const u32 sz_data_buf) { int rc; dma_chain_t *pch = &pcfg->dch_tx_data; pr_info("dma_tx_data_chain_init:\n"); rc = dma_chain_init( pch, qnt_data_buf, sizeof(dma_data_fi_t), sz_data_buf, &dma_fifo_create_data, &dma_fifo_delete_data); if( rc != RC_SPW_SUCCESS) return rc; dma_tx_data_chain_set_dflt( pch); return RC_SPW_SUCCESS; } int thread_dma_tx_job( void *pv); static int gspw_ctrl_init_struct( gspw_ctrl_t *pspw) { init_waitqueue_head( &pspw->wq_rx); pspw->max_qnt_send_desc = 12; //2; //MAX_TX_DESC_QNT / 3; #if 0 int rc; PDEBUG( "gspw_struct_init: port=%d\n", pctl->port.num); //memset( pctl, 0, sizeof(*pctl)); // RX: pctl->qnt_rx_desc = 12; //10; pctl->qnt_rx_data = 12; //5; pctl->sz_rx_data_buf = SPW_RX_DATA_BUF_SIZE; if( (rc=dma_rx_desc_chain_init( pctl, pctl->qnt_rx_desc))) return rc; if( (rc=dma_rx_data_chain_init( pctl, pctl->qnt_rx_data, pctl->sz_rx_data_buf))) return rc; // TX: pctl->qnt_tx_desc = 12; //10; pctl->qnt_tx_data = 12; //5; pctl->sz_tx_data_buf = SPW_TX_DATA_BUF_SIZE; if( (rc=dma_tx_desc_chain_init( pctl, pctl->qnt_tx_desc))) return rc; if( (rc=dma_tx_data_chain_init( pctl, pctl->qnt_tx_data, pctl->sz_tx_data_buf))) return rc; rc = fifo_init( &pctl->ff_tx_job, pctl->qnt_tx_desc, sizeof(dma_tx_job_t), NULL, NULL, NULL, FIFO_OPT__DOUBLE_LINK); if (!rc) { pr_info("gspw_cfg_ctrl_init_struct: Could not allocate memory for tx job list\n"); return ENOMEM; } //pctl->p_cur_tx_job = NULL; pctl->max_qnt_send_desc = 12; //2; //MAX_TX_DESC_QNT / 3; pctl->max_sz_tx_pack = 0x10000; //(4096 * 8); //0x20000; //131072 //(4096 * 8); init_waitqueue_head( &pctl->wq_st); init_waitqueue_head( &pctl->wq_rx); init_waitqueue_head( &pctl->wq_txdesc); init_waitqueue_head( &pctl->wq_txdata); init_waitqueue_head( &pctl->wq_txjob); #ifdef USE_DMA_TEST dma_test_init( &pctl->test); #endif //USE_DMA_TEST if( (pctl->p_task_tx_dma_job = kthread_run( &thread_dma_tx_job, pctl, "gspw__dma_tx_job"))==NULL ) { if( IS_ERR( pctl->p_task_tx_dma_job)) { pr_info( "Could not create 'gspw__dma_tx_job' thread\n"); return ENOMEM; } } #endif //0 return RC_SPW_SUCCESS; } //////////////////// gspw_cfg_ctrl_t: //////////////////// static int gspw_cfg_ctrl_init_struct( gspw_cfg_ctrl_t *pcfg); int gspw_cfg_ctrl__init( gspw_cfg_ctrl_t *pcfg) { pr_info( "gspw_cfg_ctrl__init:\n"); memset( pcfg, 0, sizeof(*pcfg)); snprintf( pcfg->port.name, sizeof(pcfg->port.name), "gspw0"); pcfg->port.num = 0; pcfg->qnt_rx_desc = 12; //10; pcfg->qnt_rx_data = 12; //5; pcfg->sz_rx_data_buf = SPW_RX_DATA_BUF_SIZE; pcfg->qnt_tx_desc = 12; //10; pcfg->qnt_tx_data = 12; //5; pcfg->sz_tx_data_buf = SPW_TX_DATA_BUF_SIZE; pcfg->max_sz_tx_pack = 0x10000; //(4096 * 8); //0x20000; //131072 //(4096 * 8); return gspw_cfg_ctrl_init_struct( pcfg); } void dma_rx_chain_free( gspw_cfg_ctrl_t *pcfg) { fifo_free( &pcfg->dch_rx_desc.ff); fifo_free( &pcfg->dch_rx_data.ff); } void dma_tx_chain_free( gspw_cfg_ctrl_t *pcfg) { int rc; //TODO: soft stop needs !!! if( pcfg->p_task_tx_dma_job) { if( (rc = kthread_stop( pcfg->p_task_tx_dma_job)) < 0) { pr_info( "dma_tx_chain_free: kthread_stop ERROR(%u)\n", rc); } } fifo_free( &pcfg->ff_tx_job); fifo_free( &pcfg->dch_tx_desc.ff); fifo_free( &pcfg->dch_tx_data.ff); } void gspw_cfg_ctrl_free( gspw_cfg_ctrl_t *pcfg) { dma_rx_chain_free( pcfg); dma_tx_chain_free( pcfg); } static void gspw_cfg_ctrl_stop( gspw_cfg_ctrl_t *pcfg) { PDEBUG( "gspw_cfg_ctrl_stop:\n"); MC_RUN_GSPW_RX_DAT = 0; MC_RUN_GSPW_RX_DES = 0; MC_RUN_GSPW_TX_DAT = 0; MC_RUN_GSPW_TX_DES = 0; } static void gspw_cfg_ctrl_start( gspw_cfg_ctrl_t *pcfg) { u32 k10 = XTI125_FREQ / 10; // Включение частоты MC_CLKEN |= MC_CLKEN_GSpWR; // Сброс контроллера //-EDN: ???: MC_SWIC_MODE_CR( pgsc->port) = SWIC_RESET; // Запись тайминга для того, чтобы SWIC отрабатывал временные интер- // валы в соответствии со стандартом SpaceWire //MC_SWIC_MODE_CR(u->port) = MC_SWIC_TIMING_WR_EN; //MC_SWIC_TX_SPEED(u->port) = MC_SWIC_TIMING(KHZ/10000); //-EDN: ???: MC_SWIC_MODE_CR(u->port) = SWIC_START; GSPW_MOD_REG = GSPW_MOD_GIGASPWR_WE | GSPW_MOD_DMA_ENA | ((k10 & GSPW_MOD_KOEFF10_MSK) << GSPW_MOD_KOEFF10_OFS); //WORK_EN | DMA_EN| coef_10 // Начальные установки и пуск //-EDN: ???: MC_SWIC_TX_SPEED(u->port) = MC_SWIC_TX_SPEED_PRM(CONFIG_MULTICORE_GSPW_SW_START_SPEED / 5) | MC_SWIC_PLL_TX_EN | MC_SWIC_LVDS_EN; //MC_SWIC_TX_SPEED(u->port) = MC_SWIC_TX_SPEED_CON(SPW_START_SPEED / 5) | // MC_SWIC_TX_SPEED_PRM(u->speed / 5) | MC_SWIC_PLL_TX_EN | MC_SWIC_LVDS_EN; //mdelay (20); //-EDN: ???: PDEBUG ("TX_SPEED(%d) = %08X\n", u->port, MC_SWIC_TX_SPEED(u->port)); //-EDN: ???: MC_SWIC_MODE_CR(u->port) = MC_SWIC_LinkStart | MC_SWIC_AutoStart | //-EDN: ???: MC_SWIC_WORK_TYPE | MC_SWIC_LINK_MASK; //MC_SWIC_MODE_CR(u->port) = MC_SWIC_LinkStart | MC_SWIC_AutoStart | // MC_SWIC_WORK_TYPE | MC_SWIC_LINK_MASK | MC_SWIC_AUTO_TX_SPEED; // Сброс всех признаков прерываний //-EDN: ???: MC_SWIC_STATUS(u->port) = SWIC_RESET_ALL_IRQS; /*pr_info( "gspw_cfg_ctrl_start: SYS_IRQ_MSK0_REG=%Xh, SYS_IRQ_REQ0_REG=%Xh\n", SYS_IRQ_MSK0_REG, SYS_IRQ_REQ0_REG); SYS_IRQ_MSK0_REG = (SYS_IRQ_MSK0_REG & ~(SYS_IRQ_GSPW_RX_TX_MSK << SYS_IRQ_GSPW_RX_TX_OFS)); SYS_IRQ_MSK0_REG = (SYS_IRQ_MSK0_REG & ~(SYS_IRQ_GSPW_MSK << SYS_IRQ_GSPW_OFS)); SYS_IRQ_REQ0_REG = (SYS_IRQ_REQ0_REG & ~(SYS_IRQ_GSPW_RX_TX_MSK << SYS_IRQ_GSPW_RX_TX_OFS)); SYS_IRQ_REQ0_REG = (SYS_IRQ_REQ0_REG & ~(SYS_IRQ_GSPW_MSK << SYS_IRQ_GSPW_OFS)); pr_info( "gspw_cfg_ctrl_start: SYS_IRQ_MSK0_REG=%Xh, SYS_IRQ_REQ0_REG=%Xh\n", SYS_IRQ_MSK0_REG, SYS_IRQ_REQ0_REG); */ /*pr_info( "drv_gspw_open: SYS_IRQ_MSK0_REG=%Xh, SYS_IRQ_REQ0_REG=%Xh\n", SYS_IRQ_MSK0_REG, SYS_IRQ_REQ0_REG); SYS_IRQ_MSK0_REG &= ~(SYS_IRQ_GSPW_MSK << SYS_IRQ_GSPW_OFS); SYS_IRQ_MSK0_REG |= (SYS_IRQ_GSPW_MSK << SYS_IRQ_GSPW_OFS); SYS_IRQ_REQ0_REG &= ~(SYS_IRQ_GSPW_MSK << SYS_IRQ_GSPW_OFS); SYS_IRQ_REQ0_REG |= (SYS_IRQ_GSPW_MSK << SYS_IRQ_GSPW_OFS); pr_info( "drv_gspw_open: SYS_IRQ_MSK0_REG=%Xh, SYS_IRQ_REQ0_REG=%Xh\n", SYS_IRQ_MSK0_REG, SYS_IRQ_REQ0_REG); */ // Сброс счетчиков принятых пакетов //-EDN: ???: MC_SWIC_CNT_RX_PACK(u->port) = 0; //-EDN: ???: MC_SWIC_CNT_RX0_PACK(u->port) = 0; } int dma_rx_chain_init( gspw_cfg_ctrl_t *pcfg) { int rc; if( (rc=dma_rx_desc_chain_init( pcfg, pcfg->qnt_rx_desc)) != RC_SPW_SUCCESS) return rc; init_dma_rx_desk_chain_reg( pcfg); if( (rc=dma_rx_data_chain_init( pcfg, pcfg->qnt_rx_data, pcfg->sz_rx_data_buf)) != RC_SPW_SUCCESS) return rc; init_dma_rx_data_chain_reg( pcfg); return RC_SPW_SUCCESS; } int dma_tx_chain_init( gspw_cfg_ctrl_t *pcfg) { int rc; if( (rc=dma_tx_desc_chain_init( pcfg, pcfg->qnt_tx_desc))) return rc; if( (rc=dma_tx_data_chain_init( pcfg, pcfg->qnt_tx_data, pcfg->sz_tx_data_buf))) return rc; rc = fifo_init( &pcfg->ff_tx_job, pcfg->qnt_tx_desc, sizeof(dma_tx_job_t), NULL, NULL, NULL, FIFO_OPT__DOUBLE_LINK); if (!rc) { pr_info("dma_tx_chain_init: Could not allocate memory for tx job list\n"); return -ENOMEM; } //pcfg->p_cur_tx_job = NULL; return RC_SPW_SUCCESS; } int gspw_cfg_ctrl_init_job_task( gspw_cfg_ctrl_t *pcfg) { if( (pcfg->p_task_tx_dma_job = kthread_run( &thread_dma_tx_job, pcfg, "gspw__dma_tx_job"))==NULL ) { if( IS_ERR( pcfg->p_task_tx_dma_job)) { pr_info( "Could not create 'gspw__dma_tx_job' thread\n"); return -ENOMEM; } } return RC_SPW_SUCCESS; } static int gspw_cfg_ctrl_init_struct( gspw_cfg_ctrl_t *pcfg) { #if 1 int rc; PDEBUG( "gspw_cfg_ctrl_init_struct: port=%d\n", pcfg->port.num); //memset( pcfg, 0, sizeof(*pcfg)); //init_completion( &pcfg->compl_tx); //mutex_init( &pcfg->mut_tx); // RX: if( (rc=dma_rx_chain_init( pcfg)) != RC_SPW_SUCCESS) return rc; // TX: if( (rc=dma_tx_chain_init( pcfg)) != RC_SPW_SUCCESS) 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); #ifdef USE_DMA_TEST dma_test_init( &pcfg->test); #endif //USE_DMA_TEST if( (rc=gspw_cfg_ctrl_init_job_task( pcfg)) != RC_SPW_SUCCESS) return rc; #endif //1 return RC_SPW_SUCCESS; } void print_fifo_held_qnt( gspw_cfg_ctrl_t *pcfg, const char *psMes) { PRINT( "%s: fifo_qnt: job=%u, tx= %u %u, rx= %u %u\n", psMes, fifo_get_held_qnt( &pcfg->ff_tx_job), fifo_get_held_qnt( &pcfg->dch_tx_desc.ff), fifo_get_held_qnt( &pcfg->dch_tx_data.ff), fifo_get_held_qnt( &pcfg->dch_rx_desc.ff), fifo_get_held_qnt( &pcfg->dch_rx_data.ff)); } void init_dma_rx_desk_chain_reg( gspw_cfg_ctrl_t *pcfg) { fifo_t *pff = &pcfg->dch_rx_desc.ff; dma_desc_fi_t *p_desc; if( (p_desc = (dma_desc_fi_t *)fifo_get_first_free( pff)) ) { MC_CP_GSPW_RX_DES = mips_virt_to_phys( (unsigned )&p_desc->reg_init) | 1; pr_info("FF: RX_DESC: CP=%Xh, IR=%Xh, CSR=%Xh\n", p_desc->reg_init.cp, p_desc->reg_init.ir, p_desc->reg_init.csr); //pr_info("RX_DESC: CP=%Xh, IR=%Xh, CSR=%Xh\n", SWIC_DMA_CP( SWIC_RX_DESC_CHAN), // SWIC_DMA_IR( SWIC_RX_DESC_CHAN), SWIC_DMA_CSR( SWIC_RX_DESC_CHAN)); } } void init_dma_rx_data_chain_reg( gspw_cfg_ctrl_t *pcfg) { fifo_t *pff = &pcfg->dch_rx_data.ff; dma_data_fi_t *p_data; if( (p_data = (dma_data_fi_t *)fifo_get_first_free( pff)) ) { MC_CP_GSPW_RX_DAT = mips_virt_to_phys( (unsigned )&p_data->reg_init) | 1; pr_info("FF: RX_DATA: CP=%Xh, IR=%Xh, CSR=%Xh\n", p_data->reg_init.cp, p_data->reg_init.ir, p_data->reg_init.csr); //pr_info("RX_DATA: CP=%Xh, IR=%Xh, CSR=%Xh\n", SWIC_DMA_CP( SWIC_RX_DATA_CHAN), // SWIC_DMA_IR( SWIC_RX_DATA_CHAN), SWIC_DMA_CSR( SWIC_RX_DATA_CHAN)); } } //////////////////// spw_routing_t: //////////////////// static int spw_routing__init( spw_routing_t *prt) { int i; //u32 rt; pr_info( "spw_routing__init:\n"); // routing table preparing: memset( prt->a_rt, 0, sizeof(prt->a_rt)); //return 0; //- empty routing table // track routing: /* prt->a_rt[GSPW_PACK_PORT_IN_CFG] = GSPW_RT_SEND_CFG_PORT | GSPW_RT_DIV_HDR; prt->a_rt[GSPW_PACK_PORT_IN_SWIC0] = (GSPW_PACK_PORT_IN_SWIC0 << GSPW_RT_SEND_SPW_PORT_OFS) | GSPW_RT_DIV_HDR; prt->a_rt[GSPW_PACK_PORT_IN_SWIC1] = (GSPW_PACK_PORT_IN_SWIC1 << GSPW_RT_SEND_SPW_PORT_OFS) | GSPW_RT_DIV_HDR; */ // logic routing - all packet direct to cfg port with header division: for( i=0/*SPW_RT_LOGIC_ADDR_FIRST*/; (i <= SPW_RT_LOGIC_ADDR_LAST); ++i) { prt->a_rt[i] = GSPW_RT_SEND_CFG_PORT | GSPW_RT_PACK_PRIOR; // | GSPW_RT_VALID_STRING; // | GSPW_RT_ADAPT_ROUTE; //| GSPW_RT_DIV_HDR; //prt->a_rt[i] = ((1 & GSPW_RT_SEND_GSPW_PORT_MSK) << GSPW_RT_SEND_GSPW_PORT_OFS) | // GSPW_RT_PACK_PRIOR | GSPW_RT_VALID_STRING | GSPW_RT_ADAPT_ROUTE; } // init routing table: for( i=0; (i < SPW_RT_TABLE_SIZE); ++i) { //rt = (u32 )prt->a_rt[i]; GSPW_RT_REG((i<<2)) = (u32 )prt->a_rt[i]; } /*i = 33; v = (u32 )prt->a_rt[i]; GSPW_RT_REG(i) = (u32 )v; pr_info( "spw_routing__init: rt[%i]=%Xh %Xh addr=%Xh\n", i, GSPW_RT_REG(i), prt->a_rt[i], MC_A( GSPW_ADDR_OFS | 0x400 | i));*/ //for( i=SPW_RT_LOGIC_ADDR_FIRST; (i < SPW_RT_LOGIC_ADDR_FIRST+10); ++i) // pr_info( "spw_routing__init: rt[%i]=%Xh %Xh addr=%Xh\n", i, GSPW_RT_REG((i<<2)), prt->a_rt[i], MC_A( GSPW_ADDR_OFS | 0x400 | (i<<2))); //ADG init: GSPW_ADG_REG( 0) = GSPW_PACK_PORT_OUT_SWIC0; // | GSPW_PACK_PORT_OUT_SWIC1; GSPW_ADG_REG( 1) = GSPW_PACK_PORT_OUT_SWIC1; // | GSPW_PACK_PORT_OUT_SWIC0; return RC_SPW_SUCCESS; } //////////////////// gspw_switch_t: //////////////////// static void gspw_sw__giga_init( void); static int gspw_sw__init( gspw_switch_t *p_sw) { int rc; int i; if( p_sw==NULL) { PDEBUGG ("gspw_switch__init: ERROR: Main GigaSpaceWire switch object is empty\n"); return -EINVAL; } memset( p_sw, 0, sizeof(*p_sw)); snprintf( p_sw->name, sizeof(p_sw->name), "%s", DEV_NAME); if( !is_init_gspw_switch) gspw_sw__giga_init(); mutex_init( &p_sw->mtx_tx); if( (rc=gspw_cfg_ctrl__init( &p_sw->cfg_ctrl)) ) return rc; spw_routing__init( &p_sw->rt); for( i=0; (i < MAX_SPW_PORT_QNT) ;++i) gspw_ctrl__init( &p_sw->a_gspwc[i], /*GSPW_FIRST_SPW_PORT_NUM+*/ i); //for( i=0; (i < MAX_GSPW_PORT_QNT) ;++i) // gspw_ctrl__init( &p_sw->a_gspwc[i], i); gspw_sw_set_settings(); return RC_SPW_SUCCESS; } static int gspw_sw__exit( gspw_switch_t *p_sw) { mutex_destroy( &p_sw->mtx_tx); } static void gspw_sw__giga_init( void) { unsigned int tmp_RISK_IRQ_MASK = 0; pr_info( "gspw_sw__giga_init:\n"); tmp_RISK_IRQ_MASK = GSPW_RISC_IRQ_MSK_REG; *((volatile unsigned int *) 0xB82FA0C4) = 0x1D08; *((volatile unsigned int *) 0xB82FA114) = 0x128294; *((volatile unsigned int *) 0xB82FA0AC) = 0x02C83414; *((volatile unsigned int *) 0xB82FA0C8) = 0x1D08; *((volatile unsigned int *) 0xB82FA118) = 0x128294; *((volatile unsigned int *) 0xB82FA0B0) = 0x02C83414; *((volatile unsigned int *) 0xB82FA0CC) = 0x1D08; *((volatile unsigned int *) 0xB82FA11C) = 0x128294; *((volatile unsigned int *) 0xB82FA0B4) = 0x02C83414; *((volatile unsigned int *) 0xB82FA0D0) = 0x1D08; *((volatile unsigned int *) 0xB82FA120) = 0x128294; *((volatile unsigned int *) 0xB82FA0B8) = 0x02C83414; // ожидаем соединения от всех 4-х портов GigaSpWR: // TODO: мож. быть зависание !!! : while( (GSPW_STATE_REG & GSPW_STATE_GIGA_CON_MSK) != GSPW_STATE_GIGA_CON_MSK ) mdelay( 100); GSPW_STATE_REG = GSPW_STATE_GIGA_CON_MSK; //- 0x00780000 //*((volatile unsigned int *) 0xB82FA024) = 0xFFF; GSPW_STATE_CON_REG = 0xFFF; GSPW_RISC_IRQ_MSK_REG = tmp_RISK_IRQ_MASK; } void gspw_sw_set_settings( 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; ps->tx.dma.qnt_desc = pcfg->qnt_tx_desc; ps->tx.dma.qnt_data = pcfg->qnt_tx_data; ps->tx.dma.sz_data_buf = pcfg->sz_tx_data_buf; ps->tx.max_sz_pack = pcfg->max_sz_tx_pack; ps->rx.dma.qnt_desc = pcfg->qnt_rx_desc; ps->rx.dma.qnt_data = pcfg->qnt_rx_data; ps->rx.dma.sz_data_buf = pcfg->sz_rx_data_buf; for(i=0; (i < MAX_SPW_PORT_QNT); ++i) { pspw = &gspw_sw.a_gspwc[i]; pspws = &ps->a_spw[i]; pspws->max_qnt_send_desc = pspw->max_qnt_send_desc; pspws->tx_speed = pspw->speed; } memcpy( ps->a_rt, gspw_sw.rt.a_rt, sizeof(ps->a_rt)); } //////////////////// Driver: //////////////////// // Прототипы функций-обработчиков файловых операций static ssize_t drv_gspw_read(struct file *file, char *p_buf, size_t count, loff_t *ppos); static ssize_t drv_gspw_write(struct file *file, const char *p_buf, size_t count, loff_t *ppos); static int drv_gspw_open(struct inode *inode, struct file *file); static int drv_gspw_close(struct inode *inode, struct file *file); //long drv_gspw_ioctl (struct file *file, unsigned int cmd, unsigned long arg); // Доступные файловые операции static struct file_operations gspwsw_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = drv_gspw_read, .write = drv_gspw_write, .open = drv_gspw_open, .release = drv_gspw_close, .compat_ioctl = drv_gspw_ioctl, .unlocked_ioctl = drv_gspw_ioctl, }; static inline void gspv_print_dsk( const char *ps_msg, gspw_desc_t *pd) { PRINT( "%s: pd=0x%p sz=%u ep=%u valid=%u msk=%Xh\n", ps_msg, pd, pd->size, pd->type_ep, pd->valid, pd->port_mask); } static inline int has_new_rx_data_in_cur_buf( fifo_t *pff_data) { dma_data_fi_t *p_data = (dma_data_fi_t *)fifo_get_first_free(pff_data); u32 wcx = (MC_RUN_GSPW_RX_DAT >> SWIC_DMA_CSR_WCX_OFS) & SWIC_DMA_CSR_WCX_MSK; //PRINT( "RUN=%Xh, IR=%Xh\n", MC_RUN_GSPW_RX_DAT, MC_IR_GSPW_RX_DAT); if( p_data==NULL || wcx==SWIC_DMA_CSR_WCX_MSK) return 0; return (p_data->pos_proc != ((wcx + 1)<<3)) ? 1 : 0; } void gspw_wake_up_all_rx_thread( void) { int i; for( i=0; i < GSPW_SPW_PORT_QNT; ++i) wake_up_interruptible( &gspw_sw.a_gspwc[i].wq_rx); } void wake_up_next_rx_thread( fifo_t *pff_desc, u32 port_cur) { gspw_ctrl_t *pspw; dma_desc_fi_t *p_desc = (dma_desc_fi_t *)fifo_get_first_held( pff_desc); u32 port_next = port_cur + 1; if( p_desc == NULL) return; if( port_next >= GSPW_FIRST_SPW_PORT_NUM + GSPW_SPW_PORT_QNT) port_next = GSPW_FIRST_SPW_PORT_NUM; if( port_next == port_cur) return; if( p_desc->desc.port_mask == port_next) { pspw = &gspw_sw.a_gspwc[port_next-1]; wake_up_interruptible( &pspw->wq_rx); } } // RX: static ssize_t drv_gspw_read( struct file *file, char *p_buf, size_t size, loff_t *ppos) { unsigned int dev_num = iminor( file->f_dentry->d_inode); u32 spw_num = dev_num - 1; gspw_cfg_ctrl_t *pcfg = &gspw_sw.cfg_ctrl; gspw_ctrl_t *pspw = NULL; dma_desc_fi_t *p_desc = NULL, *pdsk; dma_data_fi_t *p_data = NULL; dma_data_fi_t *p_data_free = NULL; dma_chain_t *pch_desc = &pcfg->dch_rx_desc; dma_chain_t *pch_data = &pcfg->dch_rx_data; fifo_t *pff_desc = &pch_desc->ff; fifo_t *pff_data = &pch_data->ff; //unsigned sz_to_end, nbytes, rest, completed; //char *pdata; int rc/*, i=-1*/; u32 sz_rd_avail = size - *ppos; //- returned buffer available size u32 sz_desc_data; u32 sz_data_buf_avail; u32 len_data; u32 cnt_rx = 0; //- returned data counter u32 ir; //short wcx; u32 len_cur_data; int has_new_rx_data; u32 ir_before_wait; //pr_info( "drv_gspw_read: pid=%li tid=%li\n", sys_getpid(), sys_gettid()); if( gspw_sw.mode != GSPW_MODE_WORK) { gspw_sw.is_rx_stop |= (1 << spw_num); return 0; } if( pcfg->is_reset_io) return 0; if( (dev_num != GSPW_PORT_SWIC0) && (dev_num != GSPW_PORT_SWIC1)) { PRINT( "drv_gspw_read: Reading from unsupportable port=%d\n", dev_num); return -ENODEV; } pspw = &gspw_sw.a_gspwc[spw_num]; PRINT( "\ndrv_gspw_read: chan=%d, size=%u\n", pspw->port.num, size); while( !pcfg->is_reset_io) { if( gspw_sw.mode != GSPW_MODE_WORK) break; //disable_irq( spw_rx_desc_irq()); //disable_irq( spw_rx_data_irq()); /*if(++i==0) { PRINT("RX DESC/DATA: IR=%Xh, RUN=%Xh / IR=%Xh, RUN=%Xh\n", SWIC_DMA_IR( SWIC_RX_DESC_CHAN), SWIC_DMA_RUN( SWIC_RX_DESC_CHAN), SWIC_DMA_IR( SWIC_RX_DATA_CHAN), SWIC_DMA_RUN( SWIC_RX_DATA_CHAN) ); }*/ //wcx = 0; len_cur_data = 0; if( p_desc==NULL) { p_desc = (dma_desc_fi_t *)fifo_get_first_held( pff_desc); //if( p_desc) // pr_info( "drv_gspw_read: desc.port_mask=%Xh\n", p_desc->desc.port_mask); if( p_desc && (p_desc->desc.port_mask != dev_num)) p_desc = NULL; } if( p_data==NULL) p_data = (dma_data_fi_t *)fifo_get_first_held( pff_data); #if 1 //PRINT( "drv_gspw_read: p_desc=0x%p, p_data=0x%p\n", p_desc, p_data); if( p_desc && p_data==NULL) { // обрабатываем еще незаполненный буфер: // p_data_free = (dma_data_fi_t *)fifo_get_first_free( pff_data); if( p_data_free==NULL) { if( cnt_rx) break; goto l_wait; } p_data = (dma_data_fi_t *)fifo_get_first_held( pff_data); if( p_data==NULL) p_data = p_data_free; else continue; ir = MC_IR_GSPW_RX_DAT; if( (ir >= p_data->reg_init.ir) && (ir < p_data->reg_init.ir + pch_data->sz_data_buf) ) { /*if( ir != MC_IR_GSPW_RX_DAT) { //// текущий активный буфер в цепочке сдвинулся: // continue; }*/ len_cur_data = ir - p_data->reg_init.ir; /*wcx = (MC_RUN_GSPW_RX_DAT >> SWIC_DMA_CSR_WCX_OFS) & SWIC_DMA_CSR_WCX_MSK; len_wcx_data = ((wcx + 1) << 3); if( MC_IR_GSPW_RX_DAT == pch_data->pfi_cur->reg_init.ir) p_data = pch_data->pfi_cur; else { // текущий активный буфер в цепочке сдвинулся: wcx = 0; }*/ } } /*else if( p_desc==NULL && p_data==NULL && pch_data->pfi_cur) { ir = MC_IR_GSPW_RX_DAT; if( ir == pch_data->pfi_cur->reg_init.ir) { wcx = (MC_RUN_GSPW_RX_DAT >> SWIC_DMA_CSR_WCX_OFS) & SWIC_DMA_CSR_WCX_MSK; len_wcx_data = ((wcx + 1) << 3); if( MC_IR_GSPW_RX_DAT == pch_data->pfi_cur->reg_init.ir) p_data = pch_data->pfi_cur; else { // текущий активный буфер в цепочке сдвинулся: wcx = 0; } } if( wcx == 0) { if( cnt_rx) break; goto l_wait; } }*/ #endif //0 //enable_irq( spw_rx_desc_irq()); //enable_irq( spw_rx_data_irq()); if( p_desc==NULL || p_data==NULL || (p_desc && !p_desc->desc.valid)) { //if( p_desc && !p_desc->desc.valid) // PRINT("drv_gspw_read: valid==0\n"); if( cnt_rx) break; goto l_wait; } //PRINT("Receive spw packet:\n"); //dma_desc_fi_print( p_desc); //PRINT("RX_DATA_RUN=%Xh\n", SWIC_DMA_RUN( SWIC_RX_DATA_CHAN)); sz_rd_avail = size - (*ppos + cnt_rx); sz_desc_data = p_desc->desc.size - p_desc->pos_proc; sz_data_buf_avail = (len_cur_data ? len_cur_data : pch_data->sz_data_buf) - p_data->pos_proc; //PRINT("drv_gspw_read: size=%u, szs: %u %u %u\n", // size, sz_rd_avail, sz_desc_data, sz_data_buf_avail); if( sz_rd_avail == 0) break; len_data = min3( sz_rd_avail, sz_desc_data, sz_data_buf_avail); //PRINT("drv_gspw_read: len_data=%u\n", len_data); if( len_data==0) { if( cnt_rx) break; goto l_wait; } PRINT( "drv_gspw_read: copy_to_user(%u)\n", len_data); PRINT( "drv_gspw_read: unused: %Xh %Xh\n", p_desc->desc.unused, p_desc->desc.unused1); copy_to_user( &p_buf[*ppos + cnt_rx], &p_data->p_buf[p_data->pos_proc], len_data); cnt_rx += len_data; p_desc->pos_proc += len_data; p_data->pos_proc += len_data; if( p_data->pos_proc == pch_data->sz_data_buf) { //PRINT( "drv_gspw_read: p_data=%p,%p; stat=%u\n", p_data, p_data_free, p_data->stat); if( (p_data != p_data_free) || (p_data->stat == DMA_FI_STAT__FILLED)) { PRINT("drv_gspw_read: free_held data ir=%Xh\n", p_data->reg_init.ir); dma_data_fi_reset_proc( p_data); if( p_data != (dma_data_fi_t *)fifo_free_first_held( pff_data)) PRINT( "drv_gspw_read: ERROR: Trying of using free said RX data list from several threads!\n"); p_data->p_prev->reg_init.csr |= SWIC_DMA_CSR_RUN; if( !(MC_RUN_GSPW_RX_DAT & SWIC_DMA_CSR_RUN)) MC_RUN_GSPW_RX_DAT |= SWIC_DMA_CSR_RUN; p_data = NULL; } else { // данные буфера переданы, хотя прерывания по завершению вычитывания буфера еще не было: PRINT( "drv_gspw_read: Interrupt is absent at full filled data buffer\n"); } } if( p_desc->pos_proc == p_desc->desc.size) { PRINT( "drv_gspw_read: free_held desc ir=%Xh\n", p_desc->reg_init.ir); dma_desc_fi_reset_proc( p_desc); if( p_desc != (dma_desc_fi_t *)fifo_free_first_held( pff_desc)) PRINT( "drv_gspw_read: ERROR: Trying of using free said RX descriptor list from several threads!\n"); p_desc->p_prev->reg_init.csr |= SWIC_DMA_CSR_RUN; if( !(MC_RUN_GSPW_RX_DES & SWIC_DMA_CSR_RUN)) MC_RUN_GSPW_RX_DES |= SWIC_DMA_CSR_RUN; p_desc = NULL; } //print_dma_rx_desc_regs( "drv_gspw_read"); //print_dma_rx_data_regs( "drv_gspw_read"); //PRINT( "drv_gspw_read: QSTR0=%Xh, MASK0=%X\n", MC_QSTR0, MC_MASKR0); continue; l_wait:; //enable_irq( spw_rx_desc_irq()); //enable_irq( spw_rx_data_irq()); //enable_irq( spw_rx_desc_irq()); /*PRINT("Read: IRQ_MSK0=%Xh, IRQ_REQ0=%Xh\n", SYS_IRQ_MSK0_REG, SYS_IRQ_REQ0_REG); PRINT("RX DESC/DATA: IR=%Xh, RUN=%Xh / IR=%Xh, RUN=%Xh\n", SWIC_DMA_IR( SWIC_RX_DESC_CHAN), SWIC_DMA_RUN( SWIC_RX_DESC_CHAN), SWIC_DMA_IR( SWIC_RX_DATA_CHAN), SWIC_DMA_RUN( SWIC_RX_DATA_CHAN) );*/ wake_up_interruptible( &pcfg->wq_txdata); wake_up_interruptible( &pcfg->wq_txdesc); wake_up_interruptible( &pcfg->wq_txjob); wake_up_next_rx_thread( pff_desc, dev_num); PRINT( "\ndrv_gspw_read: wait_event_interruptible()\n"); print_fifo_held_qnt( pcfg, "READ_wait"); ir_before_wait = MC_IR_GSPW_RX_DAT; if( (rc=wait_event_interruptible( pspw->wq_rx, ((pdsk=(dma_desc_fi_t *)fifo_get_first_held( pff_desc)) && (pdsk->desc.port_mask == dev_num)) || (fifo_get_first_held( pff_data) && (ir_before_wait != MC_IR_GSPW_RX_DAT)) || (gspw_sw.mode != GSPW_MODE_WORK) /*(has_new_rx_data = has_new_rx_data_in_cur_buf(p_data->reg_init.ir, remains))*/ ) )) { PRINT("drv_gspw_read: wait_event_interruptible -> (%i) -ERESTARTSYS\n", rc); disable_irq( spw_rx_desc_irq()); return -ERESTARTSYS; } has_new_rx_data = (ir_before_wait != MC_IR_GSPW_RX_DAT); PRINT( "drv_gspw_read: wait_event_interruptible() -> %Xh %Xh %i: %Xh %Xh\n", (u32 )fifo_get_first_held( pff_desc), (u32 )fifo_get_first_held( pff_data), has_new_rx_data, ir_before_wait, MC_IR_GSPW_RX_DAT); /*print_dma_rx_desc_regs( "READ"); print_dma_rx_data_regs( "READ"); { dma_desc_fi_t *pdes; dma_data_fi_t *pdat; pdes = (dma_desc_fi_t *)fifo_get_first_held( pff_desc); pdat = (dma_data_fi_t *)fifo_get_first_held( pff_data); PRINT("drv_gspw_read: held: %Xh %Xh\n", (pdes ? pdes->reg_init.ir:0), (pdat ? pdat->reg_init.ir:0)); pdes = (dma_desc_fi_t *)fifo_get_first_free( pff_desc); pdat = (dma_data_fi_t *)fifo_get_first_free( pff_data); PRINT( "drv_gspw_read: free: %Xh %Xh\n", (pdes ? pdes->reg_init.ir:0), (pdat ? pdat->reg_init.ir:0)); }*/ //disable_irq( spw_rx_desc_irq()); /*if( (rc=wait_event_timeout( pcfg->wq_rx, fifo_get_first_held( pff), msecs_to_jiffies(7000)))) { PRINT("drv_gspw_read: wait_event_interruptible -> (%i) -ERESTARTSYS\n", rc); return -ERESTARTSYS; }*/ //PRINT( "drv_gspw_read: wait_event_interruptible -> OK\n"); //disable_irq( spw_rx_desc_irq()); //SWIC_DMA_CSR( pcfg->rx_desc_buf.dma_chan); // Сброс признака прерывания //SWIC_DMA_CSR( SWIC_RX_DESC_CHAN); } //-end: while(1) if( gspw_sw.mode != GSPW_MODE_WORK) gspw_sw.is_rx_stop |= (1 << spw_num); wake_up_next_rx_thread( pff_desc, dev_num); //disable_irq( spw_rx_data_irq()); print_fifo_held_qnt( pcfg, "READ"); print_dma_rx_desc_regs( "READ"); print_dma_rx_data_regs( "READ"); PRINT( "drv_gspw_read: -> %u END\n\n", cnt_rx); // check data: /*{ int i=0; u8 cc = 0; u32 cntErrCC = 0; for( i=0; (i < cnt_rx); ++i, ++cc) { if( (u8 )p_buf[i] != cc) { pr_info( "READ CC ERROR: %.2Xh (wait %.2Xh) in pos: %u\n", (u8 )p_buf[i], cc, i); ++cntErrCC; cc = (u8 )p_buf[i]; } } pr_info( "READ cntErrCC=%u\n", cntErrCC); }*/ return cnt_rx; //completed; } //-end: drv_gspw_read() // TX: static inline void dma_tx_job_clear( gspw_cfg_ctrl_t *pcfg, dma_tx_job_t *pj) { dma_chain_t *pch_desc = &pcfg->dch_tx_desc; dma_chain_t *pch_data = &pcfg->dch_tx_data; fifo_t *pff_desc = &pch_desc->ff; fifo_t *pff_data = &pch_data->ff; dma_desc_fi_t *p_desc, *pdsc; dma_data_fi_t *p_data, *pdat; u32 cntFreeDesc=0, cntFreeData=0; p_desc = pj->p_desc_first; while( (pdsc = (dma_desc_fi_t *)fifo_get_first_held( pff_desc)) ) { //PRINT("dma_tx_job_clear: pdsc->ir=%Xh\n", pdsc->reg_init.ir); for( ; (p_desc); p_desc = p_desc->p_next) { if( pdsc != p_desc) { if( p_desc == pj->p_desc_last) { if( cntFreeDesc==0) { PRINT("Logic ERROR: Held desc item %Xh is out of job desc range [%Xh-%Xh]\n", pdsc->reg_init.ir, pj->p_desc_first->reg_init.ir, pj->p_desc_last->reg_init.ir); } p_desc = NULL; break; } continue; } //PRINT("dma_tx_job_clear: p_desc->ir=%Xh\n", p_desc->reg_init.ir); if (pdsc->stat != DMA_FI_STAT__SENT) PRINT("dma_tx_job_clear: Attempt of clearing descriptor item without sent status\n"); PRINT("dma_tx_job_clear: free dsc: ir=%Xh\n", pdsc->reg_init.ir); dma_desc_fi_reset_proc( pdsc); pdsc->reg_init.csr &= ~SWIC_DMA_CSR_CHEN; if( (pdsc != (dma_desc_fi_t *)fifo_free_first_held( pff_desc)) ) PRINT( "dma_tx_job_clear: Trying of using free said Tx descriptor list from several threads !!!\n"); ++cntFreeDesc; if( p_desc == pj->p_desc_last) p_desc = pj->p_desc_first = pj->p_desc_last = pj->p_desc_cur = NULL; else p_desc = p_desc->p_next; break; } //-end: while() if( p_desc==NULL) break; } //-end: for() p_data = pj->p_data_first; while( (pdat = (dma_data_fi_t *)fifo_get_first_held( pff_data)) ) { //PRINT("dma_tx_job_clear: pdat->ir=%Xh\n", pdat->reg_init.ir); for( ; (p_data); p_data = p_data->p_next) { if( pdat != p_data) { if( p_data == pj->p_data_last) { if( cntFreeData==0) { PRINT("Logic ERROR: Held data item %Xh is out of job data range [%Xh-%Xh]\n", pdat->reg_init.ir, pj->p_data_first->reg_init.ir, pj->p_data_last->reg_init.ir); } p_data = NULL; break; } continue; } //PRINT("dma_tx_job_clear: p_data->ir=%Xh\n", p_data->reg_init.ir); if (pdat->stat != DMA_FI_STAT__SENT) PRINT("dma_tx_job_clear: Attempt of clearing data item without sent status\n"); PRINT("dma_tx_job_clear: free dat: ir=%Xh\n", pdat->reg_init.ir); dma_data_fi_reset_proc( pdat); pdat->reg_init.csr &= ~SWIC_DMA_CSR_CHEN; if( (pdat != (dma_data_fi_t *)fifo_free_first_held( pff_data)) ) PRINT( "dma_tx_job_clear: Trying of using free said Tx data list from several threads !!!\n"); ++cntFreeData; if( p_data == pj->p_data_last) p_data = pj->p_data_first = pj->p_data_last = pj->p_data_cur = NULL; else p_data = p_data->p_next; break; } //-end: while() if( p_data==NULL) break; } //-end: for() //pj->p_desc_first = pj->p_desc_last = pj->p_desc_cur = NULL; //pj->p_data_first = pj->p_data_last = pj->p_data_cur = NULL; if( pj->p_desc_first==NULL && pj->p_data_first==NULL) { pj->stat = DMA_JOB_STAT_FREE; } } //- end: dma_tx_job_clear #if 0 static void check_data_before_tx( gspw_cfg_ctrl_t *pcfg, dma_tx_job_t *p_job) { dma_desc_fi_t *p_desc; dma_data_fi_t *p_data; u32 pos = 0, szData = 0; u32 i, len; u32 sz_data_buf = pcfg->dch_tx_data.sz_data_buf; u8 cc = 0; u32 cntErrCC = 0; for( p_desc = p_job->p_desc_first; (1); p_desc = p_desc->p_next) { szData += p_desc->desc.size; if( p_desc == p_job->p_desc_last) break; } //- end: for() for( p_data = p_job->p_data_first; (1); p_data = p_data->p_next) { len = szData - pos; if( len > sz_data_buf) len = sz_data_buf; for( i=0; (i < len); ++i, ++cc) { if( cc != (u8 )p_data->p_buf[i]) { pr_info( "WRITE CC ERROR: %.2Xh (wait %.2Xh) in pos: %u\n", (u8 )p_data->p_buf[i], cc, i); ++cntErrCC; cc = (u8 )p_data->p_buf[i]; } } pos += i; if( p_data == p_job->p_data_last) break; } pr_info( "check_data_before_tx: WRITE cntErrCC=%u\n", cntErrCC); } #endif //0 int thread_dma_tx_job( void *pv) { gspw_cfg_ctrl_t *pcfg = (gspw_cfg_ctrl_t *)pv; fifo_t *pff_job = &pcfg->ff_tx_job; dma_tx_job_t *p_job = NULL; dma_desc_fi_t *p_desc; dma_data_fi_t *p_data; u32 v; while(1) { if( gspw_sw.mode == GSPW_MODE_FORCE_STOP) goto l_wait_job; if( (p_job=(dma_tx_job_t *)fifo_get_first_held( pff_job))==NULL ) goto l_wait_job; PRINT( "thread_dma_tx_job: select job %Xh stat=%u\n", (u32 )p_job, p_job->stat); if( p_job->stat == DMA_JOB_STAT_FIN) { dma_tx_job_clear( pcfg, p_job); PRINT("thread_dma_tx_job: free job %Xh\n", (u32 )p_job); if( p_job != (dma_tx_job_t *)fifo_free_first_held( pff_job)) PRINT( "thread_dma_tx_job: ERROR: Trying of using free said TX job list from several threads!\n"); //PRINT( "thread_dma_tx_job: wake_up_interruptible()\n"); wake_up_interruptible( &pcfg->wq_txdesc); wake_up_interruptible( &pcfg->wq_txdata); continue; } if (p_job->stat != DMA_JOB_STAT_READY) goto l_wait_job; PRINT( "start_chain_work: TX_RUN: %Xh %Xh\n", MC_RUN_GSPW_TX_DES, MC_RUN_GSPW_TX_DAT); if( (MC_RUN_GSPW_TX_DES & SWIC_DMA_CSR_RUN) || (MC_RUN_GSPW_TX_DAT & SWIC_DMA_CSR_RUN)) goto l_wait_job; PRINT( "start_chain_work: start new job\n"); for( p_desc = p_job->p_desc_first; (1); p_desc = p_desc->p_next) { if( p_desc == p_job->p_desc_last) { p_desc->reg_init.csr &= ~SWIC_DMA_CSR_CHEN; p_job->stat = DMA_JOB_STAT_RUN; PRINT(" start desc chain\n"); //check_data_before_tx( pcfg, p_job); MC_CP_GSPW_TX_DES = mips_virt_to_phys((unsigned )&p_job->p_desc_first->reg_init) | 1; p_job->pspw->cnt_tx_desc_send = 0; break; } p_desc->reg_init.csr |= SWIC_DMA_CSR_CHEN; } //- end: for() for (p_data = p_job->p_data_first; (1); p_data = p_data->p_next) { p_data->reg_init.csr &= ~(SWIC_DMA_CSR_WCX_MSK << SWIC_DMA_CSR_WCX_OFS); v = p_data->pos_proc; v = (v >> 3) + ((v & 0x7) ? 1:0) - 1; p_data->reg_init.csr |= ((v & SWIC_DMA_CSR_WCX_MSK) << SWIC_DMA_CSR_WCX_OFS); if( p_data == p_job->p_data_last) { p_data->reg_init.csr &= ~SWIC_DMA_CSR_CHEN; PRINT(" start data chain\n"); MC_CP_GSPW_TX_DAT = mips_virt_to_phys((unsigned)&p_job->p_data_first->reg_init) | 1; break; } p_data->reg_init.csr |= SWIC_DMA_CSR_CHEN; } //- end: for() // debug: /*for( p_desc = p_job->p_desc_first; (1); p_desc = p_desc->p_next) { PRINT(" desc csr=%Xh ir=%Xh sz=%u\n", p_desc->reg_init.csr, p_desc->reg_init.ir, p_desc->desc.size); if( p_desc == p_job->p_desc_last) break; } for (p_data = p_job->p_data_first; (1); p_data = p_data->p_next) { PRINT(" data csr=%Xh ir=%Xh\n", p_data->reg_init.csr, p_data->reg_init.ir); if( p_data == p_job->p_data_last) break; }*/ continue; l_wait_job:; if( gspw_sw.mode != GSPW_MODE_WORK) { gspw_sw.is_tx_job_stop = 1; break; } if( (p_job=(dma_tx_job_t *)fifo_get_first_held( pff_job))==NULL ) { PRINT("thread_dma_tx_job: wait_event_interruptible(job!=NULL):\n"); print_fifo_held_qnt( pcfg, "job_NULL"); if( wait_event_interruptible( pcfg->wq_txjob, fifo_get_first_held( pff_job))) { //disable_irq( spw_tx_data_irq()); PRINT("thread_dma_tx_job: wait_event_interruptible(job) -> -ERESTARTSYS\n"); return -ERESTARTSYS; } } else if (p_job->stat == DMA_JOB_STAT_RUN) { PRINT("thread_dma_tx_job: wait_event_interruptible(stat=%u):\n", p_job->stat); print_fifo_held_qnt( pcfg, "job_RUN"); if( wait_event_interruptible( pcfg->wq_txjob, (p_job->stat==DMA_JOB_STAT_FIN))) { //disable_irq( spw_tx_data_irq()); PRINT("thread_dma_tx_job: wait_event_interruptible(job) -> -ERESTARTSYS\n"); return -ERESTARTSYS; } } } //- end: while() return 0; } //- end: thread_dma_tx_job #if 0 //-> is started chain work (1) static u32 start_job( gspw_cfg_ctrl_t *pcfg) { dma_chain_t *pch_desc = &pcfg->dch_tx_desc; dma_chain_t *pch_data = &pcfg->dch_tx_data; fifo_t *pff_desc = &pch_desc->ff; fifo_t *pff_data = &pch_data->ff; dma_desc_fi_t *p_desc, *p_desc_first, *p_desc_next = NULL; dma_data_fi_t *p_data, *p_data_first, *p_data_next = NULL; u32 v; u32 is_started = 0; /*dma_desc_fi_t *pdsc; dma_data_fi_t *pdat; u32 i;*/ PRINT( "start_chain_work: TX_RUN: %Xh %Xh\n", MC_RUN_GSPW_TX_DES, MC_RUN_GSPW_TX_DAT); if( !(MC_RUN_GSPW_TX_DES & SWIC_DMA_CSR_RUN) && !(MC_RUN_GSPW_TX_DAT & SWIC_DMA_CSR_RUN)) { PRINT( "start_chain_work: ff first_held: %Xh %Xh\n", (u32 )fifo_get_first_held( pff_desc), (u32 )fifo_get_first_held( pff_data)); if( (p_desc = p_desc_first = (dma_desc_fi_t *)fifo_get_first_held( pff_desc))==NULL ) return 0; for( ; (1); p_desc=p_desc_next) { p_desc->desc.size = p_desc->pos_proc; p_desc_next = p_desc->p_next; if( (p_desc_next==(dma_desc_fi_t *)fifo_get_first_free( pff_desc)) || (p_desc_next==(dma_desc_fi_t *)fifo_get_first_held( pff_desc)) ) { p_desc->reg_init.csr &= ~SWIC_DMA_CSR_CHEN; /*PRINT( "desc.size=%u csr=%Xh ir=%Xh END\n", p_desc->desc.size, p_desc->reg_init.csr, p_desc->reg_init.ir); for( i=0,pdsc=p_desc_first; (i < 10); ++i, pdsc=pdsc->p_next) { PRINT("dsc: csr=%Xh ir=%Xh sz=%u\n", pdsc->reg_init.csr, pdsc->reg_init.ir, pdsc->desc.size); }*/ MC_CP_GSPW_TX_DES = mips_virt_to_phys((unsigned )&p_desc_first->reg_init) | 1; pcfg->cnt_tx_desc_send = 0; is_started = 1; break; } p_desc->reg_init.csr |= SWIC_DMA_CSR_CHEN; //PRINT( "desc.size=%u csr=%Xh ir=%Xh\n", // p_desc->desc.size, p_desc->reg_init.csr, p_desc->reg_init.ir); } //- end: for() if( (p_data = p_data_first = (dma_data_fi_t *)fifo_get_first_held( pff_data))==NULL ) return 0; for (; (1); p_data=p_data_next) { p_data->reg_init.csr &= ~(SWIC_DMA_CSR_WCX_MSK << SWIC_DMA_CSR_WCX_OFS); v = p_data->pos_proc; v = (v >> 3) + ((v & 0x7) ? 1:0) - 1; p_data->reg_init.csr |= ((v & SWIC_DMA_CSR_WCX_MSK) << SWIC_DMA_CSR_WCX_OFS); p_data_next = p_data->p_next; if( (p_data_next==(dma_data_fi_t *)fifo_get_first_free( pff_data)) || (p_data_next==(dma_data_fi_t *)fifo_get_first_held( pff_data)) ) { p_data->reg_init.csr &= ~SWIC_DMA_CSR_CHEN; /*PRINT( "pos_proc=%u v=%Xh csr=%Xh ir=%Xh END\n", p_data->pos_proc, v, p_data->reg_init.csr, p_data->reg_init.ir); for( i=0, pdat=p_data_first; (i < 10); ++i,pdat=pdat->p_next) { PRINT("dat: csr=%Xh ir=%Xh;\n", pdat->reg_init.csr, pdat->reg_init.ir); }*/ MC_CP_GSPW_TX_DAT = mips_virt_to_phys((unsigned)&p_data_first->reg_init) | 1; break; } p_data->reg_init.csr |= SWIC_DMA_CSR_CHEN; //PRINT( "pos_proc=%u v=%Xh csr=%Xh ir=%Xh\n", // p_data->pos_proc, v, p_data->reg_init.csr, p_data->reg_init.ir); } //- end: for() /* { for( i=0; i<30; ++i) { PRINT( "%Xh %Xh %Xh %Xh %Xh\n", MC_RUN_GSPW_TX_DES, MC_IR_GSPW_TX_DES, MC_CP_GSPW_TX_DES, MC_RUN_GSPW_TX_DAT, MC_IR_GSPW_TX_DAT); } }*/ } //- end: if( !(MC_RUN_GSPW_TX_DES & SWIC_DMA_CSR_RUN) && ...) return is_started; } #endif //0 ssize_t gspw_dev_write( unsigned dev_num, u32 is_net, const char *p_buf, size_t size, loff_t *ppos) { //unsigned int minor = iminor( file->f_dentry->d_inode); u32 spw_num = dev_num - 1; gspw_cfg_ctrl_t *pcfg = &gspw_sw.cfg_ctrl; gspw_ctrl_t *pspw; u32 completed = 0; //- returned data counter dma_tx_job_t *p_job = NULL; fifo_t *pff_job = &pcfg->ff_tx_job; dma_chain_t *pch_desc = &pcfg->dch_tx_desc; dma_chain_t *pch_data = &pcfg->dch_tx_data; fifo_t *pff_desc = &pch_desc->ff; fifo_t *pff_data = &pch_data->ff; dma_desc_fi_t *p_desc = NULL; dma_data_fi_t *p_data = NULL; u32 sz_wr_avail = size - *ppos; //- returned buffer available size u32 sz_desc_data; u32 sz_data_buf_avail; u32 len_data; //dma_params_t *pdp_prev; //u32 ir; int is_run = 0; u32 wcx; //pr_info( "drv_spw_write: pid=%li tid=%li\n", sys_getpid(), sys_gettid()); if( gspw_sw.mode != GSPW_MODE_WORK) { gspw_sw.is_tx_stop |= (1 << spw_num); return 0; } if( pcfg->is_reset_io) return 0; if( (dev_num != GSPW_PORT_SWIC0) && (dev_num != GSPW_PORT_SWIC1)) { PRINT( "gspw_dev_write: Writing to unsupportable port: '%s%d'\n", INTF_NAME(is_net), dev_num); return -ENODEV; } pspw = &gspw_sw.a_gspwc[spw_num]; if( pspw->port.net_usage != is_net) { pr_info( "gspw_dev_write: Could not write to '%s%d': resourse is busy\n", INTF_NAME(is_net), dev_num); return -EBUSY; } PRINT( "gspw_dev_write: spw_num=%d, size=%d\n", spw_num, size); //pr_info( "drv_gspw_write: mutex_lock()\n"); //mutex_lock( &pcfg->mut_tx); //pr_info( "drv_gspw_write: while() tid=%li\n", sys_gettid()); while( (sz_wr_avail || (sz_wr_avail==0 && p_desc && p_data)) && !pcfg->is_reset_io) { if( gspw_sw.mode != GSPW_MODE_WORK) break; if( p_job==NULL && (p_job=(dma_tx_job_t *)fifo_get_first_free( pff_job))==NULL ) break; if( p_data==NULL && (p_data=(dma_data_fi_t *)fifo_get_first_free( pff_data))==NULL ) goto l_wait_data; if( p_desc==NULL) { if( (p_desc = (dma_desc_fi_t *)fifo_get_first_free( pff_desc))==NULL ) goto l_wait_desc; p_desc->desc.size = pcfg->max_sz_tx_pack; } sz_desc_data = p_desc->desc.size - p_desc->pos_proc; sz_data_buf_avail = pch_data->sz_data_buf - p_data->pos_proc; PRINT( "gspw_dev_write: sz_wr_avail=%u, sz_desc_data=%u, sz_data_buf_avail=%u\n", sz_wr_avail, sz_desc_data, sz_data_buf_avail); PRINT( "gspw_dev_write: p_desc->desc.size=%u, pch_data->sz_data_buf=%u\n", p_desc->desc.size, pch_data->sz_data_buf); len_data = min3( sz_wr_avail, sz_desc_data, sz_data_buf_avail); if( len_data) { //PRINT( "drv_gspw_write: copy_from_user(%u) %u %u %u\n", // len_data, sz_wr_avail, sz_desc_data, sz_data_buf_avail); PRINT( "gspw_dev_write: copy_from_user(%u)\n", len_data); copy_from_user( &p_data->p_buf[p_data->pos_proc], &p_buf[*ppos + completed], len_data); if( pch_data->sz_data_buf - (p_data->pos_proc + len_data) > 0) memset(&p_data->p_buf[p_data->pos_proc + len_data], 0xFF, pch_data->sz_data_buf - (p_data->pos_proc + len_data)); } else { PRINT( "gspw_dev_write: logic ERROR: min3 -> 0 !!!\n"); break; } if( gspw_sw.mode == GSPW_MODE_FORCE_STOP) break; completed += len_data; p_desc->pos_proc += len_data; p_data->pos_proc += len_data; sz_wr_avail -= len_data; // sz_data_buf = 65536 if( (p_data->pos_proc == pch_data->sz_data_buf) || (len_data && sz_wr_avail == 0) || (len_data && (gspw_sw.mode != GSPW_MODE_WORK)) || ( (p_desc->pos_proc == p_desc->desc.size) && (pspw->max_qnt_send_desc && (pspw->cnt_tx_desc_send + 1) >= pspw->max_qnt_send_desc))) { /* MC_IR_GSPW_TX_DES = mips_virt_to_phys( (unsigned )pcfg->tx_desc); MC_CSR_GSPW_TX_DES = MC_DMA_CSR_WCX(0) | MC_DMA_RUN; // 1 8-байтовое слово pdr = &pd->reg_init; pdr->ir = mips_virt_to_phys( (unsigned )pd->p_buf); pdr->csr = MC_DMA_CSR_IM | MC_DMA_CSR_WN(0) | MC_DMA_CSR_RUN | MC_DMA_CSR_WCX((pch->sz_data_buf >> 3) - 1) | MC_DMA_CSR_CHEN; pdr->cp = mips_virt_to_phys((unsigned)&pd->p_next->reg_init); MC_CSR_GSPW_TX_DAT = MC_DMA_CSR_IM | MC_DMA_CSR_WCX(((nbytes + 7) >> 3) - 1); //PRINT("drv_gspw_write: 0) TX_DAT_RUN=%Xh, TX_DES_RUN=%Xh\n", MC_RUN_GSPW_TX_DAT, MC_RUN_GSPW_TX_DES); //PRINT("Write: IRQ_MSK0=%Xh, IRQ_REQ0=%Xh\n", SYS_IRQ_MSK0_REG, SYS_IRQ_REQ0_REG); MC_CSR_GSPW_TX_DAT |= MC_DMA_RUN; */ p_data->reg_init.csr &= ~(SWIC_DMA_CSR_WCX_MSK << SWIC_DMA_CSR_WCX_OFS); wcx = ((p_desc->pos_proc >> 3) + ((p_desc->pos_proc & 7) ? 1 : 0) - 1) & SWIC_DMA_CSR_WCX_MSK; p_data->reg_init.csr |= (wcx << SWIC_DMA_CSR_WCX_OFS); PRINT( "gspw_dev_write: + data buf %u, csr=%Xh\n", p_data->pos_proc, p_data->reg_init.csr); if( p_data != (dma_data_fi_t *)fifo_hold_first_free( pff_data)) PRINT( "gspw_dev_write: ERROR: Trying of using free said TX data list from several threads!\n"); if( p_job->p_data_first==NULL) { p_job->p_data_first = p_data; p_job->stat = DMA_JOB_STAT_PREP; } p_job->p_data_last = p_data; p_data = NULL; } if( (p_desc->pos_proc == p_desc->desc.size) || (len_data && sz_wr_avail == 0) || (len_data && (gspw_sw.mode != GSPW_MODE_WORK)) ) { is_run = 0; //dma_desc_fi_reset_proc( p_desc); //MC_DMA_CSR_CHEN p_desc->desc.size = p_desc->pos_proc; p_desc->desc.type_ep = SPW_EOP; p_desc->desc.unused = 0; p_desc->desc.unused1 = 0; p_desc->desc.port_mask = (1 << dev_num); //TX_PACK_PORT_MSK_SWIC0; p_desc->desc.valid = 1; //PRINT( "drv_gspw_write: desc: pos_proc=%u %u\n", p_desc->pos_proc, p_desc->desc.size); //=32k PRINT( "gspw_dev_write: + desc %u, %u\n", p_desc->desc.size, completed); if( p_desc != (dma_desc_fi_t *)fifo_hold_first_free( pff_desc)) PRINT( "gspw_dev_write: ERROR: Trying of using free said TX descriptor list from several threads!\n"); if( p_job->p_desc_first==NULL) { p_job->p_desc_first = p_desc; p_job->stat = DMA_JOB_STAT_PREP; } p_job->p_desc_last = p_desc; if( pspw->max_qnt_send_desc) ++pspw->cnt_tx_desc_send; if( (pspw->max_qnt_send_desc && pspw->cnt_tx_desc_send >= pspw->max_qnt_send_desc) || sz_wr_avail==0 || (gspw_sw.mode != GSPW_MODE_WORK) ) { p_job->stat = DMA_JOB_STAT_READY; p_job->pspw = pspw; PRINT( "gspw_dev_write: add new job %Xh\n", (u32 )p_job); if( p_job != (dma_tx_job_t *)fifo_hold_first_free( pff_job)) PRINT( "gspw_dev_write: ERROR: Trying of using free said TX job list from several threads!\n"); pspw->cnt_tx_desc_send = 0; #if 0 if( fifo_get_first_free( pff_desc)==0 || fifo_get_first_free( pff_data)==0 ||fifo_get_first_free( pff_job)==0) { wake_up_interruptible( &pcfg->wq_txjob); stop_wr = 1; } #else wake_up_interruptible( &pcfg->wq_txjob); #endif //pr_info( "drv_gspw_write: mutex_unlock() tid=%li\n", sys_gettid()); //complete( &pcfg->compl_tx); //mutex_unlock( &pcfg->mut_tx); //udelay (10); //pr_info( "drv_gspw_write: mutex_lock() tid=%li\n", sys_gettid()); //wait_for_completion( &pcfg->compl_tx); //mutex_lock( &pcfg->mut_tx); //pr_info( "drv_gspw_write: mutex_lock() return tid=%li\n", sys_gettid()); p_job = NULL; p_desc = NULL; p_data = NULL; if( gspw_sw.mode != GSPW_MODE_WORK) break; continue; } #if 0 if( is_init_tx_desc_chain) { u32 ir, run; // временно выключаемся: MC_RUN_GSPW_TX_DES &= ~SWIC_DMA_CSR_RUN; PRINT( "Temporary stop dma_tx_desc:\n"); print_dma_tx_desc_regs( "drv_spw_write"); print_dma_tx_data_regs( "drv_spw_write"); ir = MC_IR_GSPW_TX_DES; run = MC_RUN_GSPW_TX_DES; PRINT( "ir=%Xh sz_buf=%u %u\n", p_desc->p_prev->reg_init.ir, pch_desc->sz_data_buf, sizeof(gspw_desc_t)); if( (((run >> SWIC_DMA_CSR_WCX_OFS) & SWIC_DMA_CSR_WCX_MSK) == SWIC_DMA_CSR_WCX_MSK) && (ir == p_desc->p_prev->reg_init.ir + pch_desc->sz_data_buf)) { // дошли до конца заполненных дескрипторов: if( !(run & (SWIC_DMA_CSR_END | SWIC_DMA_CSR_DONE)) && p_desc->pos_proc) { PRINT( "drv_gspw_write: end of tx desc chain without of END or DONE\n"); } if( p_desc != (dma_desc_fi_t *)fifo_hold_first_free( pff_desc)) PRINT( "drv_gspw_write: ERROR: Trying of using free said TX descriptor list from several threads!\n"); print_dma_tx_desc_regs( "drv_spw_write +CHEN"); p_desc->reg_init.csr &= ~SWIC_DMA_CSR_CHEN; MC_CSR_GSPW_TX_DES |= SWIC_DMA_CSR_CHEN; PRINT( "drv_gspw_write: end of tx desc chain!\n"); print_dma_tx_desc_regs( "drv_spw_write"); //print_dma_tx_data_regs( "drv_spw_write"); } else if( ir < p_desc->p_prev->reg_init.ir || (ir > p_desc->p_prev->reg_init.ir + pch_desc->sz_data_buf) ) { // до конца цепочки еще не дошли: if( p_desc != (dma_desc_fi_t *)fifo_hold_first_free( pff_desc)) PRINT( "drv_gspw_write: ERROR: Trying of using free said TX descriptor list from several threads!\n"); p_desc->reg_init.csr &= ~SWIC_DMA_CSR_CHEN; p_desc->p_prev->reg_init.csr |= SWIC_DMA_CSR_CHEN; PRINT( "drv_gspw_write: not a end of tx desc chain!\n"); print_dma_tx_desc_regs( "drv_spw_write"); } // запускаемся: MC_RUN_GSPW_TX_DES |= SWIC_DMA_CSR_RUN; /* if( MC_RUN_GSPW_TX_DES & SWIC_DMA_CSR_RUN) { // временно выключаемся: MC_RUN_GSPW_TX_DES &= ~SWIC_DMA_CSR_RUN; is_run = 1; } //if( MC_RUN_GSPW_TX_DES & SWIC_DMA_CSR_DONE) //PRINT( "drv_spw_write: is_run=%u, TX_RUN=%Xh IR=%Xh CP=%Xh\n", // is_run, MC_RUN_GSPW_TX_DES, MC_IR_GSPW_TX_DES, MC_CP_GSPW_TX_DES); if( !is_run) { // стояли, переходим на следующий элемент цепочки: MC_CSR_GSPW_TX_DES |= (SWIC_DMA_CSR_CHEN | SWIC_DMA_CSR_RUN); PRINT( "drv_spw_write: to next chain item, TX_RUN=%Xh, TX_IR=%Xh\n", MC_RUN_GSPW_TX_DES, MC_IR_GSPW_TX_DES); } else { // работали: pdp_prev = &p_desc->p_prev->reg_init; p_desc->reg_init.csr &= ~SWIC_DMA_CSR_CHEN; ir = MC_IR_GSPW_TX_DES; if( (ir >= pdp_prev->ir) && (ir < (pdp_prev->ir + pch_desc->sz_data_buf)) ) MC_CSR_GSPW_TX_DES |= SWIC_DMA_CSR_CHEN; else pdp_prev->csr |= SWIC_DMA_CSR_CHEN; // запускаемся: MC_RUN_GSPW_TX_DES |= SWIC_DMA_CSR_RUN; print_dma_tx_desc_regs( "drv_spw_write"); print_dma_tx_data_regs( "drv_spw_write"); } */ } else { #if 0 u32 run, ir; u32 i; { dma_desc_fi_t *pdsc = p_desc->p_next; int i; //PRINT("csr=%Xh ir=%Xh sz=%u\n", pdsc->reg_init.csr, p_desc->reg_init.ir, pdsc->desc.size); /*for( i = 0; ((i < 4) && pdsc); ++i, pdsc = pdsc->p_next) { pdsc->desc = p_desc->desc; //PRINT("csr=%Xh ir=%Xh sz=%u\n", pdsc->reg_init.csr, pdsc->reg_init.ir, pdsc->desc.size); }*/ for( i = 0; ((i < 2) && pdsc); ++i, pdsc = pdsc->p_next) { //pdsc->reg_init.csr &= ~(SWIC_DMA_CSR_WCX_MSK << SWIC_DMA_CSR_WCX_OFS); //pdsc->reg_init.csr |= (SWIC_DMA_CSR_WCX_MSK << SWIC_DMA_CSR_WCX_OFS); pdsc->reg_init.csr |= SWIC_DMA_CSR_RUN; pdsc->desc.size = 0; //PRINT("csr=%Xh ir=%Xh sz=%u\n", pdsc->reg_init.csr, pdsc->reg_init.ir, pdsc->desc.size); } for( i=0; ((i < 4) && pdsc); ++i, pdsc = pdsc->p_next) { pdsc->desc = p_desc->desc; //PRINT("csr=%Xh ir=%Xh sz=%u\n", pdsc->reg_init.csr, pdsc->reg_init.ir, pdsc->desc.size); } for( i=0, pdsc=p_desc; ((i < 10) && pdsc); ++i, pdsc = pdsc->p_next) { PRINT("csr=%Xh ir=%Xh cp=%Xh sz=%u\n", pdsc->reg_init.csr, pdsc->reg_init.ir, pdsc->reg_init.cp, pdsc->desc.size); } //p_desc->desc.size = 8; //p_desc->reg_init.csr &= ~SWIC_DMA_CSR_RUN; } #endif //0 // first chain initialization: PRINT("drv_gspw_write: first chain initialization\n"); print_dma_tx_desc_regs( "drv_spw_write"); //print_dma_tx_data_regs( "drv_spw_write"); if( p_desc != (dma_desc_fi_t *)fifo_hold_first_free( pff_desc)) PRINT( "drv_gspw_write: ERROR: Trying of using free said TX descriptor list from several threads!\n"); MC_CP_GSPW_TX_DAT = mips_virt_to_phys((unsigned)&p_data->reg_init) | 1; //for( i=0; i<3; ++i) // PRINT( "%Xh %Xh %Xh %Xh\n", MC_RUN_GSPW_TX_DES, MC_IR_GSPW_TX_DES, MC_RUN_GSPW_TX_DAT, MC_IR_GSPW_TX_DAT); MC_CP_GSPW_TX_DES = mips_virt_to_phys((unsigned)&p_desc->reg_init) | 1; #if 0 for( i=0; i<45; ++i) { run = MC_RUN_GSPW_TX_DES; PRINT( "%Xh %Xh %Xh %Xh %Xh\n", run, MC_IR_GSPW_TX_DES, MC_CP_GSPW_TX_DES, MC_RUN_GSPW_TX_DAT, MC_IR_GSPW_TX_DAT); if( !(run & SWIC_DMA_CSR_RUN)) { //MC_CSR_GSPW_TX_DES |= (SWIC_DMA_CSR_RUN); //| SWIC_DMA_CSR_CHEN MC_RUN_GSPW_TX_DES |= (SWIC_DMA_CSR_RUN); PRINT( "+RUN\n"); } /*if( i==3 && !(MC_RUN_GSPW_TX_DES & SWIC_DMA_CSR_RUN)) { PRINT("!!!\n"); //MC_RUN_GSPW_TX_DES |= SWIC_DMA_CSR_RUN; MC_CSR_GSPW_TX_DES |= SWIC_DMA_CSR_RUN; }*/ } run = MC_RUN_GSPW_TX_DES; ir = MC_IR_GSPW_TX_DES; PRINT( "drv_spw_write: to next chain item, TX_RUN=%Xh, TX_IR=%Xh\n", run, ir); #endif //0 is_init_tx_desc_chain = 1; print_dma_tx_desc_regs( "drv_spw_write after"); //print_dma_tx_data_regs( "drv_spw_write after"); } #endif //0 //if( p_desc != (dma_desc_fi_t *)fifo_hold_first_free( pff_desc)) // PRINT( "drv_gspw_write: ERROR: Trying of using free said TX descriptor list from several threads!\n"); p_desc = NULL; continue; } //- end: if( (p_desc->pos_proc == p_desc->desc.size) || (sz_wr_avail == 0)) sz_desc_data = p_desc->desc.size - p_desc->pos_proc; sz_data_buf_avail = pch_data->sz_data_buf - p_data->pos_proc; len_data = min3( sz_wr_avail, sz_desc_data, sz_data_buf_avail); //PRINT("drv_gspw_write: min3=%u\n", len_data); if( len_data==0 ) break; continue; l_wait_data:; wake_up_interruptible( &pcfg->wq_txjob); p_job = NULL; p_desc = NULL; p_data = NULL; //enable_irq( spw_tx_data_irq()); if( (p_data=(dma_data_fi_t *)fifo_get_first_free( pff_data))==NULL ) { PRINT("gspw_dev_write: wait_event_interruptible(data):\n"); print_fifo_held_qnt( pcfg, "write_data_wait"); if( wait_event_interruptible( pcfg->wq_txdata, fifo_get_first_free( pff_data))) { //disable_irq( spw_tx_data_irq()); PRINT("gspw_dev_write: wait_event_interruptible(data) -> -ERESTARTSYS\n"); return -ERESTARTSYS; } } //disable_irq( spw_tx_data_irq()); continue; l_wait_desc:; wake_up_interruptible( &pcfg->wq_txjob); p_job = NULL; p_desc = NULL; p_data = NULL; //enable_irq( spw_tx_desc_irq()); if( (p_desc=(dma_desc_fi_t *)fifo_get_first_free( pff_desc))==NULL ) { /*PRINT*/pr_info("gspw_dev_write: wait_event_interruptible(desc):\n"); print_fifo_held_qnt( pcfg, "write_desc_wait"); //wait_event_timeout() if( wait_event_interruptible( pcfg->wq_txdesc, fifo_get_first_free( pff_desc))) { //disable_irq( spw_tx_desc_irq()); PRINT("gspw_dev_write: wait_event_interruptible(desc) -> -ERESTARTSYS\n"); return -ERESTARTSYS; } } //disable_irq( spw_tx_desc_irq()); } //- end: while(1) if( gspw_sw.mode != GSPW_MODE_WORK) gspw_sw.is_tx_stop |= (1 << spw_num); //pr_info( "drv_gspw_write: END mutex_unlock() tid=%li\n", sys_gettid()); //complete( &pcfg->compl_tx); //mutex_unlock( &pcfg->mut_tx); PRINT( "gspw_dev_write: END: '%s%d' completed=%d\n", INTF_NAME(is_net), dev_num, completed); return completed; } //- end: drv_gspw_write() static ssize_t drv_gspw_write( struct file *file, const char *p_buf, size_t size, loff_t *ppos) { unsigned int minor = iminor( file->f_dentry->d_inode); ssize_t rc; mutex_lock( &pspw->mtx_tx); rc = gspw_dev_write( minor, 0, p_buf, size, ppos); mutex_unlock( &pspw->mtx_tx); return rc; } //const char *paGspwIrqName[8] = { "gspw0", "gspw1", "gspw2", "gspw3", "gspw4", "gspw5", "gspw6", "gspw7"}; // open configure port controller work: static int drv_gspw_open( struct inode *p_inode, struct file *p_file) { unsigned dev_num = iminor(p_inode); //- получаем номер конфигурационного канала //gspw_t *u; gspw_cfg_ctrl_t *pcfg; gspw_ctrl_t *pspw; int ret, i; //fifo_t *pff; //dma_desc_fi_t *p_desc; //dma_data_fi_t *p_data; pr_info( "gspw_dev_open: open device '%s%d'\n", DEV_NAME, dev_num); //PDEBUG( "drv_gspw_open: MASKR0 = %08X, QSTR0 = %08X\n", MC_MASKR0, MC_QSTR0); if( (dev_num != GSPW_PORT_CFG) && (dev_num != GSPW_PORT_SWIC0) && (dev_num != GSPW_PORT_SWIC1)) return -ENXIO; if( dev_num==GSPW_PORT_CFG) { pcfg = &gspw_sw.cfg_ctrl; // Запрещаем повторное открытие порта if( pcfg->port.open) return -EBUSY; //drv_gspw_struct_init( pcfg, chan_num); //pr_info( "drv_gspw_open: pcfg->port.nonblock\n"); //pcfg->port.nonblock = p_file->f_flags & O_NONBLOCK; // Set DMA irqs: //pr_info( "spw_rx_desc_irq()=%Xh, port.name='%s'\n", spw_rx_desc_irq(), pcfg->port.name); ret = request_irq( spw_rx_desc_irq(), drv_spw_dma_rx_desc_ih, 0 /*irq_flags*/, pcfg->port.name, pcfg); if( ret) return -EFAULT; //pr_info( "***EDN: request_irq(spw_rx_data_irq)\n"); ret = request_irq( spw_rx_data_irq(), drv_spw_dma_rx_data_ih, 0 /*irq_flags*/, pcfg->port.name, pcfg); if( ret) { free_irq( spw_rx_desc_irq(), pcfg); return -EFAULT; } //pr_info( "request_irq(spw_tx_data_irq)\n"); ret = request_irq( spw_tx_data_irq(), drv_spw_dma_tx_data_ih, 0 /*irq_flags*/, pcfg->port.name, pcfg); if( ret) { free_irq( spw_rx_desc_irq(), pcfg); free_irq( spw_rx_data_irq(), pcfg); return -EFAULT; } //pr_info( "request_irq(spw_tx_desc_irq)\n"); ret = request_irq( spw_tx_desc_irq(), drv_spw_dma_tx_desc_ih, 0 /*irq_flags*/, pcfg->port.name, pcfg); if( ret) { free_irq( spw_rx_desc_irq(), pcfg); free_irq( spw_rx_data_irq(), pcfg); free_irq( spw_tx_data_irq(), pcfg); return -EFAULT; } // Set connection irqs: //pr_info( "GSPW_RISC_IRQ_MSK_REG=%Xh\n", GSPW_RISC_IRQ_MSK_REG); GSPW_RISC_IRQ_MSK_REG &= ~(GSPW_RISC_IRQ_MSK_CON | GSPW_RISC_IRQ_MSK_DISCON); GSPW_RISC_IRQ_MSK_REG |= (GSPW_RISC_IRQ_MSK_CON | GSPW_RISC_IRQ_MSK_DISCON); pr_info( " GSPW_RISC_IRQ_MSK_REG=%Xh\n", GSPW_RISC_IRQ_MSK_REG); pr_info( " GSPW_ID_NET_REG=%Xh\n", GSPW_ID_NET_REG); #if 0 //pr_info( "for(...)\n"); { //char s[100]; for( i=0; (i < 8); ++i) { //snprintf( s, sizeof(s), "gspw_%i", i); pr_info( "request_irq( %i '%s'): irq=%u, handler=0x%p\n", i, paGspwIrqName[i], spw_change_state_irq(i), drv_spw_change_state_ih); ret = request_irq( spw_change_state_irq(i), drv_spw_change_state_ih, IRQF_SHARED, paGspwIrqName[i], pcfg); if (ret) { pr_info( "request_irq( '%s') -> %i\n", paGspwIrqName[i], ret); break; } /*pr_info( "disable_irq:\n"); disable_irq( spw_change_state_irq(i)); pr_info( "enable_irq:\n"); enable_irq( spw_change_state_irq(i));*/ } } #endif //0 #if 0 for( i=0; (i < GSPW_SPW_PORT_QNT); ++i) { //ret = request_irq( spw_change_state_irq(i), drv_spw_change_state_ih, 0, gspw_sw.name, &gspw_sw); ret = request_irq( spw_change_state_irq(i), drv_spw_change_state_ih, 0, gspw_sw.a_gspwc[i].port.name, &gspw_sw.a_gspwc[i]); if( ret) { pr_info( "request_irq( '%s') -> %i\n", gspw_sw.a_gspwc[i].port.name, ret); free_irq( spw_rx_desc_irq(), pcfg); free_irq( spw_rx_data_irq(), pcfg); free_irq( spw_tx_data_irq(), pcfg); for( --i; (i >=0); --i) free_irq( spw_change_state_irq(i), &gspw_sw.a_gspwc[i]); return -EFAULT; } } #endif //0 //-EDN: pcfg->port.open = 1; /* -EDN: pr_info( "disable_irq(spw_rx_desc_irq)\n"); disable_irq( spw_rx_desc_irq()); //- ??? */ //pr_info( "disable_irq(spw_tx_data_irq)\n"); //disable_irq( spw_tx_data_irq()); //- ??? //spw_clean_dma (u); //-EDN: spw_start( pcfg); pr_info( "gspw_cfg_ctrl_start()\n"); gspw_cfg_ctrl_start( pcfg); PDEBUG( "GSPW_CFG_PORT_NUM: MASKR0 = %08X, QSTR0 = %08X\n", MC_MASKR0, MC_QSTR0); pr_info( "STATE=%Xh\n", GSPW_STATE_REG); pcfg->port.open = 1; // pcfg->port.net_usage = (is_net ? 1 : 0); // Start DMA work: pr_info("RX_DESC: CP=%Xh, IR=%Xh, RUN=%Xh\n", SWIC_DMA_CP( SWIC_RX_DESC_CHAN), SWIC_DMA_IR( SWIC_RX_DESC_CHAN), SWIC_DMA_RUN( SWIC_RX_DESC_CHAN)); pr_info("RX_DATA: CP=%Xh, IR=%Xh, RUN=%Xh\n", SWIC_DMA_CP( SWIC_RX_DATA_CHAN), SWIC_DMA_IR( SWIC_RX_DATA_CHAN), SWIC_DMA_RUN( SWIC_RX_DATA_CHAN)); //pr_info("IRQ: rx_desc=%u rx_data=%u\n", spw_rx_desc_irq(), spw_rx_data_irq()); // 25 26 //pr_info("1) IRQ_MSK0=%Xh, IRQ_REQ0=%Xh\n", SYS_IRQ_MSK0_REG, SYS_IRQ_REQ0_REG); //+EDN: //disable_irq( spw_rx_desc_irq()); //disable_irq( spw_rx_data_irq()); //pr_info("2) IRQ_MSK0=%Xh, IRQ_REQ0=%Xh\n", SYS_IRQ_MSK0_REG, SYS_IRQ_REQ0_REG); //SWIC_DMA_CSR( SWIC_RX_DESC_CHAN); // Сброс признака прерывания //SWIC_DMA_CSR( SWIC_RX_DATA_CHAN); // Сброс признака прерывания //SWIC_DMA_CSR( SWIC_RX_DESC_CHAN) = 0; //SWIC_DMA_CSR( SWIC_RX_DATA_CHAN) = 0; //SWIC_DMA_CP( pdbuf->dma_chan) = mips_virt_to_phys (pcur->chain_addr) | 1; //enable_irq( spw_rx_data_irq()); //enable_irq( spw_rx_desc_irq()); //pr_info("3) IRQ_MSK0=%Xh, IRQ_REQ0=%Xh\n", SYS_IRQ_MSK0_REG, SYS_IRQ_REQ0_REG); // first initialization DMA RX chain registers: // init_dma_rx_desk_chain_reg( pcfg); // init_dma_rx_data_chain_reg( pcfg); //enable_irq( spw_rx_data_irq()); //enable_irq( spw_rx_desc_irq()); } else if( (dev_num == GSPW_PORT_SWIC0) || (dev_num == GSPW_PORT_SWIC1)) { unsigned spw_num = dev_num - 1; pspw = &gspw_sw.a_gspwc[spw_num]; // Запрещаем повторное открытие порта if( pspw->port.open) return -EBUSY; mutex_lock( &pspw->mtx_rx); //pspw->port.nonblock = p_file->f_flags & O_NONBLOCK; if( request_irq( spw_change_state_irq(spw_num), drv_spw_change_state_ih, 0, pspw->port.name, pspw)) { pr_info( "request_irq( '%s') -> %i\n", gspw_sw.a_gspwc[i].port.name, ret); mutex_unlock( &pspw->mtx_rx); return -EINVAL; } disable_irq( spw_change_state_irq(spw_num)); gspw_ctrl_start( pspw); enable_irq( spw_change_state_irq(spw_num)); pspw->port.open = 1; mutex_unlock( &pspw->mtx_rx); //pspw->port.net_usage = (is_net ? 1 : 0); PDEBUG( "GSPW_FIRST_SPW_PORT_NUM: MASKR0 = %08X, QSTR0 = %08X\n", MC_MASKR0, MC_QSTR0); } else { PDEBUG( "gspw_dev_open: Device '%s%d' is absent\n", DEV_NAME, dev_num); return -ENXIO; } PDEBUG( "gspw_dev_open: Device '%s%d' is done!\n", DEV_NAME, dev_num); return RC_SPW_SUCCESS; } static int drv_gspw_close( struct inode *inode, struct file *p_file) { unsigned dev_num = iminor(inode); // получаем номер устройства (канала SpW) //gspw_t *u = &gspw_chan[ chan_num]; gspw_cfg_ctrl_t *pcfg; gspw_ctrl_t *pspw; int i; if( (dev_num < GSPW_CFG_PORT_NUM) || (dev_num >= GSPW_FIRST_SPW_PORT_NUM + GSPW_SPW_PORT_QNT)) return -ENXIO; pr_info( "gspw_dev_close: '%s%d'\n", DEV_NAME, dev_num); if( dev_num==GSPW_PORT_CFG) { pcfg = &gspw_sw.cfg_ctrl; if( !pcfg->port.open) return 0; for( i=0; (i < MAX_SPW_PORT_QNT) ;++i) { pspw = &gspw_sw.a_gspwc[i]; if( pspw->port.open) { pr_info( "drv_gspw_close: Could not close '%s%d': net interface '%s%d' is still opened\n", DEV_NAME, dev_num, DEV_NAME, i); return -EBUSY; } } free_irq( spw_rx_desc_irq(), pcfg); free_irq( spw_rx_data_irq(), pcfg); free_irq( spw_tx_data_irq(), pcfg); free_irq( spw_tx_desc_irq(), pcfg); //for( i=0; (i < 8); ++i) // free_irq( spw_change_state_irq(i), &gspw_sw); //for( i=0; (i < GSPW_SPW_PORT_QNT); ++i) // free_irq( spw_change_state_irq(i), &gspw_sw.a_gspwc[i]); gspw_cfg_ctrl_stop( pcfg); pcfg->port.nonblock &= ~O_NONBLOCK; pcfg->port.open = 0; } else if( (dev_num == GSPW_PORT_SWIC0) || (dev_num ==GSPW_PORT_SWIC1)) { unsigned spw_num = dev_num - 1; pspw = &gspw_sw.a_gspwc[spw_num]; if( !pspw->port.open) return RC_SPW_SUCCESS; mutex_lock( &pspw->mtx_rx); if( pspw->port.net_usage) { pr_info( "drv_gspw_close: Could not close '%s%d': net interface '%s%d' is still opened\n", DEV_NAME, dev_num, ETHOSPW_DEV_NAME, i); mutex_unlock( &pspw->mtx_rx); return -EBUSY; } free_irq( spw_change_state_irq(spw_num), pspw); gspw_ctrl_stop( pspw); //pcfg->port.nonblock &= ~O_NONBLOCK; pspw->port.open = 0; pspw->connected = 0; pspw->bds = 0; mutex_unlock( &pspw->mtx_rx); } else { PDEBUG( "SpaceWire port '%s%d' is absent\n", DEV_NAME, dev_num); return EINVAL; } return RC_SPW_SUCCESS; } /*static void print_sys_regs(void) { pr_info( "print_sys_regs:\n"); pr_info( " CRPLL=%.8Xh\n", MC_CRPLL); pr_info( " CRPLL1=%.8Xh\n", MC_CRPLL1); pr_info( " CLKEN=%.8Xh\n", MC_CLKEN); pr_info( " MC_CSR=%.8Xh\n", MC_CSR); }*/ static int drv_gspw_sw_module_init(void) { int rc = EPERM; int err = 0; const unsigned EXPECTED_HW_VER = 0x00000008; PDEBUG( "drv_gspw_sw_module_init:\n"); pr_info( "\ndrv_gspw_sw_module_init:\n"); if( is_init_gspw_switch) { pr_info( "Could not reinitialize '%s' driver \n", GSPW_DEV_NAME); return ENODEV; } //print_sys_regs(); SYS_CSR_REG |= YS_CSR_GSPW_CLK_PLL; //print_sys_regs(); if( GSPW_ID_VER_REG != EXPECTED_HW_VER) { printk( GSPW_DEV_NAME ": not detected!\n"); return ENODEV; } //pr_info( "drv_gspw_sw_module_init: register_chrdev()\n"); if( register_chrdev( GSPW_SW_MAJOR, GSPW_DEV_NAME, &gspwsw_fops) < 0) { printk( GSPW_DEV_NAME ": unable to create char device with major number %d\n", GSPW_SW_MAJOR); return ENODEV; } //pr_info( "drv_gspw_sw_module_init: class_create()\n"); p_gspwsw_class = class_create( THIS_MODULE, GSPW_DEV_NAME); if( IS_ERR( p_gspwsw_class)) { printk( GSPW_DEV_NAME ": class ERROR!\n"); err = PTR_ERR (p_gspwsw_class); rc = EPERM; goto l_err; } pr_info( "drv_gspw_sw_module_init: gspw_sw__init()\n"); gspw_sw__init( &gspw_sw); #ifdef USE_ETHOSPW drv_ethospw_init(); #endif //USE_ETHOSPW pr_info( "drv_gspw_sw_module_init: done!\n"); is_init_gspw_switch = 1; return 0; l_err: PDEBUG( "drv_gspw_sw_module_init: unregister_chrdev()\n"); unregister_chrdev( GSPW_SW_MAJOR, GSPW_DEV_NAME); return rc; } static void __exit drv_gspw_sw_module_exit( void) { gspw_cfg_ctrl_t *pcfg = &gspw_sw.cfg_ctrl; int i; #ifdef USE_ETHOSPW drv_ethospw_exit(); #endif //USE_ETHOSPW gspw_cfg_ctrl_stop( pcfg); set_configure_mode(); mdelay( 1500); for( i=0; (i < MAX_SPW_PORT_QNT) ;++i) gspw_ctrl__exit( &gspw_sw.a_gspwc[i]); gspw_cfg_ctrl_free( pcfg); gspw_sw__exit( &gspw_sw); PDEBUG( "drv_gspw_sw_module_exit: unregister_chrdev()\n"); unregister_chrdev( GSPW_SW_MAJOR, GSPW_DEV_NAME); if( p_gspwsw_class == NULL) { pr_info( "drv_gspw_sw_module_exit: class_destroy()\n"); class_destroy( p_gspwsw_class); } PDEBUGG ("drv_gspw_sw_module_exit: done!\n"); } module_init( drv_gspw_sw_module_init); module_exit( drv_gspw_sw_module_exit); MODULE_DESCRIPTION("Multicore GigaSpacewire Switch driver"); MODULE_AUTHOR("Dmitry Evtushenko"); MODULE_LICENSE("GPL");