⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dbdma.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
		if ( stp->dev_flags & DEV_FLAGS_BURSTABLE )			src1 |= DSCR_SRC1_SAM(DSCR_xAM_BURST);		else		src1 |= DSCR_SRC1_SAM(DSCR_xAM_STATIC);	}	if (stp->dev_physaddr)		src0 = stp->dev_physaddr;	/* Set up dest1.  For now, assume no stride and increment.	 * A channel attribute update can change this later.	 */	switch (dtp->dev_tsize) {	case 1:		dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE1);		break;	case 2:		dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE2);		break;	case 4:		dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE4);		break;	case 8:	default:		dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE8);		break;	}	/* If destination output is fifo, set static address.	*/	if (dtp->dev_flags & DEV_FLAGS_OUT) {		if ( dtp->dev_flags & DEV_FLAGS_BURSTABLE )	                dest1 |= DSCR_DEST1_DAM(DSCR_xAM_BURST);				else		dest1 |= DSCR_DEST1_DAM(DSCR_xAM_STATIC);	}	if (dtp->dev_physaddr)		dest0 = dtp->dev_physaddr;#if 0		printk("did:%x sid:%x cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n",			dtp->dev_id, stp->dev_id, cmd0, cmd1, src0, src1, dest0, dest1 );#endif	for (i=0; i<entries; i++) {		dp->dscr_cmd0 = cmd0;		dp->dscr_cmd1 = cmd1;		dp->dscr_source0 = src0;		dp->dscr_source1 = src1;		dp->dscr_dest0 = dest0;		dp->dscr_dest1 = dest1;		dp->dscr_stat = 0;		dp->sw_context = 0;		dp->sw_status = 0;		dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(dp + 1));		dp++;	}	/* Make last descrptor point to the first.	*/	dp--;	dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(ctp->chan_desc_base));	ctp->get_ptr = ctp->put_ptr = ctp->cur_ptr = ctp->chan_desc_base;	return (u32)(ctp->chan_desc_base);}EXPORT_SYMBOL(au1xxx_dbdma_ring_alloc);/* Put a source buffer into the DMA ring. * This updates the source pointer and byte count.  Normally used * for memory to fifo transfers. */u32_au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags){	chan_tab_t		*ctp;	au1x_ddma_desc_t	*dp;	/* I guess we could check this to be within the	 * range of the table......	 */	ctp = *((chan_tab_t **)chanid);	/* We should have multiple callers for a particular channel,	 * an interrupt doesn't affect this pointer nor the descriptor,	 * so no locking should be needed.	 */	dp = ctp->put_ptr;	/* If the descriptor is valid, we are way ahead of the DMA	 * engine, so just return an error condition.	 */	if (dp->dscr_cmd0 & DSCR_CMD0_V) {		return 0;	}	/* Load up buffer address and byte count.	*/	dp->dscr_source0 = virt_to_phys(buf);	dp->dscr_cmd1 = nbytes;	/* Check flags  */	if (flags & DDMA_FLAGS_IE)		dp->dscr_cmd0 |= DSCR_CMD0_IE;	if (flags & DDMA_FLAGS_NOIE)		dp->dscr_cmd0 &= ~DSCR_CMD0_IE;	/*	 * There is an errata on the Au1200/Au1550 parts that could result	 * in "stale" data being DMA'd. It has to do with the snoop logic on	 * the dache eviction buffer.  NONCOHERENT_IO is on by default for	 * these parts. If it is fixedin the future, these dma_cache_inv will	 * just be nothing more than empty macros. See io.h.	 * */	dma_cache_wback_inv((unsigned long)buf, nbytes);        dp->dscr_cmd0 |= DSCR_CMD0_V;        /* Let it rip */	au_sync();	dma_cache_wback_inv((unsigned long)dp, sizeof(dp));        ctp->chan_ptr->ddma_dbell = 0;	/* Get next descriptor pointer.	*/	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));	/* return something not zero.	*/	return nbytes;}EXPORT_SYMBOL(_au1xxx_dbdma_put_source);/* Put a destination buffer into the DMA ring. * This updates the destination pointer and byte count.  Normally used * to place an empty buffer into the ring for fifo to memory transfers. */u32_au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags){	chan_tab_t		*ctp;	au1x_ddma_desc_t	*dp;	/* I guess we could check this to be within the	 * range of the table......	 */	ctp = *((chan_tab_t **)chanid);	/* We should have multiple callers for a particular channel,	 * an interrupt doesn't affect this pointer nor the descriptor,	 * so no locking should be needed.	 */	dp = ctp->put_ptr;	/* If the descriptor is valid, we are way ahead of the DMA	 * engine, so just return an error condition.	 */	if (dp->dscr_cmd0 & DSCR_CMD0_V)		return 0;	/* Load up buffer address and byte count */	/* Check flags  */	if (flags & DDMA_FLAGS_IE)		dp->dscr_cmd0 |= DSCR_CMD0_IE;	if (flags & DDMA_FLAGS_NOIE)		dp->dscr_cmd0 &= ~DSCR_CMD0_IE;	dp->dscr_dest0 = virt_to_phys(buf);	dp->dscr_cmd1 = nbytes;#if 0	printk("cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n",			dp->dscr_cmd0, dp->dscr_cmd1, dp->dscr_source0,			dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1 );#endif	/*	 * There is an errata on the Au1200/Au1550 parts that could result in	 * "stale" data being DMA'd. It has to do with the snoop logic on the	 * dache eviction buffer. NONCOHERENT_IO is on by default for these	 * parts. If it is fixedin the future, these dma_cache_inv will just	 * be nothing more than empty macros. See io.h.	 * */	dma_cache_inv((unsigned long)buf,nbytes);	dp->dscr_cmd0 |= DSCR_CMD0_V;	/* Let it rip */	au_sync();	dma_cache_wback_inv((unsigned long)dp, sizeof(dp));        ctp->chan_ptr->ddma_dbell = 0;	/* Get next descriptor pointer.	*/	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));	/* return something not zero.	*/	return nbytes;}EXPORT_SYMBOL(_au1xxx_dbdma_put_dest);/* Get a destination buffer into the DMA ring. * Normally used to get a full buffer from the ring during fifo * to memory transfers.  This does not set the valid bit, you will * have to put another destination buffer to keep the DMA going. */u32au1xxx_dbdma_get_dest(u32 chanid, void **buf, int *nbytes){	chan_tab_t		*ctp;	au1x_ddma_desc_t	*dp;	u32			rv;	/* I guess we could check this to be within the	 * range of the table......	 */	ctp = *((chan_tab_t **)chanid);	/* We should have multiple callers for a particular channel,	 * an interrupt doesn't affect this pointer nor the descriptor,	 * so no locking should be needed.	 */	dp = ctp->get_ptr;	/* If the descriptor is valid, we are way ahead of the DMA	 * engine, so just return an error condition.	 */	if (dp->dscr_cmd0 & DSCR_CMD0_V)		return 0;	/* Return buffer address and byte count.	*/	*buf = (void *)(phys_to_virt(dp->dscr_dest0));	*nbytes = dp->dscr_cmd1;	rv = dp->dscr_stat;	/* Get next descriptor pointer.	*/	ctp->get_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));	/* return something not zero.	*/	return rv;}voidau1xxx_dbdma_stop(u32 chanid){	chan_tab_t	*ctp;	au1x_dma_chan_t *cp;	int halt_timeout = 0;	ctp = *((chan_tab_t **)chanid);	cp = ctp->chan_ptr;	cp->ddma_cfg &= ~DDMA_CFG_EN;	/* Disable channel */	au_sync();	while (!(cp->ddma_stat & DDMA_STAT_H)) {		udelay(1);		halt_timeout++;		if (halt_timeout > 100) {			printk("warning: DMA channel won't halt\n");			break;		}	}	/* clear current desc valid and doorbell */	cp->ddma_stat |= (DDMA_STAT_DB | DDMA_STAT_V);	au_sync();}EXPORT_SYMBOL(au1xxx_dbdma_stop);/* Start using the current descriptor pointer.  If the dbdma encounters * a not valid descriptor, it will stop.  In this case, we can just * continue by adding a buffer to the list and starting again. */voidau1xxx_dbdma_start(u32 chanid){	chan_tab_t	*ctp;	au1x_dma_chan_t *cp;	ctp = *((chan_tab_t **)chanid);	cp = ctp->chan_ptr;	cp->ddma_desptr = virt_to_phys(ctp->cur_ptr);	cp->ddma_cfg |= DDMA_CFG_EN;	/* Enable channel */	au_sync();	cp->ddma_dbell = 0;	au_sync();}EXPORT_SYMBOL(au1xxx_dbdma_start);voidau1xxx_dbdma_reset(u32 chanid){	chan_tab_t		*ctp;	au1x_ddma_desc_t	*dp;	au1xxx_dbdma_stop(chanid);	ctp = *((chan_tab_t **)chanid);	ctp->get_ptr = ctp->put_ptr = ctp->cur_ptr = ctp->chan_desc_base;	/* Run through the descriptors and reset the valid indicator.	*/	dp = ctp->chan_desc_base;	do {		dp->dscr_cmd0 &= ~DSCR_CMD0_V;		/* reset our SW status -- this is used to determine		 * if a descriptor is in use by upper level SW. Since		 * posting can reset 'V' bit.		 */		dp->sw_status = 0;		dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));	} while (dp != ctp->chan_desc_base);}EXPORT_SYMBOL(au1xxx_dbdma_reset);u32au1xxx_get_dma_residue(u32 chanid){	chan_tab_t	*ctp;	au1x_dma_chan_t *cp;	u32		rv;	ctp = *((chan_tab_t **)chanid);	cp = ctp->chan_ptr;	/* This is only valid if the channel is stopped.	*/	rv = cp->ddma_bytecnt;	au_sync();	return rv;}voidau1xxx_dbdma_chan_free(u32 chanid){	chan_tab_t	*ctp;	dbdev_tab_t	*stp, *dtp;	ctp = *((chan_tab_t **)chanid);	stp = ctp->chan_src;	dtp = ctp->chan_dest;	au1xxx_dbdma_stop(chanid);	kfree((void *)ctp->chan_desc_base);	stp->dev_flags &= ~DEV_FLAGS_INUSE;	dtp->dev_flags &= ~DEV_FLAGS_INUSE;	chan_tab_ptr[ctp->chan_index] = NULL;	kfree(ctp);}EXPORT_SYMBOL(au1xxx_dbdma_chan_free);static irqreturn_tdbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs){	u32 intstat;	u32 chan_index;	chan_tab_t		*ctp;	au1x_ddma_desc_t	*dp;	au1x_dma_chan_t *cp;	intstat = dbdma_gptr->ddma_intstat;	au_sync();	chan_index = au_ffs(intstat) - 1;	ctp = chan_tab_ptr[chan_index];	cp = ctp->chan_ptr;	dp = ctp->cur_ptr;	/* Reset interrupt.	*/	cp->ddma_irq = 0;	au_sync();	if (ctp->chan_callback)		(ctp->chan_callback)(irq, ctp->chan_callparam, regs);	ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));	return IRQ_RETVAL(1);}static void au1xxx_dbdma_init(void){	int irq_nr;	dbdma_gptr->ddma_config = 0;	dbdma_gptr->ddma_throttle = 0;	dbdma_gptr->ddma_inten = 0xffff;	au_sync();#if defined(CONFIG_SOC_AU1550)	irq_nr = AU1550_DDMA_INT;#elif defined(CONFIG_SOC_AU1200)	irq_nr = AU1200_DDMA_INT;#else	#error Unknown Au1x00 SOC#endif	if (request_irq(irq_nr, dbdma_interrupt, SA_INTERRUPT,			"Au1xxx dbdma", (void *)dbdma_gptr))		printk("Can't get 1550 dbdma irq");}voidau1xxx_dbdma_dump(u32 chanid){	chan_tab_t		*ctp;	au1x_ddma_desc_t	*dp;	dbdev_tab_t		*stp, *dtp;	au1x_dma_chan_t *cp;		u32			i = 0;	ctp = *((chan_tab_t **)chanid);	stp = ctp->chan_src;	dtp = ctp->chan_dest;	cp = ctp->chan_ptr;	printk("Chan %x, stp %x (dev %d)  dtp %x (dev %d) \n",		(u32)ctp, (u32)stp, stp - dbdev_tab, (u32)dtp, dtp - dbdev_tab);	printk("desc base %x, get %x, put %x, cur %x\n",		(u32)(ctp->chan_desc_base), (u32)(ctp->get_ptr),		(u32)(ctp->put_ptr), (u32)(ctp->cur_ptr));	printk("dbdma chan %x\n", (u32)cp);	printk("cfg %08x, desptr %08x, statptr %08x\n",		cp->ddma_cfg, cp->ddma_desptr, cp->ddma_statptr);	printk("dbell %08x, irq %08x, stat %08x, bytecnt %08x\n",		cp->ddma_dbell, cp->ddma_irq, cp->ddma_stat, cp->ddma_bytecnt);	/* Run through the descriptors	*/	dp = ctp->chan_desc_base;	do {                printk("Dp[%d]= %08x, cmd0 %08x, cmd1 %08x\n",                        i++, (u32)dp, dp->dscr_cmd0, dp->dscr_cmd1);                printk("src0 %08x, src1 %08x, dest0 %08x, dest1 %08x\n",                        dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);                printk("stat %08x, nxtptr %08x\n",                        dp->dscr_stat, dp->dscr_nxtptr);		dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));	} while (dp != ctp->chan_desc_base);}/* Put a descriptor into the DMA ring. * This updates the source/destination pointers and byte count. */u32au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr ){	chan_tab_t *ctp;	au1x_ddma_desc_t *dp;	u32 nbytes=0;	/* I guess we could check this to be within the	* range of the table......	*/	ctp = *((chan_tab_t **)chanid);	/* We should have multiple callers for a particular channel,	* an interrupt doesn't affect this pointer nor the descriptor,	* so no locking should be needed.	*/	dp = ctp->put_ptr;	/* If the descriptor is valid, we are way ahead of the DMA	* engine, so just return an error condition.	*/	if (dp->dscr_cmd0 & DSCR_CMD0_V)		return 0;	/* Load up buffer addresses and byte count.	*/	dp->dscr_dest0 = dscr->dscr_dest0;	dp->dscr_source0 = dscr->dscr_source0;	dp->dscr_dest1 = dscr->dscr_dest1;	dp->dscr_source1 = dscr->dscr_source1;	dp->dscr_cmd1 = dscr->dscr_cmd1;	nbytes = dscr->dscr_cmd1;	/* Allow the caller to specifiy if an interrupt is generated */	dp->dscr_cmd0 &= ~DSCR_CMD0_IE;	dp->dscr_cmd0 |= dscr->dscr_cmd0 | DSCR_CMD0_V;	ctp->chan_ptr->ddma_dbell = 0;	/* Get next descriptor pointer.	*/	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));	/* return something not zero.	*/	return nbytes;}#endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -