void debug_print_stts( zion_params_t *params, int ch, char *str ) { unsigned short edma_stts = (unsigned short)mbus_readw( MBUS_ADDR(params, ZION_MBUS_EDMA_EDMA_STATE(ch)) ); unsigned char sbus_stts = mbus_readb( MBUS_ADDR(params, (ZION_MBUS_EDMA_INT_SBUS_STATE(ch)+1)) ); /* unsigned short sbus_stts */ /* = mbus_readw( MBUS_ADDR(params, (ZION_MBUS_EDMA_INT_SBUS_STATE(ch))) ); */ PDEBUG( "%sCH%d EDMA state: 0x%04X, SBUS state: 0x%02X\n", str, ch ,edma_stts, sbus_stts ); }
/*************************************************************************** * zion_dmaif_event * @func * Interruption handler for EDMA * @args * zion_params_t *params [in/out]: parameters of ZION driver * int irq [in] : IRQ number * void *dev_id [in] : Device ID * u16 pci_status[in] : PCI config interrupt status * @return * void * @comment * * @author * H. Hoshino **************************************************************************/ void zion_dmaif_event(zion_params_t * params, int bit, int irq, void *dev_id, u16 pci_status) { unsigned short int_status = 0; unsigned short int_mask = 0; int ch = 0; zion_edma_params_t *edma_prms = NULL; /*** Check EDMA interruption for each channel ***/ for (ch = 0; ch < ZION_EDMA_NR_CH; ++ch) { /* Get interrupt status and mask(enable) */ int_status = (unsigned short)mbus_readw( MBUS_ADDR(params, ZION_MBUS_EDMA_INTSTTS(ch)) ); int_mask = (unsigned short)mbus_readw( MBUS_ADDR(params, ZION_MBUS_EDMA_INTENB(ch)) ); /* Memorize it ! */ params->interrupt_bits.DMA_INT[ch] |= int_status; /* for DEBUG */ /* PDEBUG( "CH%d int_status: 0x%04X, mask: 0x%04X\n", */ /* ch, int_status, int_mask ); */ /** Check interruptions (Common port) **/ if ( int_status & int_mask ) { /* Get EDMA params */ edma_prms = &(ZION_DMAIF_PARAM(params)->port_params[ZION_EDMA_CMN_PORTNO(ch)]); /* for DEBUG */ /* PDEBUG( "[CH%d port%d] Get interruptions!\n", */ /* ch, ZION_EDMA_CMN_PORTNO(ch) ); */ if ( NULL == edma_prms ) { PERROR( "[CH%d port%d] EDMA params is NULL!!\n", ch, ZION_EDMA_CMN_PORTNO(ch) ); mbus_writew( (ZION_MBUS_EDMA_DMADONEINT | ZION_MBUS_EDMA_SYNCFRMINT | ZION_MBUS_EDMA_BUFFINT_MASK | ZION_MBUS_EDMA_ERRINT_MASK), MBUS_ADDR(params, ZION_MBUS_EDMA_INTCLR(ch))); /** Clear interrupt status INT B reg **/ zion_mbus_int_clear(params, Dmaif_Int); return; } /* Set interrupt status */ spin_lock( &(edma_prms->params_lock) ); /* Spin lock */ edma_prms->int_status |= int_status; /* edma_prms->int_status = int_status; */ spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */ /* Wake up */ spin_lock( &(edma_prms->params_lock) ); /* Spin lock */ edma_prms->condition = ZION_DMAIF_DISPATCH_DONE; spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */ wake_up(&(edma_prms->zion_dmaif_wait_queue)); } /** Check sync frame pulse interruption **/ if ( int_status & int_mask & ZION_MBUS_EDMA_SYNCFRMINT ) { /* Get EDMA params */ edma_prms = &(ZION_DMAIF_PARAM(params)->port_params[ZION_EDMA_FRM_PORTNO(ch)]); /* for DEBUG */ /* PDEBUG( "[CH%d port%d] Sync frame pulse!\n", */ /* ch, ZION_EDMA_FRM_PORTNO(ch) ); */ /* Set interrupt status */ spin_lock( &(edma_prms->params_lock) ); /* Spin lock */ if ( 0 == edma_prms->int_status ) { edma_prms->int_status = int_status; } else { /* PDEBUG( "[CH%d port%d] int_status is already set(0x%04X, 0x%04X)!\n", */ /* ch, ZION_EDMA_DMA_PORTNO(ch), edma_prms->int_status, int_status ); */ } spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */ /* Clear interrupt status: sync frame pulse */ mbus_writew(ZION_MBUS_EDMA_SYNCFRMINT, MBUS_ADDR(params, ZION_MBUS_EDMA_INTCLR(ch))); /* Wake up */ spin_lock( &(edma_prms->params_lock) ); /* Spin lock */ edma_prms->condition = ZION_DMAIF_DISPATCH_DONE; spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */ wake_up(&(edma_prms->zion_dmaif_wait_queue)); } /** Check DMA done interruption **/ if ( int_status & int_mask & ZION_MBUS_EDMA_DMADONEINT ) { /* Get EDMA params */ edma_prms = &(ZION_DMAIF_PARAM(params)->port_params[ZION_EDMA_DMA_PORTNO(ch)]); /* for DEBUG */ PDEBUG( "[CH%d port%d] DMA Done!\n", ch, ZION_EDMA_DMA_PORTNO(ch) ); /* PINFO( "[CH%d port%d] DMA Done!\n", */ /* ch, ZION_EDMA_DMA_PORTNO(ch) ); */ /* Stop DMA for G1&G2 transfer mode */ { unsigned char cmd = mbus_readb( MBUS_ADDR(params, (ZION_MBUS_EDMA_DMACMD(ch)+1)) ); mbus_writeb( (cmd & (~0x02)), MBUS_ADDR(params, (ZION_MBUS_EDMA_DMACMD(ch)+1)) ); } /* for DEBUG XXX*/ /* { */ /* unsigned short usPMT = mbus_readw( MBUS_ADDR(params, ZION_MBUS_EDMA_CURRPMT(ch)) ); */ /* PDEBUG( "[CH%d port%d] CurrPMT: 0x%04X\n", */ /* ch, ZION_EDMA_DMA_PORTNO(ch), usPMT ); */ /* } */ spin_lock( &(edma_prms->params_lock) ); /* Spin lock */ /* Set interrupt status */ /* PDEBUG( "[CH%d] int_status: 0x%04X, old: 0x%04X!\n", */ /* ch, int_status, edma_prms->int_status ); */ if ( 0 == edma_prms->int_status ) { edma_prms->int_status = int_status; } else { /* PDEBUG( "[CH%d port%d] int_status is already set(0x%04X, 0x%04X)!\n", */ /* ch, ZION_EDMA_DMA_PORTNO(ch), edma_prms->int_status, int_status ); */ } /* Delete timer */ del_timer_sync(&(edma_prms->timer)); spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */ /* Clear interrupt status: DMA done */ mbus_writew(ZION_MBUS_EDMA_DMADONEINT, MBUS_ADDR(params, ZION_MBUS_EDMA_INTCLR(ch))); /* Wake up */ spin_lock( &(edma_prms->params_lock) ); /* Spin lock */ edma_prms->condition = ZION_DMAIF_DISPATCH_DONE; spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */ wake_up(&(edma_prms->zion_dmaif_wait_queue)); } /** Check error and buffer empty/almost empty/almost full/full interruption **/ if ( int_status & int_mask & (ZION_MBUS_EDMA_BUFFINT_MASK | ZION_MBUS_EDMA_ERRINT_MASK) ) { /* Get EDMA parameters */ edma_prms = &(ZION_DMAIF_PARAM (params)->port_params[ZION_EDMA_BUF_PORTNO(ch)]); /* for DEBUG */ PDEBUG( "[CH%d port%d] Error or warning!\n", ch, ZION_EDMA_BUF_PORTNO(ch) ); /* Set interrupt status */ spin_lock( &(edma_prms->params_lock) ); /* Spin lock */ /* PDEBUG( "[CH%d] int_status: 0x%04X, old: 0x%04X!\n", */ /* ch, int_status, edma_prms->int_status ); */ if ( 0 == edma_prms->int_status ) { edma_prms->int_status = int_status; } else { /* PDEBUG( "[CH%d port%d] int_status is already set(0x%04X, 0x%04X)!\n", */ /* ch, ZION_EDMA_BUF_PORTNO(ch), edma_prms->int_status, int_status ); */ } spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */ /* Clear interrupt status */ mbus_writew((ZION_MBUS_EDMA_BUFFINT_MASK | ZION_MBUS_EDMA_ERRINT_MASK), MBUS_ADDR(params, ZION_MBUS_EDMA_INTCLR(ch))); /* Wake up */ spin_lock( &(edma_prms->params_lock) ); /* Spin lock */ edma_prms->condition = ZION_DMAIF_DISPATCH_DONE; spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */ wake_up(&(edma_prms->zion_dmaif_wait_queue)); } } /* The end of FOR(ch) */ /** Clear interrupt status INT B reg **/ zion_mbus_int_clear(params, Dmaif_Int); /* PDEBUG ("exit %s\n", __FUNCTION__); */ return; }
/*************************************************************************** * zion_dmaif_port_ioctl **************************************************************************/ int zion_dmaif_port_ioctl(zion_params_t * params, struct inode *inode, struct file *file, unsigned int function, unsigned long arg) { switch (function) { case ZION_EDMA_IOC_OPEN: { unsigned char ucReg = 0; zion_edma_params_t *edma_prms = (zion_edma_params_t *)file->private_data; int ch = -1; int rw = -1; unsigned long irq_flags = 0; /* Check EDMA parameters */ if (NULL == edma_prms) { PERROR("Private data is NULL!\n"); return (-ENODEV); } /* Get and check EDMA channel number */ ch = edma_prms->ch_no; if (ch < 0 || ZION_EDMA_NR_CH <= ch) { PERROR("Invalid ZION EDMA channel number(%d)!", ch); return (-ENODEV); } /* Get argument: I/O direction */ if (copy_from_user((void *)&rw, (void *)arg, sizeof(int))) return (-EFAULT); /* Check argument: I/O direction */ if ((ZION_EDMA_READ != rw) && (ZION_EDMA_WRITE != rw)) { PERROR("[CH%d] Invalid I/O direction(%d)!\n", ch, rw); return (-EINVAL); } /* Read EDMA command register */ ucReg = mbus_readb(MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(ch) + 1)); /* Write EDMA command register: DmaOpen=1 */ ucReg |= (ZION_MBUS_EDMA_OPEN | (rw << 2)) & 0x0F; /* PDEBUG("[CH%d] EDMA open(0x%02X)\n", ch, ucReg); */ mbus_writeb(ucReg, MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(ch) + 1)); /* Clear interrupt status */ spin_lock_irqsave( &(edma_prms->params_lock), irq_flags ); edma_prms->int_status = 0x0000; spin_unlock_irqrestore( &(edma_prms->params_lock), irq_flags ); break; } case ZION_EDMA_IOC_CLOSE: { unsigned char ucReg = 0; zion_edma_params_t *edma_prms = (zion_edma_params_t *)file->private_data; int ch = -1; /* Check EDMA parameters */ if (NULL == edma_prms) { PERROR("Private data is NULL!\n"); return (-ENODEV); } /* Get and check EDMA channel number */ ch = edma_prms->ch_no; if (ch < 0 || ZION_EDMA_NR_CH <= ch) { PERROR("Invalid ZION EDMA channel number(%d)!", ch); return (-ENODEV); } /* Read EDMA command register */ ucReg = mbus_readb( MBUS_ADDR(params, (ZION_MBUS_EDMA_DMACMD(ch)+1)) ); /* Write EDMA command register: DmaOpen=0 */ ucReg &= ZION_MBUS_EDMA_CLOSE & 0x0F; /* PDEBUG("[CH%d] EDMA close(0x%02X)\n", ch, ucReg); */ mbus_writeb( ucReg, MBUS_ADDR(params, (ZION_MBUS_EDMA_DMACMD(ch)+1)) ); /* Success */ break; } case ZION_EDMA_IOC_RUN: { unsigned char ucReg = 0; zion_edma_params_t *edma_prms = (zion_edma_params_t *)file->private_data; int ch = -1; unsigned short usCmdReg = 0; /* Check EDMA parameters */ if (NULL == edma_prms) { PERROR("Private data is NULL!\n"); return (-ENODEV); } /* Get and check EDMA channel number */ ch = edma_prms->ch_no; if (ch < 0 || ZION_EDMA_NR_CH <= ch) { PERROR("Invalid ZION EDMA channel number(%d)!", ch); return (-ENODEV); } /* Read EDMA command register */ ucReg = mbus_readb(MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(ch) + 1)); /* Write EDMA command register: DmaRun=1 */ ucReg |= ZION_MBUS_EDMA_RUN; PDEBUG ("[CH%d] EDMA run(0x%02X)\n", ch, ucReg); mbus_writeb(ucReg, MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(ch) + 1)); #ifdef NEO_WRITEBACK /* for DEBUG -- write back XXX */ usCmdReg = (unsigned short)mbus_readw( MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(edma_prms->ch_no)) ); /* PDEBUG( "[CH%d] Write back DMA RUN: 0x%04X\n", */ /* edma_prms->ch_no, usCmdReg ); */ #endif /* NEO_WRITEBACK */ /* Success */ break; } case ZION_EDMA_IOC_STOP: { unsigned char ucReg = 0; zion_edma_params_t *edma_prms = (zion_edma_params_t *)file->private_data; int ch = -1; /* Check EDMA parameters */ if (NULL == edma_prms) { PERROR("Private data is NULL!\n"); return (-ENODEV); } /* Get and check EDMA channel number */ ch = edma_prms->ch_no; if (ch < 0 || ZION_EDMA_NR_CH <= ch) { PERROR("Invalid ZION EDMA channel number(%d)!", ch); return (-ENODEV); } /* Read EDMA command register */ ucReg = mbus_readb(MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(ch) + 1)); /* Write EDMA command register: DmaRun=0 */ ucReg &= ZION_MBUS_EDMA_STOP & 0x0F; /* PDEBUG("[CH%d] EDMA stop(0x%02X)\n", ch, ucReg); */ mbus_writeb(ucReg, MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(ch) + 1)); /* Success */ break; } case ZION_EDMA_IOC_READ: { /* EDMA read */ return (zion_edma_run(params, inode, file, ZION_EDMA_READ)); } case ZION_EDMA_IOC_WRITE: { /* EDMA write */ return (zion_edma_run(params, inode, file, ZION_EDMA_WRITE)); } case ZION_EDMA_IOC_SET_REGION: { struct zion_edma_region s_zion_edma_region; if (copy_from_user((void *)&s_zion_edma_region, (void *)arg, sizeof(struct zion_edma_region))) return (-EFAULT); return zion_edma_set_region(params, s_zion_edma_region.dma_ch, s_zion_edma_region.num, s_zion_edma_region.lower, s_zion_edma_region.upper); } case ZION_EDMA_IOC_GET_REGION: { struct zion_edma_region s_zion_edma_region; if (copy_from_user((void *)&s_zion_edma_region, (void *)arg, sizeof(struct zion_edma_region))) return (-EFAULT); if (zion_edma_get_region(params, s_zion_edma_region.dma_ch, s_zion_edma_region.num, &s_zion_edma_region.lower, &s_zion_edma_region.upper)) return -EINVAL; if (copy_to_user((void *)arg, (void *)&s_zion_edma_region, sizeof(struct zion_edma_region))) return -EFAULT; /* Success */ break; } /* Get interrupt status for poll-select */ case ZION_EDMA_IOC_GET_INTSTTS: { zion_edma_params_t *edma_prms = (zion_edma_params_t *)file->private_data; int ch = -1; unsigned long irq_flags = 0; /* Check EDMA parameters */ if (NULL == edma_prms) { PERROR("Invalid ZION EDMA parameters!\n"); return (-ENODEV); } /* Set and check EDMA channel number */ ch = edma_prms->ch_no; if (ch < 0 || ZION_EDMA_NR_CH <= ch) { PERROR("Invalid ZION EDMA channel number(%d)!", ch); return (-ENODEV); } /* Set interrupt status */ if (copy_to_user((void *)arg, (void *)&(edma_prms->int_status), sizeof(unsigned short))) return (-EFAULT); /* Clear interrupt status */ spin_lock_irqsave( &(edma_prms->params_lock), irq_flags ); edma_prms->int_status = 0x0000; spin_unlock_irqrestore( &(edma_prms->params_lock), irq_flags ); /* Success */ break; } default: PERROR("No such Ioctl command!\n"); return (-EINVAL); } /* The end of SWITCH(function) */ return 0; }
static int zion_common_ioctl(zion_params_t *zion_params, struct inode *inode, struct file *filp, unsigned int function, unsigned long arg) { struct zion_config_byte zion_config_byte = {0}; struct zion_config_word zion_config_word = {0}; struct zion_config_dword zion_config_dword = {0}; struct zion_buf zion_buf; struct ZION_Interrupt_Bits zion_interrupt = {0}; u16 revision; switch(function) { case ZION_MBUS_READ_CONFIG_BYTE: if(copy_from_user((void *)&zion_config_byte, (void *)arg, sizeof(struct zion_config_byte))) return -EFAULT; zion_config_byte.val = (u8) mbus_readb( MBUS_ADDR(zion_params, zion_config_byte.where) ); if(copy_to_user((void *)arg, (void *)&zion_config_byte, sizeof(struct zion_config_byte))) return -EFAULT; break; case ZION_MBUS_READ_CONFIG_WORD: if(copy_from_user((void *)&zion_config_word, (void *)arg, sizeof(struct zion_config_word))) return -EFAULT; zion_config_word.val = (u16) mbus_readw( MBUS_ADDR(zion_params,zion_config_word.where) ); if(copy_to_user((void *)arg, (void *)&zion_config_word, sizeof(struct zion_config_word))) return -EFAULT; break; case ZION_MBUS_READ_CONFIG_DWORD: if(copy_from_user((void *)&zion_config_dword, (void *)arg, sizeof(struct zion_config_dword))) return -EFAULT; zion_config_dword.val = (u32) mbus_readl( MBUS_ADDR(zion_params,zion_config_dword.where) ); if(copy_to_user((void *)arg, (void *)&zion_config_dword, sizeof(struct zion_config_dword))) return -EFAULT; break; case ZION_MBUS_WRITE_CONFIG_BYTE: if(copy_from_user((void *)&zion_config_byte, (void *)arg, sizeof(struct zion_config_byte))) return -EFAULT; mbus_writeb(zion_config_byte.val, MBUS_ADDR(zion_params, zion_config_byte.where) ); if(copy_to_user((void *)arg, (void *)&zion_config_byte, sizeof(struct zion_config_byte))) return -EFAULT; break; case ZION_MBUS_WRITE_CONFIG_WORD: if(copy_from_user((void *)&zion_config_word, (void *)arg, sizeof(struct zion_config_word))) return -EFAULT; mbus_writew(zion_config_word.val, MBUS_ADDR(zion_params, zion_config_word.where) ); if(copy_to_user((void *)arg, (void *)&zion_config_word, sizeof(struct zion_config_word))) return -EFAULT; break; case ZION_MBUS_WRITE_CONFIG_DWORD: if(copy_from_user((void *)&zion_config_dword, (void *)arg, sizeof(struct zion_config_dword))) return -EFAULT; mbus_writel(zion_config_dword.val, MBUS_ADDR(zion_params, zion_config_dword.where) ); if(copy_to_user((void *)arg, (void *)&zion_config_dword, sizeof(struct zion_config_dword))) return -EFAULT; break; case ZION_WRAM_READ: if(copy_from_user((void *)&zion_buf, (void *)arg, sizeof(struct zion_buf))) return -EFAULT; if((zion_buf.size = neo_wram_pio_read(zion_params, zion_buf.addr, zion_buf.buf, zion_buf.size, zion_buf.access_type))==0) return -EINVAL; if(copy_to_user((void *)arg, (void *)&zion_buf, sizeof(struct zion_buf))) return -EFAULT; break; case ZION_WRAM_WRITE: if(copy_from_user((void *)&zion_buf, (void *)arg, sizeof(struct zion_buf))) return -EFAULT; if((zion_buf.size = neo_wram_pio_write(zion_params, zion_buf.addr, zion_buf.buf, zion_buf.size, zion_buf.access_type))==0) return -EINVAL; if(copy_to_user((void *)arg, (void *)&zion_buf, sizeof(struct zion_buf))) return -EFAULT; break; case ZION_WAIT_INTERRUPT: zion_goto_bed(zion_params, &zion_interrupt); /* zion_interrupt.c */ if(copy_to_user((void *)arg, (void *)&zion_interrupt, sizeof(struct ZION_Interrupt_Bits))) return -EFAULT; break; case ZION_WAKE_THREADS_UP: zion_rout_them_up(zion_params); /* zion_interrupt.c */ break; case ZION_SET_ENABLE_BITS: if(copy_from_user((void *)&zion_interrupt, (void *)arg, sizeof(struct ZION_Interrupt_Bits))) return -EFAULT; zion_set_enable_bits(zion_params, &zion_interrupt); /* zion_interrupt.c */ break; case ZION_GET_ENABLE_BITS: zion_get_enable_bits(zion_params, &zion_interrupt); /* zion_interrupt.c */ if(copy_to_user((void *)arg, (void *)&zion_interrupt, sizeof(struct ZION_Interrupt_Bits))) return -EFAULT; break; case ZION_SET_TIMEOUT: zion_params->wait_timeout = arg; /* by jiffies */ break; case ZION_GET_REVISION: revision = zion_params->revision; if(copy_to_user((void *)arg, (void *)&revision, sizeof(u16))) { return -EFAULT; } break; default: PERROR("No such IOCTL.\n"); return -EINVAL; } return 0; }