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

📄 zatm.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 4 页
字号:
/* drivers/atm/zatm.c - ZeitNet ZN122x device driver */ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */#include <linux/config.h>#include <linux/module.h>#include <linux/sched.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/netdevice.h>#include <linux/delay.h>#include <linux/ioport.h> /* for request_region */#include <linux/uio.h>#include <linux/init.h>#include <linux/atm_zatm.h>#include <linux/capability.h>#include <linux/bitops.h>#include <asm/byteorder.h>#include <asm/system.h>#include <asm/string.h>#include <asm/io.h>#include <asm/atomic.h>#include <asm/uaccess.h>#include "uPD98401.h"#include "uPD98402.h"#include "zeprom.h"#include "zatm.h"/* * TODO: * * Minor features *  - support 64 kB SDUs (will have to use multibuffer batches then :-( ) *  - proper use of CDV, credit = max(1,CDVT*PCR) *  - AAL0 *  - better receive timestamps *  - OAM */#if 0#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)#else#define DPRINTK(format,args...)#endif#ifndef __i386__#ifdef CONFIG_ATM_ZATM_EXACT_TS#warning Precise timestamping only available on i386 platform#undef CONFIG_ATM_ZATM_EXACT_TS#endif#endif#ifndef CONFIG_ATM_ZATM_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%x\n", (int) (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;	printk(KERN_NOTICE "----- event dump follows -----\n");	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]);	}	printk(KERN_NOTICE "----- event dump ends here -----\n");}#endif /* CONFIG_ATM_ZATM_DEBUG */#define RING_BUSY	1	/* indication from do_tx that PDU has to be				   backlogged */static struct atm_dev *zatm_boards = NULL;static unsigned long dummy[2] = {0,0};#define zin_n(r) inl(zatm_dev->base+r*4)#define zin(r) inl(zatm_dev->base+uPD98401_##r*4)#define zout(v,r) outl(v,zatm_dev->base+uPD98401_##r*4)#define zwait while (zin(CMR) & uPD98401_BUSY)/* RX0, RX1, TX0, TX1 */static const int mbx_entries[NR_MBX] = { 1024,1024,1024,1024 };static const int mbx_esize[NR_MBX] = { 16,16,4,4 }; /* entry size in bytes */#define MBX_SIZE(i) (mbx_entries[i]*mbx_esize[i])/*-------------------------------- utilities --------------------------------*/static void zpokel(struct zatm_dev *zatm_dev,u32 value,u32 addr){	zwait;	zout(value,CER);	zout(uPD98401_IND_ACC | uPD98401_IA_BALL |	    (uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR);}static u32 zpeekl(struct zatm_dev *zatm_dev,u32 addr){	zwait;	zout(uPD98401_IND_ACC | uPD98401_IA_BALL | uPD98401_IA_RW |	  (uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR);	zwait;	return zin(CER);}/*------------------------------- free lists --------------------------------*//* * Free buffer head structure: *   [0] pointer to buffer (for SAR) *   [1] buffer descr link pointer (for SAR) *   [2] back pointer to skb (for poll_rx) *   [3] data *   ... */struct rx_buffer_head {	u32		buffer;	/* pointer to buffer (for SAR) */	u32		link;	/* buffer descriptor link pointer (for SAR) */	struct sk_buff	*skb;	/* back pointer to skb (for poll_rx) */};static void refill_pool(struct atm_dev *dev,int pool){	struct zatm_dev *zatm_dev;	struct sk_buff *skb;	struct rx_buffer_head *first;	unsigned long flags;	int align,offset,free,count,size;	EVENT("refill_pool\n",0,0);	zatm_dev = ZATM_DEV(dev);	size = (64 << (pool <= ZATM_AAL5_POOL_BASE ? 0 :	    pool-ZATM_AAL5_POOL_BASE))+sizeof(struct rx_buffer_head);	if (size < PAGE_SIZE) {		align = 32; /* for 32 byte alignment */		offset = sizeof(struct rx_buffer_head);	}	else {		align = 4096;		offset = zatm_dev->pool_info[pool].offset+		    sizeof(struct rx_buffer_head);	}	size += align;	save_flags(flags);	cli();	free = zpeekl(zatm_dev,zatm_dev->pool_base+2*pool) &	    uPD98401_RXFP_REMAIN;	restore_flags(flags);	if (free >= zatm_dev->pool_info[pool].low_water) return;	EVENT("starting ... POOL: 0x%x, 0x%x\n",	    zpeekl(zatm_dev,zatm_dev->pool_base+2*pool),	    zpeekl(zatm_dev,zatm_dev->pool_base+2*pool+1));	EVENT("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);	count = 0;	first = NULL;	while (free < zatm_dev->pool_info[pool].high_water) {		struct rx_buffer_head *head;		skb = alloc_skb(size,GFP_ATOMIC);		if (!skb) {			printk(KERN_WARNING DEV_LABEL "(Itf %d): got no new "			    "skb (%d) with %d free\n",dev->number,size,free);			break;		}		skb_reserve(skb,(unsigned char *) ((((unsigned long) skb->data+		    align+offset-1) & ~(unsigned long) (align-1))-offset)-		    skb->data);		head = (struct rx_buffer_head *) skb->data;		skb_reserve(skb,sizeof(struct rx_buffer_head));		if (!first) first = head;		count++;		head->buffer = virt_to_bus(skb->data);		head->link = 0;		head->skb = skb;		EVENT("enq skb 0x%08lx/0x%08lx\n",(unsigned long) skb,		    (unsigned long) head);		cli();		if (zatm_dev->last_free[pool])			((struct rx_buffer_head *) (zatm_dev->last_free[pool]->			    data))[-1].link = virt_to_bus(head);		zatm_dev->last_free[pool] = skb;		skb_queue_tail(&zatm_dev->pool[pool],skb);		restore_flags(flags);		free++;	}	if (first) {		cli();		zwait;		zout(virt_to_bus(first),CER);		zout(uPD98401_ADD_BAT | (pool << uPD98401_POOL_SHIFT) | count,		    CMR);		restore_flags(flags);		EVENT ("POOL: 0x%x, 0x%x\n",		    zpeekl(zatm_dev,zatm_dev->pool_base+2*pool),		    zpeekl(zatm_dev,zatm_dev->pool_base+2*pool+1));		EVENT("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);	}}static void drain_free(struct atm_dev *dev,int pool){	skb_queue_purge(&ZATM_DEV(dev)->pool[pool]);}static int pool_index(int max_pdu){	int i;	if (max_pdu % ATM_CELL_PAYLOAD)		printk(KERN_ERR DEV_LABEL ": driver error in pool_index: "		    "max_pdu is %d\n",max_pdu);	if (max_pdu > 65536) return -1;	for (i = 0; (64 << i) < max_pdu; i++);	return i+ZATM_AAL5_POOL_BASE;}/* use_pool isn't reentrant */static void use_pool(struct atm_dev *dev,int pool){	struct zatm_dev *zatm_dev;	unsigned long flags;	int size;	zatm_dev = ZATM_DEV(dev);	if (!(zatm_dev->pool_info[pool].ref_count++)) {		skb_queue_head_init(&zatm_dev->pool[pool]);		size = pool-ZATM_AAL5_POOL_BASE;		if (size < 0) size = 0; /* 64B... */		else if (size > 10) size = 10; /* ... 64kB */		save_flags(flags);		cli();		zpokel(zatm_dev,((zatm_dev->pool_info[pool].low_water/4) <<		    uPD98401_RXFP_ALERT_SHIFT) |		    (1 << uPD98401_RXFP_BTSZ_SHIFT) |		    (size << uPD98401_RXFP_BFSZ_SHIFT),		    zatm_dev->pool_base+pool*2);		zpokel(zatm_dev,(unsigned long) dummy,zatm_dev->pool_base+		    pool*2+1);		restore_flags(flags);		zatm_dev->last_free[pool] = NULL;		refill_pool(dev,pool);	}	DPRINTK("pool %d: %d\n",pool,zatm_dev->pool_info[pool].ref_count);}static void unuse_pool(struct atm_dev *dev,int pool){	if (!(--ZATM_DEV(dev)->pool_info[pool].ref_count))		drain_free(dev,pool);}static void zatm_feedback(struct atm_vcc *vcc,struct sk_buff *skb,    unsigned long start,unsigned long dest,int len){	struct zatm_pool_info *pool;	unsigned long offset,flags;	DPRINTK("start 0x%08lx dest 0x%08lx len %d\n",start,dest,len);	if (len < PAGE_SIZE) return;	pool = &ZATM_DEV(vcc->dev)->pool_info[ZATM_VCC(vcc)->pool];	offset = (dest-start) & (PAGE_SIZE-1);	save_flags(flags);	cli();	if (!offset || pool->offset == offset) {		pool->next_cnt = 0;		restore_flags(flags);		return;	}	if (offset != pool->next_off) {		pool->next_off = offset;		pool->next_cnt = 0;		restore_flags(flags);		return;	}	if (++pool->next_cnt >= pool->next_thres) {		pool->offset = pool->next_off;		pool->next_cnt = 0;	}	restore_flags(flags);}/*----------------------- high-precision timestamps -------------------------*/#ifdef CONFIG_ATM_ZATM_EXACT_TSstatic struct timer_list sync_timer;/* * Note: the exact time is not normalized, i.e. tv_usec can be > 1000000. * This must be handled by higher layers. */static inline struct timeval exact_time(struct zatm_dev *zatm_dev,u32 ticks){	struct timeval tmp;	tmp = zatm_dev->last_time;	tmp.tv_usec += ((s64) (ticks-zatm_dev->last_clk)*	    (s64) zatm_dev->factor) >> TIMER_SHIFT;	return tmp;}static void zatm_clock_sync(unsigned long dummy){	struct atm_dev *atm_dev;	struct zatm_dev *zatm_dev;	for (atm_dev = zatm_boards; atm_dev; atm_dev = zatm_dev->more) {		unsigned long flags,interval;		int diff;		struct timeval now,expected;		u32 ticks;		zatm_dev = ZATM_DEV(atm_dev);		save_flags(flags);		cli();		ticks = zpeekl(zatm_dev,uPD98401_TSR);		do_gettimeofday(&now);		restore_flags(flags);		expected = exact_time(zatm_dev,ticks);		diff = 1000000*(expected.tv_sec-now.tv_sec)+		    (expected.tv_usec-now.tv_usec);		zatm_dev->timer_history[zatm_dev->th_curr].real = now;		zatm_dev->timer_history[zatm_dev->th_curr].expected = expected;		zatm_dev->th_curr = (zatm_dev->th_curr+1) &		    (ZATM_TIMER_HISTORY_SIZE-1);		interval = 1000000*(now.tv_sec-zatm_dev->last_real_time.tv_sec)		    +(now.tv_usec-zatm_dev->last_real_time.tv_usec);		if (diff >= -ADJ_REP_THRES && diff <= ADJ_REP_THRES)			zatm_dev->timer_diffs = 0;		else#ifndef AGGRESSIVE_DEBUGGING			if (++zatm_dev->timer_diffs >= ADJ_MSG_THRES)#endif			{			zatm_dev->timer_diffs = 0;			printk(KERN_INFO DEV_LABEL ": TSR update after %ld us:"			    " calculation differed by %d us\n",interval,diff);#ifdef AGGRESSIVE_DEBUGGING			printk(KERN_DEBUG "  %d.%08d -> %d.%08d (%lu)\n",			    zatm_dev->last_real_time.tv_sec,			    zatm_dev->last_real_time.tv_usec,			    now.tv_sec,now.tv_usec,interval);			printk(KERN_DEBUG "  %u -> %u (%d)\n",			    zatm_dev->last_clk,ticks,ticks-zatm_dev->last_clk);			printk(KERN_DEBUG "  factor %u\n",zatm_dev->factor);#endif		}		if (diff < -ADJ_IGN_THRES || diff > ADJ_IGN_THRES) {		    /* filter out any major changes (e.g. time zone setup and		       such) */			zatm_dev->last_time = now;			zatm_dev->factor =			    (1000 << TIMER_SHIFT)/(zatm_dev->khz+1);		}		else {			zatm_dev->last_time = expected;			/*			 * Is the accuracy of udelay really only about 1:300 on			 * a 90 MHz Pentium ? Well, the following line avoids			 * the problem, but ...			 *			 * What it does is simply:			 *			 * zatm_dev->factor = (interval << TIMER_SHIFT)/			 *     (ticks-zatm_dev->last_clk);			 */#define S(x) #x		/* "stringification" ... */#define SX(x) S(x)			asm("movl %2,%%ebx\n\t"			    "subl %3,%%ebx\n\t"			    "xorl %%edx,%%edx\n\t"			    "shldl $" SX(TIMER_SHIFT) ",%1,%%edx\n\t"			    "shl $" SX(TIMER_SHIFT) ",%1\n\t"			    "divl %%ebx\n\t"			    : "=a" (zatm_dev->factor)			    : "0" (interval-diff),"g" (ticks),			      "g" (zatm_dev->last_clk)			    : "ebx","edx","cc");#undef S#undef SX#ifdef AGGRESSIVE_DEBUGGING			printk(KERN_DEBUG "  (%ld << %d)/(%u-%u) = %u\n",			    interval,TIMER_SHIFT,ticks,zatm_dev->last_clk,			    zatm_dev->factor);#endif		}		zatm_dev->last_real_time = now;		zatm_dev->last_clk = ticks;	}	mod_timer(&sync_timer,sync_timer.expires+POLL_INTERVAL*HZ);}static void __init zatm_clock_init(struct zatm_dev *zatm_dev){	static int start_timer = 1;	unsigned long flags;

⌨️ 快捷键说明

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