diff options
Diffstat (limited to 'drivers/net/ni52.c')
-rw-r--r-- | drivers/net/ni52.c | 728 |
1 files changed, 336 insertions, 392 deletions
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 12ad62caf..9dabb5f32 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -4,14 +4,21 @@ * This is an extension to the Linux operating system, and is covered by the * same Gnu Public License that covers that work. * - * Alphacode 0.51 (94/08/19) for Linux 1.1.47 (or later) - * Copyrights (c) 1994 by Michael Hipp (mhipp@student.uni-tuebingen.de) + * Alphacode 0.62 (95/01/19) for Linux 1.1.82 (or later) + * Copyrights (c) 1994,1995 by M.Hipp (Michael.Hipp@student.uni-tuebingen.de) * [feel free to mail ....] * * CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!. + * + * If you find a bug, please report me: + * The kernel panic output and any kmsg from the ni52 driver + * the ni5210-driver-version and the linux-kernel version + * how many shared memory (memsize) on the netcard, + * bootprom: yes/no, base_addr, mem_start + * maybe the ni5210-card revision and the i82586 version * * autoprobe for: base_addr: 0x300,0x280,0x360,0x320,0x340 - * mem_start: 0xd0000,0xd4000,0xd8000 (8K and 16K) + * mem_start: 0xc8000,0xd0000,0xd4000,0xd8000 (8K and 16K) * * sources: * skeleton.c from Donald Becker @@ -19,16 +26,40 @@ * I have also done a look in the following sources: (mail me if you need them) * crynwr-packet-driver by Russ Nelson * Garret A. Wollman's (fourth) i82586-driver for BSD - * (before getting an i82596 manual, the existing drivers helped + * (before getting an i82596 (yes 596 not 586) manual, the existing drivers helped * me a lot to understand this tricky chip.) * - * Known Bugs: + * Known Problems: * The internal sysbus seems to be slow. So we often lose packets because of * overruns while receiving from a fast remote host. * This can slow down TCP connections. Maybe the newer ni5210 cards are better. + * + * IMPORTANT NOTE: + * On fast networks, it's a (very) good idea to have 16K shared memory. With + * 8K, we can store only 4 receive frames, so it can (easily) happen that a remote + * machine 'overruns' our system. + * + * Known i82586 bugs (I'm sure, there are many more!): + * Running the NOP-mode, the i82586 sometimes seems to forget to report + * every xmit-interrupt until we restart the CU. + * Another MAJOR bug is, that the RU sometimes seems to ignore the EL-Bit + * in the RBD-Struct which indicates an end of the RBD queue. + * Instead, the RU fetches another (randomly selected and + * usually used) RBD and begins to fill it. (Maybe, this happens only if + * the last buffer from the previous RFD fits exact into the queue and + * the next RFD can't fetch an initial RBD. Anyone knows more? ) */ /* + * 19.Jan.95: verified (MH) + * + * 19.Sep.94: Added Multicast support (not tested yet) (MH) + * + * 18.Sep.94: Workaround for 'EL-Bug'. Removed flexible RBD-handling. + * Now, every RFD has exact one RBD. (MH) + * + * 14.Sep.94: added promiscuous mode, a few cleanups (MH) + * * 19.Aug.94: changed request_irq() parameter (MH) * * 20.July.94: removed cleanup bugs, removed a 16K-mem-probe-bug (MH) @@ -42,13 +73,13 @@ * 26.March.94: patches for Linux 1.0 and iomem-auto-probe (MH) * * 30.Sep.93: Added nop-chain .. driver now runs with only one Xmit-Buff, too (MH) + * + * < 30.Sep.93: first versions */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/string.h> -#include <linux/ptrace.h> #include <linux/errno.h> #include <linux/ioport.h> #include <linux/malloc.h> @@ -63,15 +94,8 @@ #include "ni52.h" -#define DEBUG /* debug on */ - -/* -#define DEBUG1 -#define DEBUG2 -#define DEBUG3 -*/ - -#define SYSBUSVAL 1 +#define DEBUG /* debug on */ +#define SYSBUSVAL 1 /* 8 Bit */ #define ni_attn586() {outb(0,dev->base_addr+NI52_ATTENTION);} #define ni_reset586() {outb(0,dev->base_addr+NI52_RESET);} @@ -80,12 +104,11 @@ #define make24(ptr32) ((char *) (ptr32) - p->base) #define make16(ptr32) ((unsigned short) ((unsigned long) (ptr32) - (unsigned long) p->memtop )) -/******************* how to calc the buffers ***************************** - -IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, do also a ---------------- #define ONLY_ONE_XMIT_BUF - btw: it seems, that only the ONLY_ONE_XMIT_BUF Mode is stable +/******************* how to calculate the buffers ***************************** + * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works + * --------------- in a different (more stable?) mode. Only in this mode it's + * possible to configure the driver with 'NO_NOPCOMMANDS' sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8; sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT @@ -93,81 +116,16 @@ sizeof(rfd) = 24; sizeof(rbd) = 12; sizeof(tbd) = 8; sizeof(transmit_cmd) = 16; sizeof(nop_cmd) = 8; -examples: ---------- - -->cfg1: NUM_RECV_FRAMES=16, NUM_RECV_BUFFS=48, RECV_BUFF_SIZE=256, - NUM_XMIT_BUFFS=2 ,XMIT_BUFF_SIZE=1514 - -NUM_RECV_FRAMES * sizeof(rfd) = 384; -NUM_RECV_BUFFS * ( sizeof(rbd) + RECV_BUFF_SIZE) = 12864 -NUM_XMIT_BUFFS * ( sizeof(tbd+transmit_cmd+nop_cmd) + XMIT_BUFF_SIZE) = 3092 -INIT = 36 --------------------- -16358 (36 bytes left!) - -************************ - -->cfg2: NUM_RECV_FRAMES=9, NUM_RECV_BUFFS=18, RECV_BUFF_SIZE=256, - NUM_XMIT_BUFFS=2 ,XMIT_BUFF_SIZE=1514 - -NUM_RECV_FRAMES * sizeof(rfd) = 216 -NUM_RECV_BUFFS * ( sizeof(rbd) + RECV_BUFF_SIZE) = 4824 -NUM_XMIT_BUFFS * ( sizeof(tbd+transmit_cmd+nop_cmd) + XMIT_BUFF_SIZE) = 3092 -INIT = 36 ------------------- -8180 (24 bytes left!) - -->cfg3: NUM_RECV_FRAMES=7, NUM_RECV_BUFFS=24, RECV_BUFF_SIZE=256, - NUM_XMIT_BUFFS=1, XMIT_BUFF_SIZE=1514 - 168 + 6432 + 1538 + 36 + 16 = 8190 - -***************************************************************************/ - -#if 0 -/* config-1 for 16Kram card */ -# define NUM_RECV_FRAMES 16 /* number of frames to allow for receive */ -# define NUM_RECV_BUFFS 48 /* number of buffers to allocate */ -# define RECV_BUFF_SIZE 256 /* size of each buffer, POWER OF 2 & EVEN*/ -# define XMIT_BUFF_SIZE 1514 /* length of transmit buffer (EVEN) */ -# define NUM_XMIT_BUFFS 2 /* number of Xmit-Buffs */ -#elif 0 -/* config-2 for 8Kram card */ -# define NUM_RECV_FRAMES 9 -# define NUM_RECV_BUFFS 18 -# define RECV_BUFF_SIZE 256 -# define XMIT_BUFF_SIZE 1514 -# define NUM_XMIT_BUFFS 2 -#elif 1 -/* - * config-3 for 8Kram card ___use_this_config____ seems to be stable - */ -# define NUM_RECV_FRAMES 7 -# define NUM_RECV_BUFFS 24 -# define RECV_BUFF_SIZE 256 -# define XMIT_BUFF_SIZE 1514 -# define NUM_XMIT_BUFFS 1 -# define ONLY_ONE_XMIT_BUF -# define NO_NOPCOMMANDS -#elif 0 -/* - * cfg-4 for 16K, ONLY_ONE_XMIT_BUF - */ -# define NUM_RECV_FRAMES 20 -# define NUM_RECV_BUFFS 27 -# define RECV_BUFF_SIZE 512 -# define XMIT_BUFF_SIZE 1514 -# define NUM_XMIT_BUFFS 1 -# define ONLY_ONE_XMIT_BUF -#else -# define NUM_RECV_FRAMES 4 -# define NUM_RECV_BUFFS 4 -# define RECV_BUFF_SIZE 1536 -# define XMIT_BUFF_SIZE 1536 -# define NUM_XMIT_BUFFS 1 -# define ONLY_ONE_XMIT_BUF -# define NO_NOPCOMMANDS -#endif + * if you don't know the driver, better do not change this values: */ + +#define RECV_BUFF_SIZE 1524 /* slightly oversized */ +#define XMIT_BUFF_SIZE 1524 /* slightly oversized */ +#define NUM_XMIT_BUFFS 1 /* config for both, 8K and 16K shmem */ +#define NUM_RECV_BUFFS_8 4 /* config for 8K shared mem */ +#define NUM_RECV_BUFFS_16 9 /* config for 16K shared mem */ +#define NO_NOPCOMMANDS /* only possible with NUM_XMIT_BUFFS=1 */ + +/**************************************************************************/ #define DELAY(x) {int i=jiffies; \ if(loops_per_sec == 1) \ @@ -176,30 +134,42 @@ INIT = 36 __delay((loops_per_sec>>5)*x); \ } +/* a much shorter delay: */ +#define DELAY_16(); { __delay( (loops_per_sec>>16)+1 ); } + +/* wait for command with timeout: */ +#define WAIT_4_SCB_CMD() { int i; \ + for(i=0;i<1024;i++) { \ + if(!p->scb->cmd) break; \ + DELAY_16(); \ + if(i == 1023) { \ + printk("%s: scb_cmd timed out .. resetting i82586\n",dev->name); \ + ni_reset586(); } } } + extern void autoirq_setup(int waittime); -extern int autoirq_report(int waittime); +extern int autoirq_report(int waittime); extern void *irq2dev_map[16]; -#ifndef HAVE_PORTRESERVE -#define check_region(ioaddr, size) 0 -#define snarf_region(ioaddr, size); do ; while (0) -#endif - #define NI52_TOTAL_SIZE 16 #define NI52_ADDR0 0x02 #define NI52_ADDR1 0x07 #define NI52_ADDR2 0x01 +#ifndef HAVE_PORTRESERVE +#define check_region(ioaddr, size) 0 +#define request_region(ioaddr, size,name) do ; while (0) +#endif + static int ni52_probe1(struct device *dev,int ioaddr); -static void ni52_interrupt(int reg_ptr); +static void ni52_interrupt(int irq,struct pt_regs *reg_ptr); static int ni52_open(struct device *dev); static int ni52_close(struct device *dev); static int ni52_send_packet(struct sk_buff *,struct device *); -static struct enet_statistics *ni52_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static struct enet_statistics *ni52_get_stats(struct device *dev); +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); /* helper-functions */ -static int init586(struct device *dev); +static int init586(struct device *dev,int num_addrs,void *addrs); static int check586(struct device *dev,char *where,unsigned size); static void alloc586(struct device *dev); static void startrecv586(struct device *dev); @@ -212,20 +182,19 @@ struct priv { struct enet_statistics stats; unsigned long base; - char *memtop,*max_cbuff32,*min_cbuff32,*max_cbuff24; - volatile struct rbd_struct *rbd_last; + char *memtop; volatile struct rfd_struct *rfd_last,*rfd_top,*rfd_first; volatile struct scp_struct *scp; /* volatile is important */ volatile struct iscp_struct *iscp; /* volatile is important */ volatile struct scb_struct *scb; /* volatile is important */ volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS]; volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS]; -#ifdef ONLY_ONE_XMIT_BUF +#if (NUM_XMIT_BUFFS == 1) volatile struct nop_cmd_struct *nop_cmds[2]; #else volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS]; #endif - volatile int nop_point; + volatile int nop_point,num_recv_buffs; volatile char *xmit_cbuffs[NUM_XMIT_BUFFS]; volatile int xmit_count,xmit_last; }; @@ -255,7 +224,7 @@ static int ni52_close(struct device *dev) static int ni52_open(struct device *dev) { alloc586(dev); - init586(dev); + init586(dev,0,NULL); startrecv586(dev); if(request_irq(dev->irq, &ni52_interrupt,0,"ni52")) @@ -286,7 +255,7 @@ static int check586(struct device *dev,char *where,unsigned size) p->memtop = where + size; p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS); memset((char *)p->scp,0, sizeof(struct scp_struct)); - p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus */ + p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus, 0 = 16 Bit */ iscp_addrs[0] = where; iscp_addrs[1]= (char *) p->scp - sizeof(struct iscp_struct); @@ -303,7 +272,7 @@ static int check586(struct device *dev,char *where,unsigned size) ni_attn586(); DELAY(2); /* wait a while... */ - if(p->iscp->busy) + if(p->iscp->busy) /* i82586 clears 'busy' after successful init */ return 0; } return 1; @@ -317,6 +286,9 @@ void alloc586(struct device *dev) { struct priv *p = (struct priv *) dev->priv; + ni_reset586(); + DELAY(2); + p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS); p->scb = (struct scb_struct *) (dev->mem_start); p->iscp = (struct iscp_struct *) ((char *)p->scp - sizeof(struct iscp_struct)); @@ -332,12 +304,10 @@ void alloc586(struct device *dev) ni_reset586(); ni_attn586(); -#ifdef DEBUG DELAY(2); if(p->iscp->busy) printk("%s: Init-Problems (alloc).\n",dev->name); -#endif memset((char *)p->scb,0,sizeof(struct scb_struct)); } @@ -377,7 +347,7 @@ int ni52_probe(struct device *dev) static int ni52_probe1(struct device *dev,int ioaddr) { - long memaddrs[] = { 0xd0000,0xd2000,0xd4000,0xd6000,0xd8000, 0 }; + long memaddrs[] = { 0xd0000,0xd2000,0xc8000,0xca000,0xd4000,0xd6000,0xd8000, 0 }; int i,size; for(i=0;i<ETH_ALEN;i++) @@ -389,7 +359,7 @@ static int ni52_probe1(struct device *dev,int ioaddr) printk("%s: Ni52 found at %#3x, ",dev->name,dev->base_addr); - snarf_region(ioaddr,NI52_TOTAL_SIZE); + request_region(ioaddr,NI52_TOTAL_SIZE,"ni52"); dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL); /* warning: we don't free it on errors */ @@ -400,9 +370,9 @@ static int ni52_probe1(struct device *dev,int ioaddr) */ if(dev->mem_start != 0) /* no auto-mem-probe */ { - size = 0x4000; + size = 0x4000; /* check for 16K mem */ if(!check586(dev,(char *) dev->mem_start,size)) { - size = 0x2000; + size = 0x2000; /* check for 8K mem */ if(!check586(dev,(char *) dev->mem_start,size)) { printk("?memprobe, Can't find memory at 0x%lx!\n",dev->mem_start); return ENODEV; @@ -418,18 +388,25 @@ static int ni52_probe1(struct device *dev,int ioaddr) return ENODEV; } dev->mem_start = memaddrs[i]; - size = 0x2000; + size = 0x2000; /* check for 8K mem */ if(check586(dev,(char *)dev->mem_start,size)) /* 8K-check */ break; - size = 0x4000; + size = 0x4000; /* check for 16K mem */ if(check586(dev,(char *)dev->mem_start,size)) /* 16K-check */ break; } } - + dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */ + ((struct priv *) (dev->priv))->base = dev->mem_start + size - 0x01000000; alloc586(dev); + /* set number of receive-buffs according to memsize */ + if(size == 0x2000) + ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8; + else + ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16; + printk("Memaddr: 0x%lx, Memsize: %d, ",dev->mem_start,size); if(dev->irq < 2) @@ -470,7 +447,7 @@ static int ni52_probe1(struct device *dev,int ioaddr) * needs a correct 'allocated' memory */ -static int init586(struct device *dev) +static int init586(struct device *dev,int num_addrs,void *addrs) { void *ptr; unsigned long s; @@ -479,19 +456,26 @@ static int init586(struct device *dev) volatile struct configure_cmd_struct *cfg_cmd; volatile struct iasetup_cmd_struct *ias_cmd; volatile struct tdr_cmd_struct *tdr_cmd; + volatile struct mcsetup_cmd_struct *mc_cmd; ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct)); cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */ - - cfg_cmd->byte_cnt = 0x04; /* number of cfg bytes */ - cfg_cmd->fifo = 0xc8; /* fifo-limit (8=tx:32/rx:64) | monitor */ - cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */ - cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */ - cfg_cmd->cmd_status = 0; - cfg_cmd->cmd_cmd = CMD_CONFIGURE | CMD_LAST; - cfg_cmd->cmd_link = 0xffff; + cfg_cmd->cmd_status = 0; + cfg_cmd->cmd_cmd = CMD_CONFIGURE | CMD_LAST; + cfg_cmd->cmd_link = 0xffff; + cfg_cmd->byte_cnt = 0x0a; /* number of cfg bytes */ + cfg_cmd->fifo = 0x08; /* fifo-limit (8=tx:32/rx:64) */ + cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */ + cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */ + cfg_cmd->priority = 0x00; + cfg_cmd->ifs = 0x60; + cfg_cmd->time_low = 0x00; + cfg_cmd->time_high = 0xf2; + cfg_cmd->promisc = (num_addrs < 0) ? 1 : 0; /* promisc on/off */ + cfg_cmd->carr_coll = 0x00; + p->scb->cbl_offset = make16(cfg_cmd); p->scb->cmd = CUC_START; /* cmd.-unit start */ @@ -585,41 +569,78 @@ static int init586(struct device *dev) /* * alloc nop/xmit-cmds */ -#ifdef ONLY_ONE_XMIT_BUF +#if (NUM_XMIT_BUFFS == 1) for(i=0;i<2;i++) { p->nop_cmds[i] = (struct nop_cmd_struct *)ptr; - p->nop_cmds[i]->cmd_cmd = 0; + p->nop_cmds[i]->cmd_cmd = CMD_NOP; p->nop_cmds[i]->cmd_status = 0; p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i])); - ptr += sizeof(struct nop_cmd_struct); + ptr = (char *) ptr + sizeof(struct nop_cmd_struct); } p->xmit_cmds[0] = (struct transmit_cmd_struct *)ptr; /* transmit cmd/buff 0 */ - ptr += sizeof(struct transmit_cmd_struct); + ptr = (char *) ptr + sizeof(struct transmit_cmd_struct); #else for(i=0;i<NUM_XMIT_BUFFS;i++) { p->nop_cmds[i] = (struct nop_cmd_struct *)ptr; - p->nop_cmds[i]->cmd_cmd = 0; + p->nop_cmds[i]->cmd_cmd = CMD_NOP; p->nop_cmds[i]->cmd_status = 0; p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i])); - ptr += sizeof(struct nop_cmd_struct); - p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /* transmit cmd/buff 0 */ - ptr += sizeof(struct transmit_cmd_struct); + ptr = (char *) ptr + sizeof(struct nop_cmd_struct); + p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/ + ptr = (char *) ptr + sizeof(struct transmit_cmd_struct); } #endif ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */ - /* - * alloc xmit-buffs - */ + /* + * Multicast setup + */ + + if(num_addrs > 0) + { /* I don't understand this: do we really need memory after the init? */ + int len = ((char *) p->iscp - (char *) ptr - 8) / 6; + if(len <= 0) + { + printk("%s: Ooooops, no memory for MC-Setup!\n",dev->name); + } + else + { + if(len < num_addrs) + { + num_addrs = len; + printk("%s: Sorry, can only apply %d MC-Address(es).\n",dev->name,num_addrs); + } + mc_cmd = (struct mcsetup_cmd_struct *) ptr; + mc_cmd->cmd_status = 0; + mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST; + mc_cmd->cmd_link = 0xffff; + mc_cmd->mc_cnt = num_addrs * 6; + for(i=0;i<num_addrs;i++) + memcpy((char *) mc_cmd->mc_list[i],((char (*)[6]) addrs)[i],6); + p->scb->cbl_offset = make16(mc_cmd); + p->scb->cmd = CUC_START; + ni_attn586(); + s = jiffies; + while(!(mc_cmd->cmd_status & STAT_COMPL)) + if(jiffies - s > 30) + break; + if(!(mc_cmd->cmd_status & STAT_COMPL)) + printk("%s: Can't apply multicast-address-list.\n",dev->name); + } + } + + /* + * alloc xmit-buffs / init xmit_cmds + */ for(i=0;i<NUM_XMIT_BUFFS;i++) { p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */ - ptr += XMIT_BUFF_SIZE; + ptr = (char *) ptr + XMIT_BUFF_SIZE; p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */ - ptr += sizeof(struct tbd_struct); + ptr = (char *) ptr + sizeof(struct tbd_struct); if((void *)ptr > (void *)p->iscp) { printk("%s: not enough shared-mem for your configuration!\n",dev->name); @@ -628,11 +649,12 @@ static int init586(struct device *dev) memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct)); memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct)); p->xmit_cmds[i]->cmd_status = STAT_COMPL; + p->xmit_cmds[i]->cmd_cmd = CMD_XMIT | CMD_INT; p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i])); p->xmit_buffs[i]->next = 0xffff; p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i])); } - + p->xmit_count = 0; p->xmit_last = 0; #ifndef NO_NOPCOMMANDS @@ -646,12 +668,8 @@ static int init586(struct device *dev) p->scb->cbl_offset = make16(p->nop_cmds[0]); p->scb->cmd = CUC_START; ni_attn586(); - while(p->scb->cmd); + WAIT_4_SCB_CMD(); #else -/* - p->nop_cmds[0]->cmd_link = make16(p->nop_cmds[1]); - p->nop_cmds[1]->cmd_link = make16(p->xmit_cmds[0]); -*/ p->xmit_cmds[0]->cmd_link = 0xffff; p->xmit_cmds[0]->cmd_cmd = CMD_XMIT | CMD_LAST | CMD_INT; #endif @@ -660,7 +678,7 @@ static int init586(struct device *dev) } /****************************************************** - * This is a helper routine for ni52_nr_int() and init586(). + * This is a helper routine for ni52_rnr_int() and init586(). * It sets up the Receive Frame Area (RFA). */ @@ -671,38 +689,32 @@ static void *alloc_rfa(struct device *dev,void *ptr) int i; struct priv *p = (struct priv *) dev->priv; - memset((char *) rfd,0,sizeof(struct rfd_struct)*NUM_RECV_FRAMES); + memset((char *) rfd,0,sizeof(struct rfd_struct)*p->num_recv_buffs); p->rfd_first = rfd; - for(i = 0; i < NUM_RECV_FRAMES; i++) - rfd[i].next = make16(rfd + (i+1) % NUM_RECV_FRAMES); - rfd[NUM_RECV_FRAMES-1].last = RFD_LAST; /* set EOL (no RU suspend) */ + for(i = 0; i < p->num_recv_buffs; i++) + rfd[i].next = make16(rfd + (i+1) % p->num_recv_buffs); + rfd[p->num_recv_buffs-1].last = RFD_SUSP; /* RU suspend */ - ptr = (char *) (rfd + NUM_RECV_FRAMES); + ptr = (void *) (rfd + p->num_recv_buffs); rbd = (struct rbd_struct *) ptr; - ptr += sizeof(struct rbd_struct)*NUM_RECV_BUFFS; + ptr = (void *) (rbd + p->num_recv_buffs); /* clr descriptors */ - memset((char *) rbd,0,sizeof(struct rbd_struct)*NUM_RECV_BUFFS); + memset((char *) rbd,0,sizeof(struct rbd_struct)*p->num_recv_buffs); - p->min_cbuff32 = ptr; - for(i=0;i<NUM_RECV_BUFFS;i++) + for(i=0;i<p->num_recv_buffs;i++) { - rbd[i].next = make16((rbd + (i+1) % NUM_RECV_BUFFS)); + rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs)); rbd[i].size = RECV_BUFF_SIZE; rbd[i].buffer = make24(ptr); - ptr += RECV_BUFF_SIZE; + ptr = (char *) ptr + RECV_BUFF_SIZE; } - rbd[NUM_RECV_BUFFS-1].size |= RBD_LAST; /* set eol */ - p->max_cbuff32 = ptr; - p->max_cbuff24 = make24(p->max_cbuff32); - + p->rfd_top = p->rfd_first; - p->rfd_last = p->rfd_first + NUM_RECV_FRAMES - 1; + p->rfd_last = p->rfd_first + p->num_recv_buffs - 1; - p->rbd_last = rbd + NUM_RECV_BUFFS - 1; - p->scb->rfa_offset = make16(p->rfd_first); p->rfd_first->rbd_offset = make16(rbd); @@ -714,30 +726,18 @@ static void *alloc_rfa(struct device *dev,void *ptr) * Interrupt Handler ... */ -static void ni52_interrupt(int reg_ptr) +static void ni52_interrupt(int irq,struct pt_regs *reg_ptr) { - int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); - struct device *dev = (struct device *)(irq2dev_map[irq]); + struct device *dev = (struct device *) irq2dev_map[irq]; unsigned short stat; - int pd = 0; struct priv *p; -#ifdef DEBUG2 - printk("(1)"); -#endif - if (dev == NULL) { - printk ("ni52-interrupt: irq %d for unknown device.\n", irq); + printk ("ni52-interrupt: irq %d for unknown device.\n",(int) -(((struct pt_regs *)reg_ptr)->orig_eax+2)); return; } p = (struct priv *) dev->priv; - if(dev->interrupt) - { - printk("(ni52-I)"); - return; - } - dev->interrupt = 1; while((stat=p->scb->status & STAT_MASK)) @@ -745,57 +745,38 @@ static void ni52_interrupt(int reg_ptr) p->scb->cmd = stat; ni_attn586(); /* ack inter. */ - if(pd) - printk("ni52-%04x/%04x-",(int) stat,(int) p->scb->status); /* debug */ + if(stat & STAT_CX) /* command with I-bit set complete */ + ni52_xmt_int(dev); - if(stat & (STAT_FR | STAT_RNR)) + if(stat & STAT_FR) /* received a frame */ ni52_rcv_int(dev); - if(stat & STAT_CX) - ni52_xmt_int(dev); - #ifndef NO_NOPCOMMANDS - if(stat & STAT_CNA) -#else - if( (stat & STAT_CNA) && !(stat & STAT_CX) ) -#endif - printk("%s: oops! CU has left active state. stat: %04x/%04x.\n",dev->name,(int) stat,(int) p->scb->status); - - if(stat & STAT_RNR) + if(stat & STAT_CNA) /* CU went 'not ready' */ { - printk("%s: rnr: %04x/%04x.\n",dev->name,(int) stat,(int) p->scb->status); - ni52_rnr_int(dev); - pd = 1; /* local debug on */ + if(dev->start) + printk("%s: oops! CU has left active state. stat: %04x/%04x.\n",dev->name,(int) stat,(int) p->scb->status); } - -#ifdef DEBUG2 - pd++; #endif - while(p->scb->cmd) - { - int i; /* wait for ack. (ni52_xmt_int can be faster than ack!!) */ - for(i=0;i<200;i++); - } - } - -#ifdef DEBUG - { - static int old_ovr=0; - int l; - if((l = p->scb->ovrn_errs - old_ovr)) + if(stat & STAT_RNR) /* RU went 'not ready' */ { - if(l > 0) - p->stats.rx_over_errors += l; + if(p->scb->status & RU_SUSPEND) /* special case: RU_SUSPEND */ + { + WAIT_4_SCB_CMD(); + p->scb->cmd = RUC_RESUME; + ni_attn586(); + } else - old_ovr=0; + { + printk("%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n",dev->name,(int) stat,(int) p->scb->status); + ni52_rnr_int(dev); + } } + WAIT_4_SCB_CMD(); /* wait for ack. (ni52_xmt_int can be faster than ack!!) */ + if(p->scb->cmd) /* timed out? */ + break; } -#endif - -#ifdef DEBUG2 - printk("(2)"); -#endif dev->interrupt = 0; } @@ -807,92 +788,38 @@ static void ni52_interrupt(int reg_ptr) static void ni52_rcv_int(struct device *dev) { int status; - unsigned short totlen,pnt; + unsigned short totlen; struct sk_buff *skb; - struct rbd_struct *rbd,*rbd_first; + struct rbd_struct *rbd; struct priv *p = (struct priv *) dev->priv; for(;(status = p->rfd_top->status) & STAT_COMPL;) { - rbd = rbd_first = (struct rbd_struct *) make32(p->rfd_top->rbd_offset); + rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset); -#ifdef DEBUG1 - { - struct rbd_struct *rbd1 = rbd; - if(rbd1==p->rbd_last) - printk("L"); - printk("S:%04x/%x/%02x >",(int) rbd1->status,(int) rbd1->size>>12,(int)((unsigned long) rbd1 & 0xff)); - rbd1 = (struct rbd_struct *) make32(rbd1->next); - for(;rbd1 != rbd_first;rbd1 = (struct rbd_struct *) make32(rbd1->next)) - { - if(rbd1 == p->rbd_last) - printk("L:"); - printk("%04x/%x-",(int) rbd1->status>>12,(int) rbd1->size>>12); - } - printk("< "); - } + if(status & STAT_OK) /* frame received without error? */ { - struct rfd_struct *rfd1 = p->rfd_top; - if(rfd1==p->rfd_last) - printk("L"); - printk("S:%04x/%x/%02x >",(int) rfd1->status,(int) rfd1->last>>12,(int)((unsigned long) rfd1 & 0xff)); - rfd1 = (struct rfd_struct *) make32(rfd1->next); - for(;rfd1 != p->rfd_top;rfd1 = (struct rfd_struct *) make32(rfd1->next)) + if( (totlen = rbd->status) & RBD_LAST) /* the first and the last buffer? */ { - if(rfd1 == p->rfd_last) - printk("L:"); - printk("%x/%x-",(int) rfd1->status>>12,(int) rfd1->last>>12); - } - printk("<\n"); - } -#endif - - p->rfd_top->status = 0; - p->rfd_top->last = RFD_LAST; - p->rfd_last->last = 0; /* delete RFD_LAST, no RU suspend */ - p->rfd_last = p->rfd_top; - p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); - - if(status & RFD_ERRMASK) - printk("%s: RFD-Error ... status: %04x.\n",dev->name,status); - - if(status & STAT_OK) - { - for(totlen=0; !(rbd->status & RBD_LAST); rbd=(struct rbd_struct *) make32(rbd->next)) { - totlen += RECV_BUFF_SIZE; + totlen &= RBD_MASK; /* length of this frame */ rbd->status = 0; - } - totlen += rbd->status & RBD_MASK; - rbd->status = 0; - - skb = (struct sk_buff *) alloc_skb(totlen, GFP_ATOMIC); - - if (skb != NULL) /* copy header */ - { - skb->len = totlen; - skb->dev = dev; - - if(rbd->buffer < rbd_first->buffer) + skb = (struct sk_buff *) alloc_skb(totlen, GFP_ATOMIC); + if(skb != NULL) { - pnt = p->max_cbuff24 - rbd_first->buffer; - memcpy( (char *) skb->data,p->max_cbuff32-pnt,pnt); - memcpy( (char *) skb->data+pnt,p->min_cbuff32,totlen-pnt); + skb->len = totlen; + skb->dev = dev; + memcpy( (char *) skb->data,(char *) p->base+(unsigned long) rbd->buffer, totlen); + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + p->stats.rx_packets++; } else - memcpy( (char *) skb->data,(char *) p->base+(unsigned long) rbd_first->buffer, totlen); - - rbd->size |= RBD_LAST; - p->rbd_last->size &= ~RBD_LAST; - p->rbd_last = rbd; - - netif_rx(skb); - p->stats.rx_packets++; + p->stats.rx_dropped++; } else { - rbd->size |= RBD_LAST; - p->rbd_last->size &= ~RBD_LAST; - p->rbd_last = rbd; + printk("%s: received oversized frame.\n",dev->name); + p->stats.rx_dropped++; } } else /* frame !(ok), only with 'save-bad-frames' */ @@ -900,13 +827,16 @@ static void ni52_rcv_int(struct device *dev) printk("%s: oops! rfd-error-status: %04x\n",dev->name,status); p->stats.rx_errors++; } + p->rfd_top->status = 0; + p->rfd_top->last = RFD_SUSP; + p->rfd_last->last = 0; /* delete RU_SUSP */ + p->rfd_last = p->rfd_top; + p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */ } } /********************************************************** - * I never got this error , (which should occur if someone - * wants to blast your machine) so I couldn't debug it for now. - * but we _try_ to fix the receiver not ready int. + * handle 'Receiver went not ready'. */ static void ni52_rnr_int(struct device *dev) @@ -915,13 +845,16 @@ static void ni52_rnr_int(struct device *dev) p->stats.rx_errors++; - while(p->scb->cmd); /* wait for the last cmd */ - p->scb->cmd = RUC_ABORT; + WAIT_4_SCB_CMD(); /* wait for the last cmd */ + p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */ ni_attn586(); - while(p->scb->cmd); /* wait for accept cmd. */ + WAIT_4_SCB_CMD(); /* wait for accept cmd. */ alloc_rfa(dev,(char *)p->rfd_first); - startrecv586(dev); /* restart */ + startrecv586(dev); /* restart RU */ + + printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->status); + } /********************************************************** @@ -933,17 +866,14 @@ static void ni52_xmt_int(struct device *dev) int status; struct priv *p = (struct priv *) dev->priv; -/* - if(!(p->xmit_cmds[0]->cmd_status & STAT_COMPL)) - return; -*/ + status = p->xmit_cmds[p->xmit_last]->cmd_status; + if(!(status & STAT_COMPL)) + printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name); - if( (status=p->xmit_cmds[p->xmit_last]->cmd_status) & STAT_OK) + if(status & STAT_OK) { p->stats.tx_packets++; p->stats.collisions += (status & TCMD_MAXCOLLMASK); - dev->tbusy = 0; - mark_bh(NET_BH); } else { @@ -959,6 +889,7 @@ static void ni52_xmt_int(struct device *dev) else if(status & TCMD_LOSTCTS) printk("%s: loss of CTS detected.\n",dev->name); else if(status & TCMD_UNDERRUN) { + p->stats.tx_fifo_errors++; printk("%s: DMA underrun detected.\n",dev->name); } else if(status & TCMD_MAXCOLL) { @@ -967,11 +898,13 @@ static void ni52_xmt_int(struct device *dev) } } -#ifndef ONLY_ONE_XMIT_BUF +#if (NUM_XMIT_BUFFS != 1) if( (++p->xmit_last) == NUM_XMIT_BUFFS) p->xmit_last = 0; #endif + dev->tbusy = 0; + mark_bh(NET_BH); } /*********************************************************** @@ -984,13 +917,8 @@ static void startrecv586(struct device *dev) p->scb->rfa_offset = make16(p->rfd_first); p->scb->cmd = RUC_START; - ni_attn586(); /* start cmd. */ - while(p->scb->cmd); /* wait for accept cmd. (no timeout!!) */ - - DELAY(2); /* isn't necess. */ - - p->scb->cmd = p->scb->status & STAT_MASK; - ni_attn586(); /* ack interr */ + ni_attn586(); /* start cmd. */ + WAIT_4_SCB_CMD(); /* wait for accept cmd. (no timeout!!) */ } /****************************************************** @@ -999,7 +927,7 @@ static void startrecv586(struct device *dev) static int ni52_send_packet(struct sk_buff *skb, struct device *dev) { - int len; + int len,i; #ifndef NO_NOPCOMMANDS int next_nop; #endif @@ -1008,18 +936,37 @@ static int ni52_send_packet(struct sk_buff *skb, struct device *dev) if(dev->tbusy) { int tickssofar = jiffies - dev->trans_start; - - if (tickssofar < 30) + if (tickssofar < 5) return 1; + if(p->scb->status & CU_ACTIVE) /* COMMAND-UNIT active? */ + { + dev->tbusy = 0; #ifdef DEBUG - printk("%s: xmitter timed out, try to restart! stat: %04x\n",dev->name,p->scb->status); - printk("%s: command-stats: %04x %04x\n",dev->name,p->xmit_cmds[0]->cmd_status,p->xmit_cmds[1]->cmd_status); + printk("%s: strange ... timeout with CU active?!?\n",dev->name); + printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)p->xmit_cmds[0]->cmd_status,(int)p->nop_cmds[0]->cmd_status,(int)p->nop_cmds[1]->cmd_status,(int)p->nop_point); #endif - - ni52_close(dev); - ni52_open(dev); + p->scb->cmd = CUC_ABORT; + ni_attn586(); + WAIT_4_SCB_CMD(); + p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]); + p->scb->cmd = CUC_START; + ni_attn586(); + WAIT_4_SCB_CMD(); + dev->trans_start = jiffies; + return 0; + } + else + { +#ifdef DEBUG + printk("%s: xmitter timed out, try to restart! stat: %04x\n",dev->name,p->scb->status); + printk("%s: command-stats: %04x %04x\n",dev->name,p->xmit_cmds[0]->cmd_status,p->xmit_cmds[1]->cmd_status); +#endif + ni52_close(dev); + ni52_open(dev); + } dev->trans_start = jiffies; + return 0; } if(skb == NULL) @@ -1030,6 +977,11 @@ static int ni52_send_packet(struct sk_buff *skb, struct device *dev) if (skb->len <= 0) return 0; + if(skb->len > XMIT_BUFF_SIZE) + { + printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %ld bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len); + return 0; + } if (set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); @@ -1038,39 +990,45 @@ static int ni52_send_packet(struct sk_buff *skb, struct device *dev) memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len); len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; -#ifdef ONLY_ONE_XMIT_BUF +#if (NUM_XMIT_BUFFS == 1) # ifdef NO_NOPCOMMANDS p->xmit_buffs[0]->size = TBD_LAST | len; - p->xmit_cmds[0]->cmd_status = 0; - p->scb->cbl_offset = make16(p->xmit_cmds[0]); - p->scb->cmd = CUC_START; - - dev->trans_start = jiffies; - ni_attn586(); - while(p->scb->cmd) - for(len=0;len<256;len++); - - /* DELAY(1); */ /* TEST;TEST;TEST */ + for(i=0;i<16;i++) + { + p->scb->cbl_offset = make16(p->xmit_cmds[0]); + p->scb->cmd = CUC_START; + p->xmit_cmds[0]->cmd_status = 0; + + ni_attn586(); + dev->trans_start = jiffies; + if(!i) + dev_kfree_skb(skb,FREE_WRITE); + WAIT_4_SCB_CMD(); + if( (p->scb->status & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */ + break; + if(p->xmit_cmds[0]->cmd_status) + break; + if(i==15) + printk("%s: Can't start transmit-command.\n",dev->name); + } # else next_nop = (p->nop_point + 1) & 0x1; p->xmit_buffs[0]->size = TBD_LAST | len; - p->xmit_cmds[0]->cmd_cmd = CMD_XMIT | CMD_INT; - p->xmit_cmds[0]->cmd_status = 0; p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop])); - p->nop_cmds[next_nop]->cmd_status = 0; + p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0; p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0])); dev->trans_start = jiffies; p->nop_point = next_nop; + dev_kfree_skb(skb,FREE_WRITE); # endif #else p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len; if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS ) next_nop = 0; - p->xmit_cmds[p->xmit_count]->cmd_cmd = CMD_XMIT | CMD_INT; p->xmit_cmds[p->xmit_count]->cmd_status = 0; p->xmit_cmds[p->xmit_count]->cmd_link = p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop])); @@ -1084,71 +1042,57 @@ static int ni52_send_packet(struct sk_buff *skb, struct device *dev) if(p->xmit_count != p->xmit_last) dev->tbusy = 0; sti(); + dev_kfree_skb(skb,FREE_WRITE); #endif } - - dev_kfree_skb(skb,FREE_WRITE); - return 0; } +/******************************************* + * Someone wanna have the statistics + */ + static struct enet_statistics *ni52_get_stats(struct device *dev) { struct priv *p = (struct priv *) dev->priv; -#ifdef DEBUG3 - printk("ni52: errs, crc %d, align %d, resource %d, ovrn %d.\n",(int) p->scb->crc_errs,(int) p->scb->aln_errs,(int) p->scb->rsc_errs,(int) p->scb->ovrn_errs); -#endif + unsigned short crc,aln,rsc,ovrn; + + crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */ + p->scb->crc_errs -= crc; + aln = p->scb->aln_errs; + p->scb->aln_errs -= aln; + rsc = p->scb->rsc_errs; + p->scb->rsc_errs -= rsc; + ovrn = p->scb->ovrn_errs; + p->scb->ovrn_errs -= ovrn; + + p->stats.rx_crc_errors += crc; + p->stats.rx_fifo_errors += ovrn; + p->stats.rx_frame_errors += aln; + p->stats.rx_dropped += rsc; + return &p->stats; } +/******************************************************** + * Set MC list .. + */ + static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) { -/* - struct priv *p = (struct priv *) dev->priv; - volatile struct configure_cmd_struct *cfg_cmd; -*/ - - if(!num_addrs) - printk("%s: Currently, the Ni52 driver doesn't support promiscuous or multicast mode.\n",dev->name); - -#if 0 - p->scb->cmd = CUC_SUSPEND; - ni_attn586(); - while(p->scb->cmd); - p->scb->cmd = RUC_SUSPEND; - ni_attn586(); - while(p->scb->cmd); - - cfg_cmd = (struct configure_cmd_struct *) p->xmit_cbuffs[0]; /* we're using a transmitcommand */ - - cfg_cmd->cmd_status = 0; - cfg_cmd->cmd_cmd = CMD_CONFIGURE | CMD_LAST; - cfg_cmd->cmd_link = 0xffff; - - cfg_cmd->byte_cnt = 0x0a; /* number of cfg bytes */ - cfg_cmd->fifo = 0x08; /* fifo-limit (8=tx:32/rx:64) */ - cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */ - cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */ - cfg_cmd->priority = 0x00; - cfg_cmd->ifd = 0x60; - cfg_cmd->time_low = 0x00; - cfg_cmd->time_high = 0xf2; - cfg_cmd->promisc = 0x01; /* promisc on */ - cfg_cmd->carr_coll = 0x00; - - p->scb->cbl_offset = make16(cfg_cmd); - - p->scb->cmd = CUC_START; /* cmd.-unit start */ - ni_attn586(); - while(p->scb->cmd); - - p->scb->cbl_offset = p->nop_cmds[0]->cmd_link = make16(p->nop_cmds[0]); - p->scb->cmd = CUC_START; - ni_atthn586(); - while(p->scb->cmd); - p->scb->cmd = RUC_RESUME; - ni_atthn586(); - while(p->scb->cmd); -#endif + if(!dev->start && !num_addrs) + { + printk("%s: Can't apply promiscuous/multicastmode to a not running interface.\n",dev->name); + return; + } + dev->start = 0; + alloc586(dev); + init586(dev,num_addrs,addrs); + startrecv586(dev); + dev->start = 1; } + +/* + * END: linux/drivers/net/ni52.c + */ |