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

📄 eni.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
	EVENT("put_dma: 0x%lx+0x%lx\n",(unsigned long) paddr,size);#if 0 /* don't complain anymore */	if (paddr & 3)		printk(KERN_ERR "put_dma: unaligned addr (0x%lx)\n",paddr);	if (size & 3)		printk(KERN_ERR "put_dma: unaligned size (0x%lx)\n",size);#endif	if (paddr & 3) {		init = 4-(paddr & 3);		if (init > size || size < 7) init = size;		DPRINTK("put_dma: %lx DMA: %d/%d bytes\n",		    (unsigned long) paddr,init,size);		dma[(*j)++] = MID_DT_BYTE | (init << MID_DMA_COUNT_SHIFT) |		    (chan << MID_DMA_CHAN_SHIFT);		dma[(*j)++] = paddr;		paddr += init;		size -= init;	}	words = size >> 2;	size &= 3;	if (words && (paddr & 31)) {		init = 8-((paddr & 31) >> 2);		if (init > words) init = words;		DPRINTK("put_dma: %lx DMA: %d/%d words\n",		    (unsigned long) paddr,init,words);		dma[(*j)++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) |		    (chan << MID_DMA_CHAN_SHIFT);		dma[(*j)++] = paddr;		paddr += init << 2;		words -= init;	}#ifdef CONFIG_ATM_ENI_BURST_TX_16W /* may work with some PCI chipsets ... */	if (words & ~15) {		DPRINTK("put_dma: %lx DMA: %d*16/%d words\n",		    (unsigned long) paddr,words >> 4,words);		dma[(*j)++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT)		    | (chan << MID_DMA_CHAN_SHIFT);		dma[(*j)++] = paddr;		paddr += (words & ~15) << 2;		words &= 15;	}#endif#ifdef CONFIG_ATM_ENI_BURST_TX_8W /* recommended */	if (words & ~7) {		DPRINTK("put_dma: %lx DMA: %d*8/%d words\n",		    (unsigned long) paddr,words >> 3,words);		dma[(*j)++] = MID_DT_8W | ((words >> 3) << MID_DMA_COUNT_SHIFT)		    | (chan << MID_DMA_CHAN_SHIFT);		dma[(*j)++] = paddr;		paddr += (words & ~7) << 2;		words &= 7;	}#endif#ifdef CONFIG_ATM_ENI_BURST_TX_4W /* probably useless if TX_8W or TX_16W */	if (words & ~3) {		DPRINTK("put_dma: %lx DMA: %d*4/%d words\n",		    (unsigned long) paddr,words >> 2,words);		dma[(*j)++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT)		    | (chan << MID_DMA_CHAN_SHIFT);		dma[(*j)++] = paddr;		paddr += (words & ~3) << 2;		words &= 3;	}#endif#ifdef CONFIG_ATM_ENI_BURST_TX_2W /* probably useless if TX_4W, TX_8W, ... */	if (words & ~1) {		DPRINTK("put_dma: %lx DMA: %d*2/%d words\n",		    (unsigned long) paddr,words >> 1,words);		dma[(*j)++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT)		    | (chan << MID_DMA_CHAN_SHIFT);		dma[(*j)++] = paddr;		paddr += (words & ~1) << 2;		words &= 1;	}#endif	if (words) {		DPRINTK("put_dma: %lx DMA: %d words\n",(unsigned long) paddr,		    words);		dma[(*j)++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) |		    (chan << MID_DMA_CHAN_SHIFT);		dma[(*j)++] = paddr;		paddr += words << 2;	}	if (size) {		DPRINTK("put_dma: %lx DMA: %d bytes\n",(unsigned long) paddr,		    size);		dma[(*j)++] = MID_DT_BYTE | (size << MID_DMA_COUNT_SHIFT) |		    (chan << MID_DMA_CHAN_SHIFT);		dma[(*j)++] = paddr;	}}static enum enq_res do_tx(struct sk_buff *skb){	struct atm_vcc *vcc;	struct eni_dev *eni_dev;	struct eni_vcc *eni_vcc;	struct eni_tx *tx;	dma_addr_t paddr;	u32 dma_rd,dma_wr;	u32 size; /* in words */	int aal5,dma_size,i,j;	DPRINTK(">do_tx\n");	NULLCHECK(skb);	EVENT("do_tx: skb=0x%lx, %ld bytes\n",(unsigned long) skb,skb->len);	vcc = ATM_SKB(skb)->vcc;	NULLCHECK(vcc);	eni_dev = ENI_DEV(vcc->dev);	NULLCHECK(eni_dev);	eni_vcc = ENI_VCC(vcc);	tx = eni_vcc->tx;	NULLCHECK(tx);#if 0 /* Enable this for testing with the "align" program */	{		unsigned int hack = *((char *) skb->data)-'0';		if (hack < 8) {			skb->data += hack;			skb->len -= hack;		}	}#endif#if 0 /* should work now */	if ((unsigned long) skb->data & 3)		printk(KERN_ERR DEV_LABEL "(itf %d): VCI %d has mis-aligned "		    "TX data\n",vcc->dev->number,vcc->vci);#endif	/*	 * Potential future IP speedup: make hard_header big enough to put	 * segmentation descriptor directly into PDU. Saves: 4 slave writes,	 * 1 DMA xfer & 2 DMA'ed bytes (protocol layering is for wimps :-)	 */	aal5 = vcc->qos.aal == ATM_AAL5;	/* check space in buffer */	if (!aal5)		size = (ATM_CELL_PAYLOAD >> 2)+TX_DESCR_SIZE;			/* cell without HEC plus segmentation header (includes			   four-byte cell header) */	else {		size = skb->len+4*AAL5_TRAILER+ATM_CELL_PAYLOAD-1;			/* add AAL5 trailer */		size = ((size-(size % ATM_CELL_PAYLOAD)) >> 2)+TX_DESCR_SIZE;						/* add segmentation header */	}	/*	 * Can I move tx_pos by size bytes without getting closer than TX_GAP	 * to the read pointer ? TX_GAP means to leave some space for what	 * the manual calls "too close".	 */	if (!NEPMOK(tx->tx_pos,size+TX_GAP,	    eni_in(MID_TX_RDPTR(tx->index)),tx->words)) {		DPRINTK(DEV_LABEL "(itf %d): TX full (size %d)\n",		    vcc->dev->number,size);		return enq_next;	}	/* check DMA */	dma_wr = eni_in(MID_DMA_WR_TX);	dma_rd = eni_in(MID_DMA_RD_TX);	dma_size = 3; /* JK for descriptor and final fill, plus final size			 mis-alignment fix */DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt);	if (!ATM_SKB(skb)->iovcnt) dma_size += 5;	else dma_size += 5*ATM_SKB(skb)->iovcnt;	if (dma_size > TX_DMA_BUF) {		printk(KERN_CRIT DEV_LABEL "(itf %d): needs %d DMA entries "		    "(got only %d)\n",vcc->dev->number,dma_size,TX_DMA_BUF);	}	DPRINTK("dma_wr is %d, tx_pos is %ld\n",dma_wr,tx->tx_pos);	if (dma_wr != dma_rd && ((dma_rd+NR_DMA_TX-dma_wr) & (NR_DMA_TX-1)) <	     dma_size) {		printk(KERN_WARNING DEV_LABEL "(itf %d): TX DMA full\n",		    vcc->dev->number);		return enq_jam;	}	paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len,	    PCI_DMA_TODEVICE);	ENI_PRV_PADDR(skb) = paddr;	/* prepare DMA queue entries */	j = 0;	eni_dev->dma[j++] = (((tx->tx_pos+TX_DESCR_SIZE) & (tx->words-1)) <<	     MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) |	     MID_DT_JK;	j++;	if (!ATM_SKB(skb)->iovcnt)		if (aal5) put_dma(tx->index,eni_dev->dma,&j,paddr,skb->len);		else put_dma(tx->index,eni_dev->dma,&j,paddr+4,skb->len-4);	else {DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */		for (i = 0; i < ATM_SKB(skb)->iovcnt; i++)			put_dma(tx->index,eni_dev->dma,&j,(unsigned long)			    ((struct iovec *) skb->data)[i].iov_base,			    ((struct iovec *) skb->data)[i].iov_len);	}	if (skb->len & 3)		put_dma(tx->index,eni_dev->dma,&j,zeroes,4-(skb->len & 3));	/* JK for AAL5 trailer - AAL0 doesn't need it, but who cares ... */	eni_dev->dma[j++] = (((tx->tx_pos+size) & (tx->words-1)) <<	     MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) |	     MID_DMA_END | MID_DT_JK;	j++;	DPRINTK("DMA at end: %d\n",j);	/* store frame */	writel((MID_SEG_TX_ID << MID_SEG_ID_SHIFT) |	    (aal5 ? MID_SEG_AAL5 : 0) | (tx->prescaler << MID_SEG_PR_SHIFT) |	    (tx->resolution << MID_SEG_RATE_SHIFT) |	    (size/(ATM_CELL_PAYLOAD/4)),tx->send+tx->tx_pos*4);/*printk("dsc = 0x%08lx\n",(unsigned long) readl(tx->send+tx->tx_pos*4));*/	writel((vcc->vci << MID_SEG_VCI_SHIFT) |            (aal5 ? 0 : (skb->data[3] & 0xf)) |	    (ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? MID_SEG_CLP : 0),	    tx->send+((tx->tx_pos+1) & (tx->words-1))*4);	DPRINTK("size: %d, len:%d\n",size,skb->len);	if (aal5)		writel(skb->len,tx->send+                    ((tx->tx_pos+size-AAL5_TRAILER) & (tx->words-1))*4);	j = j >> 1;	for (i = 0; i < j; i++) {		writel(eni_dev->dma[i*2],eni_dev->tx_dma+dma_wr*8);		writel(eni_dev->dma[i*2+1],eni_dev->tx_dma+dma_wr*8+4);		dma_wr = (dma_wr+1) & (NR_DMA_TX-1);	}	ENI_PRV_POS(skb) = tx->tx_pos;	ENI_PRV_SIZE(skb) = size;	ENI_VCC(vcc)->txing += size;	tx->tx_pos = (tx->tx_pos+size) & (tx->words-1);	DPRINTK("dma_wr set to %d, tx_pos is now %ld\n",dma_wr,tx->tx_pos);	eni_out(dma_wr,MID_DMA_WR_TX);	skb_queue_tail(&eni_dev->tx_queue,skb);queued++;	return enq_ok;}static void poll_tx(struct atm_dev *dev){	struct eni_tx *tx;	struct sk_buff *skb;	enum enq_res res;	int i;	DPRINTK(">poll_tx\n");	for (i = NR_CHAN-1; i >= 0; i--) {		tx = &ENI_DEV(dev)->tx[i];		if (tx->send)			while ((skb = skb_dequeue(&tx->backlog))) {				res = do_tx(skb);				if (res == enq_ok) continue;				DPRINTK("re-queuing TX PDU\n");				skb_queue_head(&tx->backlog,skb);requeued++;				if (res == enq_jam) return;				break;			}	}}static void dequeue_tx(struct atm_dev *dev){	struct eni_dev *eni_dev;	struct atm_vcc *vcc;	struct sk_buff *skb;	struct eni_tx *tx;	NULLCHECK(dev);	eni_dev = ENI_DEV(dev);	NULLCHECK(eni_dev);	while ((skb = skb_dequeue(&eni_dev->tx_queue))) {		vcc = ATM_SKB(skb)->vcc;		NULLCHECK(vcc);		tx = ENI_VCC(vcc)->tx;		NULLCHECK(ENI_VCC(vcc)->tx);		DPRINTK("dequeue_tx: next 0x%lx curr 0x%x\n",ENI_PRV_POS(skb),		    (unsigned) eni_in(MID_TX_DESCRSTART(tx->index)));		if (ENI_VCC(vcc)->txing < tx->words && ENI_PRV_POS(skb) ==		    eni_in(MID_TX_DESCRSTART(tx->index))) {			skb_queue_head(&eni_dev->tx_queue,skb);			break;		}		ENI_VCC(vcc)->txing -= ENI_PRV_SIZE(skb);		pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len,		    PCI_DMA_TODEVICE);		if (vcc->pop) vcc->pop(vcc,skb);		else dev_kfree_skb_irq(skb);		atomic_inc(&vcc->stats->tx);		wake_up(&eni_dev->tx_wait);dma_complete++;	}}static struct eni_tx *alloc_tx(struct eni_dev *eni_dev,int ubr){	int i;	for (i = !ubr; i < NR_CHAN; i++)		if (!eni_dev->tx[i].send) return eni_dev->tx+i;	return NULL;}static int comp_tx(struct eni_dev *eni_dev,int *pcr,int reserved,int *pre,    int *res,int unlimited){	static const int pre_div[] = { 4,16,128,2048 };	    /* 2^(((x+2)^2-(x+2))/2+1) */	if (unlimited) *pre = *res = 0;	else {		if (*pcr > 0) {			int div;			for (*pre = 0; *pre < 3; (*pre)++)				if (TS_CLOCK/pre_div[*pre]/64 <= *pcr) break;			div = pre_div[*pre]**pcr;			DPRINTK("min div %d\n",div);			*res = TS_CLOCK/div-1;		}		else {			int div;			if (!*pcr) *pcr = eni_dev->tx_bw+reserved;			for (*pre = 3; *pre >= 0; (*pre)--)				if (TS_CLOCK/pre_div[*pre]/64 > -*pcr) break;			if (*pre < 3) (*pre)++; /* else fail later */			div = pre_div[*pre]*-*pcr;			DPRINTK("max div %d\n",div);			*res = (TS_CLOCK+div-1)/div-1;		}		if (*res < 0) *res = 0;		if (*res > MID_SEG_MAX_RATE) *res = MID_SEG_MAX_RATE;	}	*pcr = TS_CLOCK/pre_div[*pre]/(*res+1);	DPRINTK("out pcr: %d (%d:%d)\n",*pcr,*pre,*res);	return 0;}static int reserve_or_set_tx(struct atm_vcc *vcc,struct atm_trafprm *txtp,    int set_rsv,int set_shp){	struct eni_dev *eni_dev = ENI_DEV(vcc->dev);	struct eni_vcc *eni_vcc = ENI_VCC(vcc);	struct eni_tx *tx;	unsigned long size,mem;	int rate,ubr,unlimited,new_tx;	int pre,res,order;	int error;	rate = atm_pcr_goal(txtp);	ubr = txtp->traffic_class == ATM_UBR;	unlimited = ubr && (!rate || rate <= -ATM_OC3_PCR ||	    rate >= ATM_OC3_PCR);	if (!unlimited) {		size = txtp->max_sdu*eni_dev->tx_mult/100;		if (size > MID_MAX_BUF_SIZE && txtp->max_sdu <=		    MID_MAX_BUF_SIZE)			size = MID_MAX_BUF_SIZE;	}	else {		if (eni_dev->ubr) {			eni_vcc->tx = eni_dev->ubr;			txtp->pcr = ATM_OC3_PCR;			return 0;		}		size = UBR_BUFFER;	}	new_tx = !eni_vcc->tx;	mem = 0; /* for gcc */	if (!new_tx) tx = eni_vcc->tx;	else {		mem = eni_alloc_mem(eni_dev,&size);		if (!mem) return -ENOBUFS;		tx = alloc_tx(eni_dev,unlimited);		if (!tx) {			eni_free_mem(eni_dev,mem,size);			return -EBUSY;		}		DPRINTK("got chan %d\n",tx->index);		tx->reserved = tx->shaping = 0;		tx->send = mem;		tx->words = size >> 2;		skb_queue_head_init(&tx->backlog);		for (order = 0; size > (1 << (order+10)); order++);		eni_out((order << MID_SIZE_SHIFT) |		    ((tx->send-eni_dev->ram) >> (MID_LOC_SKIP+2)),		    MID_TX_PLACE(tx->index));		tx->tx_pos = eni_in(MID_TX_DESCRSTART(tx->index)) &		    MID_DESCR_START;	}	error = comp_tx(eni_dev,&rate,tx->reserved,&pre,&res,unlimited);	if (!error  && txtp->min_pcr > rate) error = -EINVAL;	if (!error && txtp->max_pcr && txtp->max_pcr != ATM_MAX_PCR &&	    txtp->max_pcr < rate) error = -EINVAL;	if (!error && !ubr && rate > eni_dev->tx_bw+tx->reserved)		error = -EINVAL;	if (!error && set_rsv && !set_shp && rate < tx->shaping)		error = -EINVAL;	if (!error && !set_rsv && rate > tx->reserved && !ubr)		error = -EINVAL;	if (error) {		if (new_tx) {			tx->send = 0;			eni_free_mem(eni_dev,mem,size);		}		return error;	}	txtp->pcr = rate;	if (set_rsv && !ubr) {		eni_dev->tx_bw += tx->reserved;		tx->reserved = rate;		eni_dev->tx_bw -= rate;	}	if (set_shp || (unlimited && new_tx)) {		if (unlimited && new_tx) eni_dev->ubr = tx;		tx->prescaler = pre;		tx->resolution = res;		tx->shaping = rate;	}	if (set_shp) eni_vcc->tx = tx;	DPRINTK("rsv %d shp %d\n",tx->reserved,tx->shaping);	return 0;}static int open_tx_first(struct atm_vcc *vcc){	ENI_VCC(vcc)->tx = NULL;	if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0;	ENI_VCC(vcc)->txing = 0;	return reserve_or_set_tx(vcc,&vcc->qos.txtp,1,1);}static int open_tx_second(struct atm_vcc *vcc){	return 0; /* nothing to do */}static void close_tx(struct atm_vcc *vcc){	DECLARE_WAITQUEUE(wait,current);	struct eni_dev *eni_dev;	struct eni_vcc *eni_vcc;	eni_vcc = ENI_VCC(vcc);	if (!eni_vcc->tx) return;	eni_dev = ENI_DEV(vcc->dev);	/* wait for TX queue to drain */	DPRINTK("eni_close: waiting for TX ...\n");	add_wait_queue(&eni_dev->tx_wait,&wait);	set_current_state(TASK_UNINTERRUPTIBLE);	for (;;) {		int txing;		tasklet_disable(&eni_dev->task);		txing = skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing;		tasklet_enable(&eni_dev->task);		if (!txing) break;		DPRINTK("%d TX left\n",eni_vcc->txing);		schedule();		set_current_state(TASK_UNINTERRUPTIBLE);	}	set_current_state(TASK_RUNNING);	remove_wait_queue(&eni_dev->tx_wait,&wait);	if (eni_vcc->tx != eni_dev->ubr) {

⌨️ 快捷键说明

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