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

📄 eni.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
/* drivers/atm/eni.c - Efficient Networks ENI155P device driver */ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include <linux/module.h>#include <linux/config.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/pci.h>#include <linux/errno.h>#include <linux/atm.h>#include <linux/atmdev.h>#include <linux/sonet.h>#include <linux/skbuff.h>#include <linux/time.h>#include <linux/sched.h> /* for xtime */#include <linux/delay.h>#include <linux/uio.h>#include <linux/init.h>#include <linux/atm_eni.h>#include <linux/bitops.h>#include <asm/system.h>#include <asm/io.h>#include <asm/atomic.h>#include <asm/uaccess.h>#include <asm/string.h>#include <asm/byteorder.h>#include "tonga.h"#include "midway.h"#include "suni.h"#include "eni.h"#if !defined(__i386__) && !defined(__x86_64__)#ifndef ioremap_nocache#define ioremap_nocache(X,Y) ioremap(X,Y)#endif #endif/* * TODO: * * Show stoppers *  none * * Minor *  - OAM support *  - fix bugs listed below *//* * KNOWN BUGS: * * - may run into JK-JK bug and deadlock * - should allocate UBR channel first * - buffer space allocation algorithm is stupid *   (RX: should be maxSDU+maxdelay*rate *    TX: should be maxSDU+min(maxSDU,maxdelay*rate) ) * - doesn't support OAM cells * - eni_put_free may hang if not putting memory fragments that _complete_ *   2^n block (never happens in real life, though) * - keeps IRQ even if initialization fails */#if 0#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)#else#define DPRINTK(format,args...)#endif#ifndef CONFIG_ATM_ENI_TUNE_BURST#define CONFIG_ATM_ENI_BURST_TX_8W#define CONFIG_ATM_ENI_BURST_RX_4W#endif#ifndef CONFIG_ATM_ENI_DEBUG#define NULLCHECK(x)#define EVENT(s,a,b)static void event_dump(void){}#else/*  * NULL pointer checking */#define NULLCHECK(x) \	if ((unsigned long) (x) < 0x30) \		printk(KERN_CRIT #x "==0x%lx\n",(unsigned long) (x))/* * Very extensive activity logging. Greatly improves bug detection speed but * costs a few Mbps if enabled. */#define EV 64static const char *ev[EV];static unsigned long ev_a[EV],ev_b[EV];static int ec = 0;static void EVENT(const char *s,unsigned long a,unsigned long b){	ev[ec] = s; 	ev_a[ec] = a;	ev_b[ec] = b;	ec = (ec+1) % EV;}static void event_dump(void){	int n,i;	for (n = 0; n < EV; n++) {		i = (ec+n) % EV;		printk(KERN_NOTICE);		printk(ev[i] ? ev[i] : "(null)",ev_a[i],ev_b[i]);	}}#endif /* CONFIG_ATM_ENI_DEBUG *//* * NExx   must not be equal at end * EExx   may be equal at end * xxPJOK verify validity of pointer jumps * xxPMOK operating on a circular buffer of "c" words */#define NEPJOK(a0,a1,b) \    ((a0) < (a1) ? (b) <= (a0) || (b) > (a1) : (b) <= (a0) && (b) > (a1))#define EEPJOK(a0,a1,b) \    ((a0) < (a1) ? (b) < (a0) || (b) >= (a1) : (b) < (a0) && (b) >= (a1))#define NEPMOK(a0,d,b,c) NEPJOK(a0,(a0+d) & (c-1),b)#define EEPMOK(a0,d,b,c) EEPJOK(a0,(a0+d) & (c-1),b)static int tx_complete = 0,dma_complete = 0,queued = 0,requeued = 0,  backlogged = 0,rx_enqueued = 0,rx_dequeued = 0,pushed = 0,submitted = 0,  putting = 0;static struct atm_dev *eni_boards = NULL;static u32 *cpu_zeroes = NULL; /* aligned "magic" zeroes */static dma_addr_t zeroes;/* Read/write registers on card */#define eni_in(r)	readl(eni_dev->reg+(r)*4)#define eni_out(v,r)	writel((v),eni_dev->reg+(r)*4)/*-------------------------------- utilities --------------------------------*/static void dump_mem(struct eni_dev *eni_dev){	int i;	for (i = 0; i < eni_dev->free_len; i++)		printk(KERN_DEBUG "  %d: 0x%lx %d\n",i,		    eni_dev->free_list[i].start,		    1 << eni_dev->free_list[i].order);}static void dump(struct atm_dev *dev){	struct eni_dev *eni_dev;	int i;	eni_dev = ENI_DEV(dev);	printk(KERN_NOTICE "Free memory\n");	dump_mem(eni_dev);	printk(KERN_NOTICE "TX buffers\n");	for (i = 0; i < NR_CHAN; i++)		if (eni_dev->tx[i].send)			printk(KERN_NOTICE "  TX %d @ 0x%lx: %ld\n",i,			    eni_dev->tx[i].send,eni_dev->tx[i].words*4);	printk(KERN_NOTICE "RX buffers\n");	for (i = 0; i < 1024; i++)		if (eni_dev->rx_map[i] && ENI_VCC(eni_dev->rx_map[i])->rx)			printk(KERN_NOTICE "  RX %d @ 0x%lx: %ld\n",i,			    ENI_VCC(eni_dev->rx_map[i])->recv,			    ENI_VCC(eni_dev->rx_map[i])->words*4);	printk(KERN_NOTICE "----\n");}static void eni_put_free(struct eni_dev *eni_dev,unsigned long start,    unsigned long size){	struct eni_free *list;	int len,order;	DPRINTK("init 0x%lx+%ld(0x%lx)\n",start,size,size);	start += eni_dev->base_diff;	list = eni_dev->free_list;	len = eni_dev->free_len;	while (size) {		if (len >= eni_dev->free_list_size) {			printk(KERN_CRIT "eni_put_free overflow (0x%lx,%ld)\n",			    start,size);			break;		}		for (order = 0; !((start | size) & (1 << order)); order++);		if (MID_MIN_BUF_SIZE > (1 << order)) {			printk(KERN_CRIT "eni_put_free: order %d too small\n",			    order);			break;		}		list[len].start = start;		list[len].order = order;		len++;		start += 1 << order;		size -= 1 << order;	}	eni_dev->free_len = len;	/*dump_mem(eni_dev);*/}static unsigned long eni_alloc_mem(struct eni_dev *eni_dev,unsigned long *size){	struct eni_free *list;	unsigned long start;	int len,i,order,best_order,index;	list = eni_dev->free_list;	len = eni_dev->free_len;	if (*size < MID_MIN_BUF_SIZE) *size = MID_MIN_BUF_SIZE;	if (*size > MID_MAX_BUF_SIZE) return 0;	for (order = 0; (1 << order) < *size; order++);	DPRINTK("trying: %ld->%d\n",*size,order);	best_order = 65; /* we don't have more than 2^64 of anything ... */	index = 0; /* silence GCC */	for (i = 0; i < len; i++)		if (list[i].order == order) {			best_order = order;			index = i;			break;		}		else if (best_order > list[i].order && list[i].order > order) {				best_order = list[i].order;				index = i;			}	if (best_order == 65) return 0;	start = list[index].start-eni_dev->base_diff;	list[index] = list[--len];	eni_dev->free_len = len;	*size = 1 << order;	eni_put_free(eni_dev,start+*size,(1 << best_order)-*size);	DPRINTK("%ld bytes (order %d) at 0x%lx\n",*size,order,start);	memset_io(start,0,*size);       /* never leak data */	/*dump_mem(eni_dev);*/	return start;}static void eni_free_mem(struct eni_dev *eni_dev,unsigned long start,    unsigned long size){	struct eni_free *list;	int len,i,order;	start += eni_dev->base_diff;	list = eni_dev->free_list;	len = eni_dev->free_len;	for (order = -1; size; order++) size >>= 1;	DPRINTK("eni_free_mem: 0x%lx+0x%lx (order %d)\n",start,size,order);	for (i = 0; i < len; i++)		if (list[i].start == (start^(1 << order)) &&		    list[i].order == order) {			DPRINTK("match[%d]: 0x%lx/0x%lx(0x%x), %d/%d\n",i,			    list[i].start,start,1 << order,list[i].order,order);			list[i] = list[--len];			start &= ~(unsigned long) (1 << order);			order++;			i = -1;			continue;		}	if (len >= eni_dev->free_list_size) {		printk(KERN_ALERT "eni_free_mem overflow (0x%lx,%d)\n",start,		    order);		return;	}	list[len].start = start;	list[len].order = order;	eni_dev->free_len = len+1;	/*dump_mem(eni_dev);*/}/*----------------------------------- RX ------------------------------------*/#define ENI_VCC_NOS ((struct atm_vcc *) 1)static void rx_ident_err(struct atm_vcc *vcc){	struct atm_dev *dev;	struct eni_dev *eni_dev;	struct eni_vcc *eni_vcc;	dev = vcc->dev;	eni_dev = ENI_DEV(dev);	/* immediately halt adapter */	eni_out(eni_in(MID_MC_S) &	    ~(MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE),MID_MC_S);	/* dump useful information */	eni_vcc = ENI_VCC(vcc);	printk(KERN_ALERT DEV_LABEL "(itf %d): driver error - RX ident "	    "mismatch\n",dev->number);	printk(KERN_ALERT "  VCI %d, rxing %d, words %ld\n",vcc->vci,	    eni_vcc->rxing,eni_vcc->words);	printk(KERN_ALERT "  host descr 0x%lx, rx pos 0x%lx, descr value "	    "0x%x\n",eni_vcc->descr,eni_vcc->rx_pos,	    (unsigned) readl(eni_vcc->recv+eni_vcc->descr*4));	printk(KERN_ALERT "  last 0x%p, servicing %d\n",eni_vcc->last,	    eni_vcc->servicing);	EVENT("---dump ends here---\n",0,0);	printk(KERN_NOTICE "---recent events---\n");	event_dump();	ENI_DEV(dev)->fast = NULL; /* really stop it */	ENI_DEV(dev)->slow = NULL;	skb_queue_head_init(&ENI_DEV(dev)->rx_queue);}static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,    unsigned long skip,unsigned long size,unsigned long eff){	struct eni_dev *eni_dev;	struct eni_vcc *eni_vcc;	u32 dma_rd,dma_wr;	u32 dma[RX_DMA_BUF*2];	dma_addr_t paddr;	unsigned long here;	int i,j;	eni_dev = ENI_DEV(vcc->dev);	eni_vcc = ENI_VCC(vcc);	paddr = 0; /* GCC, shut up */	if (skb) {		paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len,		    PCI_DMA_FROMDEVICE);		ENI_PRV_PADDR(skb) = paddr;		if (paddr & 3)			printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %d has "			    "mis-aligned RX data (0x%lx)\n",vcc->dev->number,			    vcc->vci,(unsigned long) paddr);		ENI_PRV_SIZE(skb) = size+skip;		    /* PDU plus descriptor */		ATM_SKB(skb)->vcc = vcc;	}	j = 0;	if ((eff && skip) || 1) { /* @@@ actually, skip is always == 1 ... */		here = (eni_vcc->descr+skip) & (eni_vcc->words-1);		dma[j++] = (here << MID_DMA_COUNT_SHIFT) | (vcc->vci		    << MID_DMA_VCI_SHIFT) | MID_DT_JK;		j++;	}	here = (eni_vcc->descr+size+skip) & (eni_vcc->words-1);	if (!eff) size += skip;	else {		unsigned long words;		if (!size) {			DPRINTK("strange things happen ...\n");			EVENT("strange things happen ... (skip=%ld,eff=%ld)\n",			    size,eff);		}		words = eff;		if (paddr & 15) {			unsigned long init;			init = 4-((paddr & 15) >> 2);			if (init > words) init = words;			dma[j++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) |			    (vcc->vci << MID_DMA_VCI_SHIFT);			dma[j++] = paddr;			paddr += init << 2;			words -= init;		}#ifdef CONFIG_ATM_ENI_BURST_RX_16W /* may work with some PCI chipsets ... */		if (words & ~15) {			dma[j++] = MID_DT_16W | ((words >> 4) <<			    MID_DMA_COUNT_SHIFT) | (vcc->vci <<			    MID_DMA_VCI_SHIFT);			dma[j++] = paddr;			paddr += (words & ~15) << 2;			words &= 15;		}#endif#ifdef CONFIG_ATM_ENI_BURST_RX_8W  /* works only with *some* PCI chipsets ... */		if (words & ~7) {			dma[j++] = MID_DT_8W | ((words >> 3) <<			    MID_DMA_COUNT_SHIFT) | (vcc->vci <<			    MID_DMA_VCI_SHIFT);			dma[j++] = paddr;			paddr += (words & ~7) << 2;			words &= 7;		}#endif#ifdef CONFIG_ATM_ENI_BURST_RX_4W /* recommended */		if (words & ~3) {			dma[j++] = MID_DT_4W | ((words >> 2) <<			    MID_DMA_COUNT_SHIFT) | (vcc->vci <<			    MID_DMA_VCI_SHIFT);			dma[j++] = paddr;			paddr += (words & ~3) << 2;			words &= 3;		}#endif#ifdef CONFIG_ATM_ENI_BURST_RX_2W /* probably useless if RX_4W, RX_8W, ... */		if (words & ~1) {			dma[j++] = MID_DT_2W | ((words >> 1) <<			    MID_DMA_COUNT_SHIFT) | (vcc->vci <<			    MID_DMA_VCI_SHIFT);			dma[j++] = paddr;			paddr += (words & ~1) << 2;			words &= 1;		}#endif		if (words) {			dma[j++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT)			    | (vcc->vci << MID_DMA_VCI_SHIFT);			dma[j++] = paddr;		}	}	if (size != eff) {		dma[j++] = (here << MID_DMA_COUNT_SHIFT) |		    (vcc->vci << MID_DMA_VCI_SHIFT) | MID_DT_JK;		j++;	}	if (!j || j > 2*RX_DMA_BUF) {		printk(KERN_CRIT DEV_LABEL "!j or j too big!!!\n");		goto trouble;	}	dma[j-2] |= MID_DMA_END;	j = j >> 1;	dma_wr = eni_in(MID_DMA_WR_RX);	dma_rd = eni_in(MID_DMA_RD_RX);	/*	 * Can I move the dma_wr pointer by 2j+1 positions without overwriting	 * data that hasn't been read (position of dma_rd) yet ?	 */	if (!NEPMOK(dma_wr,j+j+1,dma_rd,NR_DMA_RX)) { /* @@@ +1 is ugly */		printk(KERN_WARNING DEV_LABEL "(itf %d): RX DMA full\n",		    vcc->dev->number);		goto trouble;	}

⌨️ 快捷键说明

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