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

📄 eni.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
        for (i = 0; i < j; i++) {		writel(dma[i*2],eni_dev->rx_dma+dma_wr*8);		writel(dma[i*2+1],eni_dev->rx_dma+dma_wr*8+4);		dma_wr = (dma_wr+1) & (NR_DMA_RX-1);        }	if (skb) {		ENI_PRV_POS(skb) = eni_vcc->descr+size+1;		skb_queue_tail(&eni_dev->rx_queue,skb);		eni_vcc->last = skb;rx_enqueued++;	}	eni_vcc->descr = here;	eni_out(dma_wr,MID_DMA_WR_RX);	return 0;trouble:	if (paddr)		pci_unmap_single(eni_dev->pci_dev,paddr,skb->len,		    PCI_DMA_FROMDEVICE);	if (skb) dev_kfree_skb_irq(skb);	return -1;}static void discard(struct atm_vcc *vcc,unsigned long size){	struct eni_vcc *eni_vcc;	eni_vcc = ENI_VCC(vcc);	EVENT("discard (size=%ld)\n",size,0);	while (do_rx_dma(vcc,NULL,1,size,0)) EVENT("BUSY LOOP",0,0);	    /* could do a full fallback, but that might be more expensive */	if (eni_vcc->rxing) ENI_PRV_POS(eni_vcc->last) += size+1;	else eni_vcc->rx_pos = (eni_vcc->rx_pos+size+1) & (eni_vcc->words-1);}/* * TODO: should check whether direct copies (without DMA setup, dequeuing on * interrupt, etc.) aren't much faster for AAL0 */static int rx_aal0(struct atm_vcc *vcc){	struct eni_vcc *eni_vcc;	unsigned long descr;	unsigned long length;	struct sk_buff *skb;	DPRINTK(">rx_aal0\n");	eni_vcc = ENI_VCC(vcc);	descr = readl(eni_vcc->recv+eni_vcc->descr*4);	if ((descr & MID_RED_IDEN) != (MID_RED_RX_ID << MID_RED_SHIFT)) {		rx_ident_err(vcc);		return 1;	}	if (descr & MID_RED_T) {		DPRINTK(DEV_LABEL "(itf %d): trashing empty cell\n",		    vcc->dev->number);		length = 0;		atomic_inc(&vcc->stats->rx_err);	}	else {		length = ATM_CELL_SIZE-1; /* no HEC */	}	skb = length ? atm_alloc_charge(vcc,length,GFP_ATOMIC) : NULL;	if (!skb) {		discard(vcc,length >> 2);		return 0;	}	skb_put(skb,length);	skb->stamp = eni_vcc->timestamp;	DPRINTK("got len %ld\n",length);	if (do_rx_dma(vcc,skb,1,length >> 2,length >> 2)) return 1;	eni_vcc->rxing++;	return 0;}static int rx_aal5(struct atm_vcc *vcc){	struct eni_vcc *eni_vcc;	unsigned long descr;	unsigned long size,eff,length;	struct sk_buff *skb;	EVENT("rx_aal5\n",0,0);	DPRINTK(">rx_aal5\n");	eni_vcc = ENI_VCC(vcc);	descr = readl(eni_vcc->recv+eni_vcc->descr*4);	if ((descr & MID_RED_IDEN) != (MID_RED_RX_ID << MID_RED_SHIFT)) {		rx_ident_err(vcc);		return 1;	}	if (descr & (MID_RED_T | MID_RED_CRC_ERR)) {		if (descr & MID_RED_T) {			EVENT("empty cell (descr=0x%lx)\n",descr,0);			DPRINTK(DEV_LABEL "(itf %d): trashing empty cell\n",			    vcc->dev->number);			size = 0;		}		else {			static unsigned long silence = 0;			if (time_after(jiffies, silence) || silence == 0) {				printk(KERN_WARNING DEV_LABEL "(itf %d): "				    "discarding PDU(s) with CRC error\n",				    vcc->dev->number);				silence = (jiffies+2*HZ)|1;			}			size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2);			EVENT("CRC error (descr=0x%lx,size=%ld)\n",descr,			    size);		}		eff = length = 0;		atomic_inc(&vcc->stats->rx_err);	}	else {		size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2);		DPRINTK("size=%ld\n",size);		length = readl(eni_vcc->recv+(((eni_vcc->descr+size-1) &		    (eni_vcc->words-1)))*4) & 0xffff;				/* -trailer(2)+header(1) */		if (length && length <= (size << 2)-8 && length <=		  ATM_MAX_AAL5_PDU) eff = (length+3) >> 2;		else {				 /* ^ trailer length (8) */			EVENT("bad PDU (descr=0x08%lx,length=%ld)\n",descr,			    length);			printk(KERN_ERR DEV_LABEL "(itf %d): bad AAL5 PDU "			    "(VCI=%d,length=%ld,size=%ld (descr 0x%lx))\n",			    vcc->dev->number,vcc->vci,length,size << 2,descr);			length = eff = 0;			atomic_inc(&vcc->stats->rx_err);		}	}	skb = eff ? atm_alloc_charge(vcc,eff << 2,GFP_ATOMIC) : NULL;	if (!skb) {		discard(vcc,size);		return 0;	}	skb_put(skb,length);	DPRINTK("got len %ld\n",length);	if (do_rx_dma(vcc,skb,1,size,eff)) return 1;	eni_vcc->rxing++;	return 0;}static inline int rx_vcc(struct atm_vcc *vcc){	unsigned long vci_dsc,tmp;	struct eni_vcc *eni_vcc;	eni_vcc = ENI_VCC(vcc);	vci_dsc = ENI_DEV(vcc->dev)->vci+vcc->vci*16;	EVENT("rx_vcc(1)\n",0,0);	while (eni_vcc->descr != (tmp = (readl(vci_dsc+4) & MID_VCI_DESCR) >>	    MID_VCI_DESCR_SHIFT)) {		EVENT("rx_vcc(2: host dsc=0x%lx, nic dsc=0x%lx)\n",		    eni_vcc->descr,tmp);		DPRINTK("CB_DESCR %ld REG_DESCR %d\n",ENI_VCC(vcc)->descr,		    (((unsigned) readl(vci_dsc+4) & MID_VCI_DESCR) >>		    MID_VCI_DESCR_SHIFT));		if (ENI_VCC(vcc)->rx(vcc)) return 1;	}	/* clear IN_SERVICE flag */	writel(readl(vci_dsc) & ~MID_VCI_IN_SERVICE,vci_dsc);	/*	 * If new data has arrived between evaluating the while condition and	 * clearing IN_SERVICE, we wouldn't be notified until additional data	 * follows. So we have to loop again to be sure.	 */	EVENT("rx_vcc(3)\n",0,0);	while (ENI_VCC(vcc)->descr != (tmp = (readl(vci_dsc+4) & MID_VCI_DESCR)	    >> MID_VCI_DESCR_SHIFT)) {		EVENT("rx_vcc(4: host dsc=0x%lx, nic dsc=0x%lx)\n",		    eni_vcc->descr,tmp);		DPRINTK("CB_DESCR %ld REG_DESCR %d\n",ENI_VCC(vcc)->descr,		    (((unsigned) readl(vci_dsc+4) & MID_VCI_DESCR) >>		    MID_VCI_DESCR_SHIFT));		if (ENI_VCC(vcc)->rx(vcc)) return 1;	}	return 0;}static void poll_rx(struct atm_dev *dev){	struct eni_dev *eni_dev;	struct atm_vcc *curr;	eni_dev = ENI_DEV(dev);	while ((curr = eni_dev->fast)) {		EVENT("poll_rx.fast\n",0,0);		if (rx_vcc(curr)) return;		eni_dev->fast = ENI_VCC(curr)->next;		ENI_VCC(curr)->next = ENI_VCC_NOS;		barrier();		ENI_VCC(curr)->servicing--;	}	while ((curr = eni_dev->slow)) {		EVENT("poll_rx.slow\n",0,0);		if (rx_vcc(curr)) return;		eni_dev->slow = ENI_VCC(curr)->next;		ENI_VCC(curr)->next = ENI_VCC_NOS;		barrier();		ENI_VCC(curr)->servicing--;	}}static void get_service(struct atm_dev *dev){	struct eni_dev *eni_dev;	struct atm_vcc *vcc;	unsigned long vci;	DPRINTK(">get_service\n");	eni_dev = ENI_DEV(dev);	while (eni_in(MID_SERV_WRITE) != eni_dev->serv_read) {		vci = readl(eni_dev->service+eni_dev->serv_read*4);		eni_dev->serv_read = (eni_dev->serv_read+1) & (NR_SERVICE-1);		vcc = eni_dev->rx_map[vci & 1023];		if (!vcc) {			printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %ld not "			    "found\n",dev->number,vci);			continue; /* nasty but we try to go on anyway */			/* @@@ nope, doesn't work */		}		EVENT("getting from service\n",0,0);		if (ENI_VCC(vcc)->next != ENI_VCC_NOS) {			EVENT("double service\n",0,0);			DPRINTK("Grr, servicing VCC %ld twice\n",vci);			continue;		}		ENI_VCC(vcc)->timestamp = xtime;		ENI_VCC(vcc)->next = NULL;		if (vcc->qos.rxtp.traffic_class == ATM_CBR) {			if (eni_dev->fast)				ENI_VCC(eni_dev->last_fast)->next = vcc;			else eni_dev->fast = vcc;			eni_dev->last_fast = vcc;		}		else {			if (eni_dev->slow)				ENI_VCC(eni_dev->last_slow)->next = vcc;			else eni_dev->slow = vcc;			eni_dev->last_slow = vcc;		}putting++;		ENI_VCC(vcc)->servicing++;	}}static void dequeue_rx(struct atm_dev *dev){	struct eni_dev *eni_dev;	struct eni_vcc *eni_vcc;	struct atm_vcc *vcc;	struct sk_buff *skb;	unsigned long vci_dsc;	int first;	eni_dev = ENI_DEV(dev);	first = 1;	while (1) {		skb = skb_dequeue(&eni_dev->rx_queue);		if (!skb) {			if (first) {				DPRINTK(DEV_LABEL "(itf %d): RX but not "				    "rxing\n",dev->number);				EVENT("nothing to dequeue\n",0,0);			}			break;		}		EVENT("dequeued (size=%ld,pos=0x%lx)\n",ENI_PRV_SIZE(skb),		    ENI_PRV_POS(skb));rx_dequeued++;		vcc = ATM_SKB(skb)->vcc;		eni_vcc = ENI_VCC(vcc);		first = 0;		vci_dsc = eni_dev->vci+vcc->vci*16;		if (!EEPMOK(eni_vcc->rx_pos,ENI_PRV_SIZE(skb),		    (readl(vci_dsc+4) & MID_VCI_READ) >> MID_VCI_READ_SHIFT,		    eni_vcc->words)) {			EVENT("requeuing\n",0,0);			skb_queue_head(&eni_dev->rx_queue,skb);			break;		}		eni_vcc->rxing--;		eni_vcc->rx_pos = ENI_PRV_POS(skb) & (eni_vcc->words-1);		pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len,		    PCI_DMA_TODEVICE);		if (!skb->len) dev_kfree_skb_irq(skb);		else {			EVENT("pushing (len=%ld)\n",skb->len,0);			if (vcc->qos.aal == ATM_AAL0)				*(unsigned long *) skb->data =				    ntohl(*(unsigned long *) skb->data);			memset(skb->cb,0,sizeof(struct eni_skb_prv));			vcc->push(vcc,skb);			pushed++;		}		atomic_inc(&vcc->stats->rx);	}	wake_up(&eni_dev->rx_wait);}static int open_rx_first(struct atm_vcc *vcc){	struct eni_dev *eni_dev;	struct eni_vcc *eni_vcc;	unsigned long size;	DPRINTK("open_rx_first\n");	eni_dev = ENI_DEV(vcc->dev);	eni_vcc = ENI_VCC(vcc);	eni_vcc->rx = NULL;	if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0;	size = vcc->qos.rxtp.max_sdu*eni_dev->rx_mult/100;	if (size > MID_MAX_BUF_SIZE && vcc->qos.rxtp.max_sdu <=	    MID_MAX_BUF_SIZE)		size = MID_MAX_BUF_SIZE;	eni_vcc->recv = eni_alloc_mem(eni_dev,&size);	DPRINTK("rx at 0x%lx\n",eni_vcc->recv);	eni_vcc->words = size >> 2;	if (!eni_vcc->recv) return -ENOBUFS;	eni_vcc->rx = vcc->qos.aal == ATM_AAL5 ? rx_aal5 : rx_aal0;	eni_vcc->descr = 0;	eni_vcc->rx_pos = 0;	eni_vcc->rxing = 0;	eni_vcc->servicing = 0;	eni_vcc->next = ENI_VCC_NOS;	return 0;}static int open_rx_second(struct atm_vcc *vcc){	unsigned long here;	struct eni_dev *eni_dev;	struct eni_vcc *eni_vcc;	unsigned long size;	int order;	DPRINTK("open_rx_second\n");	eni_dev = ENI_DEV(vcc->dev);	eni_vcc = ENI_VCC(vcc);	if (!eni_vcc->rx) return 0;	/* set up VCI descriptor */	here = eni_dev->vci+vcc->vci*16;	DPRINTK("loc 0x%x\n",(unsigned) (eni_vcc->recv-eni_dev->ram)/4);	size = eni_vcc->words >> 8;	for (order = -1; size; order++) size >>= 1;	writel(0,here+4); /* descr, read = 0 */	writel(0,here+8); /* write, state, count = 0 */	if (eni_dev->rx_map[vcc->vci])		printk(KERN_CRIT DEV_LABEL "(itf %d): BUG - VCI %d already "		    "in use\n",vcc->dev->number,vcc->vci);	eni_dev->rx_map[vcc->vci] = vcc; /* now it counts */	writel(((vcc->qos.aal != ATM_AAL5 ? MID_MODE_RAW : MID_MODE_AAL5) <<	    MID_VCI_MODE_SHIFT) | MID_VCI_PTI_MODE |	    (((eni_vcc->recv-eni_dev->ram) >> (MID_LOC_SKIP+2)) <<	    MID_VCI_LOCATION_SHIFT) | (order << MID_VCI_SIZE_SHIFT),here);	return 0;}static void close_rx(struct atm_vcc *vcc){	DECLARE_WAITQUEUE(wait,current);	unsigned long here;	struct eni_dev *eni_dev;	struct eni_vcc *eni_vcc;	eni_vcc = ENI_VCC(vcc);	if (!eni_vcc->rx) return;	eni_dev = ENI_DEV(vcc->dev);	if (vcc->vpi != ATM_VPI_UNSPEC && vcc->vci != ATM_VCI_UNSPEC) {		here = eni_dev->vci+vcc->vci*16;		/* block receiver */		writel((readl(here) & ~MID_VCI_MODE) | (MID_MODE_TRASH <<		    MID_VCI_MODE_SHIFT),here);		/* wait for receiver to become idle */		udelay(27);		/* discard pending cell */		writel(readl(here) & ~MID_VCI_IN_SERVICE,here);		/* don't accept any new ones */		eni_dev->rx_map[vcc->vci] = NULL;		/* wait for RX queue to drain */		DPRINTK("eni_close: waiting for RX ...\n");		EVENT("RX closing\n",0,0);		add_wait_queue(&eni_dev->rx_wait,&wait);		set_current_state(TASK_UNINTERRUPTIBLE);		barrier();		for (;;) {			/* transition service->rx: rxing++, servicing-- */			if (!eni_vcc->servicing) {				barrier();				if (!eni_vcc->rxing) break;			}			EVENT("drain PDUs (rx %ld, serv %ld)\n",eni_vcc->rxing,			    eni_vcc->servicing);			printk(KERN_INFO "%d+%d RX left\n",eni_vcc->servicing,			    eni_vcc->rxing);			schedule();			set_current_state(TASK_UNINTERRUPTIBLE);		}		for (;;) {			int at_end;			u32 tmp;			tasklet_disable(&eni_dev->task);			tmp = readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ;			at_end = eni_vcc->rx_pos == tmp >> MID_VCI_READ_SHIFT;			tasklet_enable(&eni_dev->task);			if (at_end) break;			EVENT("drain discard (host 0x%lx, nic 0x%lx)\n",			    eni_vcc->rx_pos,tmp);			printk(KERN_INFO "draining RX: host 0x%lx, nic 0x%x\n",			    eni_vcc->rx_pos,tmp);			schedule();			set_current_state(TASK_UNINTERRUPTIBLE);		}		set_current_state(TASK_RUNNING);		remove_wait_queue(&eni_dev->rx_wait,&wait);	}	eni_free_mem(eni_dev,eni_vcc->recv,eni_vcc->words << 2);	eni_vcc->rx = NULL;}static int start_rx(struct atm_dev *dev){	struct eni_dev *eni_dev;	eni_dev = ENI_DEV(dev);	eni_dev->rx_map = (struct atm_vcc **) get_free_page(GFP_KERNEL);	if (!eni_dev->rx_map) {		printk(KERN_ERR DEV_LABEL "(itf %d): couldn't get free page\n",		    dev->number);		free_page((unsigned long) eni_dev->free_list);		return -ENOMEM;	}	memset(eni_dev->rx_map,0,PAGE_SIZE);	eni_dev->rx_mult = DEFAULT_RX_MULT;	eni_dev->fast = eni_dev->last_fast = NULL;	eni_dev->slow = eni_dev->last_slow = NULL;	init_waitqueue_head(&eni_dev->rx_wait);	skb_queue_head_init(&eni_dev->rx_queue);	eni_dev->serv_read = eni_in(MID_SERV_WRITE);	eni_out(0,MID_DMA_WR_RX);	return 0;}/*----------------------------------- TX ------------------------------------*/enum enq_res { enq_ok,enq_next,enq_jam };static inline void put_dma(int chan,u32 *dma,int *j,dma_addr_t paddr,    u32 size){	u32 init,words;	DPRINTK("put_dma: 0x%lx+0x%x\n",(unsigned long) paddr,size);

⌨️ 快捷键说明

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