diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-09-12 01:29:55 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-09-12 01:29:55 +0000 |
commit | 545f435ebcfd94a1e7c20b46efe81b4d6ac4e698 (patch) | |
tree | e9ce4bc598d06374bda906f18365984bf22a526a /drivers/net/arcnet.c | |
parent | 4291a610eef89d0d5c69d9a10ee6560e1aa36c74 (diff) |
Merge with Linux 2.1.55. More bugfixes and goodies from my private
CVS archive.
Diffstat (limited to 'drivers/net/arcnet.c')
-rw-r--r-- | drivers/net/arcnet.c | 3895 |
1 files changed, 1325 insertions, 2570 deletions
diff --git a/drivers/net/arcnet.c b/drivers/net/arcnet.c index c9f13150c..7669b59a8 100644 --- a/drivers/net/arcnet.c +++ b/drivers/net/arcnet.c @@ -1,8 +1,9 @@ -/* arcnet.c: +/* $Id: arcnet.c,v 1.30 1997/09/05 08:57:46 mj Exp $ + Written 1994-1996 by Avery Pennarun, derived from skeleton.c by Donald Becker. - Contact Avery at: apenwarr@foxnet.net or + Contact Avery at: apenwarr@bond.net or RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9 ********************** @@ -17,6 +18,32 @@ ********************** + v2.92 ALPHA (97/02/09) + - Code cleanup [Martin Mares <mj@atrey.karlin.mff.cuni.cz>] + - Better probing for the COM90xx chipset, although only as + a temporary solution until we implement adding of all found + devices at once. [mj] + + v2.91 ALPHA (97/19/08) + - Add counting of octets in/out. + + v2.90 ALPHA (97/08/08) + - Add support for kernel command line parsing so that chipset + drivers are usable when compiled in. + + v2.80 ALPHA (97/08/01) + - Split source into multiple files; generic arcnet support and + individual chipset drivers. <dwmw2@cam.ac.uk> + + v2.61 ALPHA (97/07/30) by David Woodhouse (dwmw2@cam.ac.uk) for + Nortel (Northern Telecom). + - Added support for IO-mapped modes and for SMC COM20020 chipset. + - Fixed (avoided) race condition in send_packet routines which was + discovered when the buffer copy routines got slow (?). + - Fixed support for device naming at load time. + - Added backplane, clock and timeout options for COM20020. + - Added support for promiscuous mode. + v2.60 ALPHA (96/11/23) - Added patch from Vojtech Pavlik <vojtech@atrey.karlin.mff.cuni.cz> and Martin Mares <mj@k332.feld.cvut.cz> to make the driver work @@ -95,30 +122,27 @@ This is half-done in ARCnet 2.60, but still uses some undocumented i386 stuff. (We shouldn't call phys_to_virt, for example.) + - Allow use of RFC1051 or Ether devices without RFC1201. + - Keep separate stats for each device. - Support "arpless" mode like NetBSD does, and as recommended by the (obsoleted) RFC1051. - - Some way to make RIM_I_MODE runtime switchable? Yuck... - Smarter recovery from RECON-during-transmit conditions. (ie. retransmit immediately) - - Make arcnetE_send_packet use arcnet_prepare_tx for loading the - packet into ARCnet memory. - - Probe for multiple devices in one shot (trying to decide whether - to do it the "ugly" way or not). - Add support for the new 1.3.x IP header cache, and other features. - - Debug level should be changed with a system call, not a hack to - the "metric" flag. + - Replace setting of debug level with the "metric" flag hack by + something better. SIOCDEVPRIVATE is a good candidate, but it would + require an extra user-level utility. + - What about cards with shared memory that can be "turned off?" (or that have none at all, like the SMC PC500longboard) + Does this work now, with IO_MAPPED_BUFFERS? + - Autoconfigure PDI5xxPlus cards. (I now have a PDI508Plus to play with temporarily.) Update: yes, the Pure Data config program for DOS works fine, but the PDI508Plus I have doesn't! :) - - Try to implement promiscuous (receive-all-packets) mode available - on some newer cards with COM20020 and similar chips. I don't have - one, but SMC sent me the specs. - ATA protocol support?? - VINES TCP/IP encapsulation?? (info needed) - Sources: - Crynwr arcnet.com/arcether.com packet drivers. - arcnet.c v0.00 dated 1/1/94 and apparently by @@ -128,6 +152,7 @@ - RFC's 1201 and 1051 - re: TCP/IP over ARCnet - The official ARCnet COM9026 data sheets (!) thanks to Ken Cornetet <kcornete@nyx10.cs.du.edu> + - The official ARCnet COM20020 data sheets. - Information on some more obscure ARCnet controller chips, thanks to the nice people at SMC. - net/inet/eth.c (from kernel 1.1.50) for header-building info. @@ -137,9 +162,7 @@ */ static const char *version = - "arcnet.c: v2.60 96/11/23 Avery Pennarun <apenwarr@foxnet.net>\n"; - - + "arcnet.c: v2.92 97/09/02 Avery Pennarun <apenwarr@bond.net> et al.\n"; #include <linux/module.h> #include <linux/config.h> @@ -164,6 +187,9 @@ static const char *version = #include <linux/skbuff.h> #include <linux/init.h> +#include <linux/if_arcnet.h> +#include <linux/arcdevice.h> + #include <asm/system.h> #include <asm/bitops.h> #include <asm/io.h> @@ -171,95 +197,6 @@ static const char *version = #include <net/arp.h> -/**************************************************************************/ - -/* Define this if you have a really ancient "RIM I" ARCnet card with no I/O - * port at all and _only_ shared memory; this option MAY work for you. It's - * untested, though, so good luck and write to me with any results! - */ -#undef RIM_I_MODE - -/* Normally, the ARCnet device needs to be assigned a name (default arc0). - * Ethernet devices have a function to automatically try eth0, eth1, etc - * until a free name is found. To name the ARCnet device using an "eth?" - * device name, define this option. - */ -#undef CONFIG_ARCNET_ETHNAME - -/* On a fast computer, the buffer copy from memory to the ARCnet card during - * a transmit can hog the bus just a little too long. SLOW_XMIT_COPY - * replaces the fast memcpy() with a slower for() loop that seems to solve - * my problems with ftape. - * - * Probably a better solution would be to use memcpy_toio (more portable - * anyway) and modify that routine to support REALLY_SLOW_IO-style - * defines; ARCnet probably is not the only driver that can screw up an - * ftape DMA transfer. - * - * Turn this on if you have timing-sensitive DMA (ie. a tape drive) and - * would like to sacrifice a little bit of network speed to reduce tape - * write retries or some related problem. - */ -#undef SLOW_XMIT_COPY - -/* The card sends the reconfiguration signal when it loses the connection to - * the rest of its network. It is a 'Hello, is anybody there?' cry. This - * usually happens when a new computer on the network is powered on or when - * the cable is broken. - * - * Define DETECT_RECONFIGS if you want to detect network reconfigurations. - * Recons may be a real nuisance on a larger ARCnet network; if you are a - * network administrator you probably would like to count them. - * Reconfigurations will be recorded in stats.tx_carrier_errors (the last - * field of the /proc/net/dev file). - * - * Define SHOW_RECONFIGS if you really want to see a log message whenever - * a RECON occurs. - */ -#define DETECT_RECONFIGS -#undef SHOW_RECONFIGS - -/* RECON_THRESHOLD is the maximum number of RECON messages to receive within - * one minute before printing a "cabling problem" warning. You must have - * DETECT_RECONFIGS enabled if you want to use this. The default value - * should be fine. - * - * After that, a "cabling restored" message will be printed on the next IRQ - * if no RECON messages have been received for 10 seconds. - * - * Do not define RECON_THRESHOLD at all if you want to disable this feature. - */ -#define RECON_THRESHOLD 30 - -/* Define this to the minimum "timeout" value. If a transmit takes longer - * than TX_TIMEOUT jiffies, Linux will abort the TX and retry. On a large - * network, or one with heavy network traffic, this timeout may need to be - * increased. The larger it is, though, the longer it will be between - * necessary transmits - don't set this too large. - */ -#define TX_TIMEOUT 20 - -/* Define this to speed up the autoprobe by assuming if only one io port and - * shmem are left in the list at Stage 5, they must correspond to each - * other. - * - * This is undefined by default because it might not always be true, and the - * extra check makes the autoprobe even more careful. Speed demons can turn - * it on - I think it should be fine if you only have one ARCnet card - * installed. - * - * If no ARCnet cards are installed, this delay never happens anyway and thus - * the option has no effect. - */ -#undef FAST_PROBE - -/* Define this to speed up "ifconfig up" by moving the card reset command - * around. This is a new option in 2.41 ALPHA. If it causes problems, - * undefine this to get the old behaviour; then send me email, because if - * there are no problems, this option will go away very soon. - */ -#define FAST_IFCONFIG - /* Define this if you want to make it easier to use the "call trace" when * a kernel NULL pointer assignment occurs. Hopefully unnecessary, most of * the time. It will make all the function names (and other things) show @@ -269,353 +206,80 @@ static const char *version = /**************************************************************************/ -/* New debugging bitflags: each option can be enabled individually. - * - * These can be set while the driver is running by typing: - * ifconfig arc0 down metric 1xxx HOSTNAME - * where 1xxx is 1000 + the debug level you want - * and HOSTNAME is your hostname/ip address - * and then resetting your routes. - * - * An ioctl() should be used for this instead, someday. - * - * Note: only debug flags included in the ARCNET_DEBUG_MAX define will - * actually be available. GCC will (at least, GCC 2.7.0 will) notice - * lines using a BUGLVL not in ARCNET_DEBUG_MAX and automatically optimize - * them out. +/* These are now provided by the chipset driver. There's a performance + * overhead in using them. */ -#define D_NORMAL 1 /* important operational info */ -#define D_EXTRA 2 /* useful, but non-vital information */ -#define D_INIT 4 /* show init/probe messages */ -#define D_INIT_REASONS 8 /* show reasons for discarding probes */ -/* debug levels below give LOTS of output during normal operation! */ -#define D_DURING 16 /* trace operations (including irq's) */ -#define D_TX 32 /* show tx packets */ -#define D_RX 64 /* show rx packets */ -#define D_SKB 128 /* show skb's */ - -#ifndef ARCNET_DEBUG_MAX -#define ARCNET_DEBUG_MAX (~0) /* enable ALL debug messages */ -/*#define ARCNET_DEBUG_MAX (D_NORMAL|D_EXTRA|D_INIT|D_INIT_REASONS) */ -/*#define ARCNET_DEBUG_MAX 0 */ /* enable NO messages (bad idea) */ -#endif - -#ifndef ARCNET_DEBUG -#define ARCNET_DEBUG (D_NORMAL|D_EXTRA) -#endif -int arcnet_debug = ARCNET_DEBUG; - -/* macros to simplify debug checking */ -#define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x)) -#define BUGMSG2(x,msg,args...) BUGLVL(x) printk(msg, ## args) -#define BUGMSG(x,msg,args...) BUGMSG2(x,"%s%6s: " msg, \ - x==D_NORMAL ? KERN_WARNING : \ - x<=D_INIT_REASONS ? KERN_INFO : KERN_DEBUG , \ - dev->name , ## args) - -/* Some useful multiprotocol macros. The idea here is that GCC will - * optimize away multiple tests or assignments to lp->adev. Relying on this - * results in the cleanest mess possible. - */ -#define ADEV lp->adev - -#ifdef CONFIG_ARCNET_ETH - #define EDEV lp->edev -#else - #define EDEV lp->adev -#endif - -#ifdef CONFIG_ARCNET_1051 - #define SDEV lp->sdev -#else - #define SDEV lp->adev -#endif -#define TBUSY ADEV->tbusy=EDEV->tbusy=SDEV->tbusy -#define IF_TBUSY (ADEV->tbusy||EDEV->tbusy||SDEV->tbusy) +#define AINTMASK(x) ((*lp->asetmask)(dev, x)) +#define ARCSTATUS ((*lp->astatus)(dev)) +#define ACOMMAND(x) ((*lp->acommand)(dev, x)) -#define INTERRUPT ADEV->interrupt=EDEV->interrupt=SDEV->interrupt -#define IF_INTERRUPT (ADEV->interrupt||EDEV->interrupt||SDEV->interrupt) +int arcnet_debug=ARCNET_DEBUG; -#define START ADEV->start=EDEV->start=SDEV->start +/* Exported function prototypes */ - -/* The number of low I/O ports used by the ethercard. */ -#define ARCNET_TOTAL_SIZE 16 - -/* Handy defines for ARCnet specific stuff */ - /* COM 9026 controller chip --> ARCnet register addresses */ -#define _INTMASK (ioaddr+0) /* writable */ -#define _STATUS (ioaddr+0) /* readable */ -#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ -#define _RESET (ioaddr+8) /* software reset (on read) */ - -/* RIM I (command/status is memory mapped) versus RIM III (standard I/O - * mapped) macros. These make things a bit cleaner. - */ -#ifdef RIM_I_MODE - #define IOADDR (dev->mem_start+0x800) - #define ARCSTATUS readb(_STATUS) - #define ACOMMAND(cmd) writeb((cmd),_COMMAND) - #define ARCRESET writeb(TESTvalue,ioaddr-0x800) /* fake reset */ - #define AINTMASK(msk) writeb((msk),_INTMASK) - #define RELEASE_REGION(x,y) /* nothing */ +#ifdef MODULE +int init_module(void); +void cleanup_module(void); #else - #define IOADDR (dev->base_addr) - #define ARCSTATUS inb(_STATUS) - #define ACOMMAND(cmd) outb((cmd),_COMMAND) - #define AINTMASK(msk) outb((msk),_INTMASK) - #define ARCRESET inb(_RESET) - #define RELEASE_REGION(x,y) release_region((x),(y)) +void arcnet_init(void); +static int init_module(void); +#ifdef CONFIG_ARCNET_COM90xx +extern char com90xx_explicit; +extern int arc90xx_probe(struct device *dev); #endif - -#define SETMASK AINTMASK(lp->intmask) - - /* Time needed to reset the card - in jiffies. This works on my SMC - * PC100. I can't find a reference that tells me just how long I - * should wait. - */ -#define RESETtime (HZ * 3 / 10) /* reset */ - - /* these are the max/min lengths of packet data. (including - * ClientData header) - * note: packet sizes 250, 251, 252 are impossible (God knows why) - * so exception packets become necessary. - * - * These numbers are compared with the length of the full packet, - * including ClientData header. - */ -#define MTU 253 /* normal packet max size */ -#define MinTU 257 /* extended packet min size */ -#define XMTU 508 /* extended packet max size */ - - /* status/interrupt mask bit fields */ -#define TXFREEflag 0x01 /* transmitter available */ -#define TXACKflag 0x02 /* transmitted msg. ackd */ -#define RECONflag 0x04 /* system reconfigured */ -#define TESTflag 0x08 /* test flag */ -#define RESETflag 0x10 /* power-on-reset */ -#define RES1flag 0x20 /* reserved - usually set by jumper */ -#define RES2flag 0x40 /* reserved - usually set by jumper */ -#define NORXflag 0x80 /* receiver inhibited */ - - /* in the command register, the following bits have these meanings: - * 0-2 command - * 3-4 page number (for enable rcv/xmt command) - * 7 receive broadcasts - */ -#define NOTXcmd 0x01 /* disable transmitter */ -#define NORXcmd 0x02 /* disable receiver */ -#define TXcmd 0x03 /* enable transmitter */ -#define RXcmd 0x04 /* enable receiver */ -#define CONFIGcmd 0x05 /* define configuration */ -#define CFLAGScmd 0x06 /* clear flags */ -#define TESTcmd 0x07 /* load test flags */ - - /* flags for "clear flags" command */ -#define RESETclear 0x08 /* power-on-reset */ -#define CONFIGclear 0x10 /* system reconfigured */ - - /* flags for "load test flags" command */ -#define TESTload 0x08 /* test flag (diagnostic) */ - - /* byte deposited into first address of buffers on reset */ -#define TESTvalue 0321 /* that's octal for 0xD1 :) */ - - /* for "enable receiver" command */ -#define RXbcasts 0x80 /* receive broadcasts */ - - /* flags for "define configuration" command */ -#define NORMALconf 0x00 /* 1-249 byte packets */ -#define EXTconf 0x08 /* 250-504 byte packets */ - - /* Starts receiving packets into recbuf. - */ -#define EnableReceiver() ACOMMAND(RXcmd|(recbuf<<3)|RXbcasts) - - /* RFC1201 Protocol ID's */ -#define ARC_P_IP 212 /* 0xD4 */ -#define ARC_P_ARP 213 /* 0xD5 */ -#define ARC_P_RARP 214 /* 0xD6 */ -#define ARC_P_IPX 250 /* 0xFA */ -#define ARC_P_NOVELL_EC 236 /* 0xEC */ - - /* Old RFC1051 Protocol ID's */ -#define ARC_P_IP_RFC1051 240 /* 0xF0 */ -#define ARC_P_ARP_RFC1051 241 /* 0xF1 */ - - /* MS LanMan/WfWg protocol */ -#define ARC_P_ETHER 0xE8 - - /* Unsupported/indirectly supported protocols */ -#define ARC_P_DATAPOINT_BOOT 0 /* very old Datapoint equipment */ -#define ARC_P_DATAPOINT_MOUNT 1 -#define ARC_P_POWERLAN_BEACON 8 /* Probably ATA-Netbios related */ -#define ARC_P_POWERLAN_BEACON2 243 -#define ARC_P_LANSOFT 251 /* 0xFB - what is this? */ -#define ARC_P_ATALK 0xDD - - /* the header required by the card itself */ -struct HardHeader -{ - u_char source, /* source ARCnet - filled in automagically */ - destination, /* destination ARCnet - 0 for broadcast */ - offset1, /* offset of ClientData (256-byte packets) */ - offset2; /* offset of ClientData (512-byte packets) */ -}; - - /* a complete ARCnet packet */ -union ArcPacket -{ - struct HardHeader hardheader; /* the hardware header */ - u_char raw[512]; /* raw packet info, incl ClientData */ -}; - - /* the "client data" header - RFC1201 information - * notice that this screws up if it's not an even number of bytes - * <sigh> - */ -struct ClientData -{ - /* data that's NOT part of real packet - we MUST get rid of it before - * actually sending!! - */ - u_char saddr, /* Source address - needed for IPX */ - daddr; /* Destination address */ - - /* data that IS part of real packet */ - u_char protocol_id, /* ARC_P_IP, ARC_P_ARP, etc */ - split_flag; /* for use with split packets */ - u_short sequence; /* sequence number */ -}; -#define EXTRA_CLIENTDATA (sizeof(struct ClientData)-4) - - - /* the "client data" header - RFC1051 information - * this also screws up if it's not an even number of bytes - * <sigh again> - */ -struct S_ClientData -{ - /* data that's NOT part of real packet - we MUST get rid of it before - * actually sending!! - */ - u_char saddr, /* Source address - needed for IPX */ - daddr, /* Destination address */ - junk; /* padding to make an even length */ - - /* data that IS part of real packet */ - u_char protocol_id; /* ARC_P_IP, ARC_P_ARP, etc */ -}; -#define S_EXTRA_CLIENTDATA (sizeof(struct S_ClientData)-1) - - -/* "Incoming" is information needed for each address that could be sending - * to us. Mostly for partially-received split packets. - */ -struct Incoming -{ - struct sk_buff *skb; /* packet data buffer */ - unsigned char lastpacket, /* number of last packet (from 1) */ - numpackets; /* number of packets in split */ - u_short sequence; /* sequence number of assembly */ -}; - -struct Outgoing -{ - struct sk_buff *skb; /* buffer from upper levels */ - struct ClientData *hdr; /* clientdata of last packet */ - u_char *data; /* pointer to data in packet */ - short length, /* bytes total */ - dataleft, /* bytes left */ - segnum, /* segment being sent */ - numsegs, /* number of segments */ - seglen; /* length of segment */ -}; - - -/* Information that needs to be kept for each board. */ -struct arcnet_local { - struct net_device_stats stats; - u_short sequence; /* sequence number (incs with each packet) */ - u_char stationid, /* our 8-bit station address */ - recbuf, /* receive buffer # (0 or 1) */ - txbuf, /* transmit buffer # (2 or 3) */ - txready, /* buffer where a packet is ready to send */ - intmask; /* current value of INTMASK register */ - short intx, /* in TX routine? */ - in_txhandler, /* in TX_IRQ handler? */ - sending, /* transmit in progress? */ - lastload_dest, /* can last loaded packet be acked? */ - lasttrans_dest; /* can last TX'd packet be acked? */ - -#if defined(DETECT_RECONFIGS) && defined(RECON_THRESHOLD) - time_t first_recon, /* time of "first" RECON message to count */ - last_recon; /* time of most recent RECON */ - int num_recons, /* number of RECONs between first and last. */ - network_down; /* do we think the network is down? */ #endif - struct timer_list timer; /* the timer interrupt struct */ - struct Incoming incoming[256]; /* one from each address */ - struct Outgoing outgoing; /* packet currently being sent */ - - struct device *adev; /* RFC1201 protocol device */ - -#ifdef CONFIG_ARCNET_ETH - struct device *edev; /* Ethernet-Encap device */ -#endif - -#ifdef CONFIG_ARCNET_1051 - struct device *sdev; /* RFC1051 protocol device */ -#endif -}; - - -/* Index to functions, as function prototypes. */ +void arcnet_tx_done(struct device *dev, struct arcnet_local *lp); +void arcnet_use_count (int open); +void arcnet_setup(struct device *dev); +void arcnet_makename(char *device); +void arcnetA_continue_tx(struct device *dev); +int arcnet_go_tx(struct device *dev,int enable_irq); +void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs); +void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr); + +EXPORT_SYMBOL(arcnet_debug); +EXPORT_SYMBOL(arcnet_tx_done); +EXPORT_SYMBOL(arcnet_use_count); +EXPORT_SYMBOL(arcnet_setup); +EXPORT_SYMBOL(arcnet_makename); +EXPORT_SYMBOL(arcnetA_continue_tx); +EXPORT_SYMBOL(arcnet_go_tx); +EXPORT_SYMBOL(arcnet_interrupt); +EXPORT_SYMBOL(arcnet_rx); #if ARCNET_DEBUG_MAX & D_SKB -static void arcnet_dump_skb(struct device *dev,struct sk_buff *skb, +void arcnet_dump_skb(struct device *dev,struct sk_buff *skb, char *desc); +EXPORT_SYMBOL(arcnet_dump_skb); #else # define arcnet_dump_skb(dev,skb,desc) ; #endif #if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX) -static void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext, +void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext, char *desc); +EXPORT_SYMBOL(arcnet_dump_packet); #else # define arcnet_dump_packet(dev,buffer,ext,desc) ; #endif -extern int arcnet_probe(struct device *dev); -static int arcnet_found(struct device *dev,int port,int airq,u_long shmem); +/* Internal function prototypes */ -static void arcnet_setup(struct device *dev); static int arcnet_open(struct device *dev); static int arcnet_close(struct device *dev); -static int arcnet_reset(struct device *dev,int reset_delay); - +static int arcnetA_header(struct sk_buff *skb,struct device *dev, + unsigned short type,void *daddr,void *saddr,unsigned len); +static int arcnetA_rebuild_header(struct sk_buff *skb); static int arcnet_send_packet_bad(struct sk_buff *skb,struct device *dev); static int arcnetA_send_packet(struct sk_buff *skb, struct device *dev); -static void arcnetA_continue_tx(struct device *dev); -static void arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA); -static int arcnet_go_tx(struct device *dev,int enable_irq); - -static void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs); -static void arcnet_inthandler(struct device *dev); - -static void arcnet_rx(struct device *dev,int recbuf); static void arcnetA_rx(struct device *dev,u_char *buf, int length,u_char saddr, u_char daddr); - static struct net_device_stats *arcnet_get_stats(struct device *dev); +static unsigned short arcnetA_type_trans(struct sk_buff *skb, + struct device *dev); -int arcnetA_header(struct sk_buff *skb,struct device *dev, - unsigned short type,void *daddr,void *saddr,unsigned len); -int arcnetA_rebuild_header(struct sk_buff *skb); -unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev); #ifdef CONFIG_ARCNET_ETH /* functions specific to Ethernet-Encap */ @@ -626,6 +290,7 @@ static void arcnetE_rx(struct device *dev,u_char *arcsoft, int length,u_char saddr, u_char daddr); #endif + #ifdef CONFIG_ARCNET_1051 /* functions specific to RFC1051 */ static int arcnetS_init(struct device *dev); @@ -633,21 +298,12 @@ static int arcnetS_open_close(struct device *dev); static int arcnetS_send_packet(struct sk_buff *skb, struct device *dev); static void arcnetS_rx(struct device *dev,u_char *buf, int length,u_char saddr, u_char daddr); -int arcnetS_header(struct sk_buff *skb,struct device *dev, +static int arcnetS_header(struct sk_buff *skb,struct device *dev, unsigned short type,void *daddr,void *saddr,unsigned len); -int arcnetS_rebuild_header(struct sk_buff *skb); -unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev); +static int arcnetS_rebuild_header(struct sk_buff *skb); +static unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev); #endif -#ifdef MODULE -int init_module(void); -void cleanup_module(void); -#endif - -#define tx_done(dev) 1 - -#define JIFFER(time) for (delayval=jiffies+time; jiffies<delayval;) ; - /**************************************************************************** * * @@ -677,6 +333,7 @@ void arcnet_dump_skb(struct device *dev,struct sk_buff *skb,char *desc) } #endif + /* Dump the contents of an ARCnet buffer */ #if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX) @@ -699,609 +356,6 @@ void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,char *desc) } #endif -/**************************************************************************** - * * - * Probe and initialization * - * * - ****************************************************************************/ - -#ifdef RIM_I_MODE - -/* We cannot probe for a RIM I card; one reason is I don't know how to reset - * them. In fact, we can't even get their node ID automatically. So, we - * need to be passed a specific shmem address, IRQ, and node ID (stored in - * dev->base_addr) - */ -__initfunc(int arcnet_probe(struct device *dev)) -{ - BUGLVL(D_NORMAL) printk(version); - BUGMSG(D_NORMAL,"Compiled for ARCnet RIM I (autoprobe disabled)\n"); - BUGMSG(D_NORMAL,"Given: node %02lXh, shmem %lXh, irq %d\n", - dev->base_addr,dev->mem_start,dev->irq); - - if (dev->mem_start<=0 || dev->irq<=0) - { - BUGMSG(D_NORMAL,"No autoprobe for RIM I; you " - "must specify the shmem and irq!\n"); - return -ENODEV; - } - - if (dev->base_addr<=0 || dev->base_addr>255) - { - BUGMSG(D_NORMAL,"You need to specify your card's station " - "ID!\n"); - return -ENODEV; - } - - return arcnet_found(dev,dev->base_addr,dev->irq,dev->mem_start); -} - -#else /* not RIM_I_MODE, so use a real autoprobe */ - -/* Check for an ARCnet network adaptor, and return '0' if one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. - * If dev->base_addr == 2, allocate space for the device and return success - * (detachable devices only). - * - * NOTE: the list of possible ports/shmems is static, so it is retained - * across calls to arcnet_probe. So, if more than one ARCnet probe is made, - * values that were discarded once will not even be tried again. - * - * FIXME: grab all devices in one shot and eliminate the big static array. - */ - -static int ports[(0x3f0 - 0x200) / 16 + 1] __initdata = { 0 }; -static u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] __initdata = { 0 }; - -__initfunc(int arcnet_probe(struct device *dev)) -{ - static int init_once = 0; - static int numports=sizeof(ports)/sizeof(ports[0]), - numshmems=sizeof(shmems)/sizeof(shmems[0]); - - int count,status,delayval,ioaddr,numprint,airq,retval=-ENODEV, - openparen=0; - unsigned long airqmask; - int *port; - u_long *shmem; - - if (!init_once) - { - for (count=0x200; count<=0x3f0; count+=16) - ports[(count-0x200)/16] = count; - for (count=0xA0000; count<=0xFF800; count+=2048) - shmems[(count-0xA0000)/2048] = count; - init_once=1; - } - - BUGLVL(D_NORMAL) printk(version); - - BUGMSG(D_DURING,"space used for probe buffers: %d+%d=%d bytes\n", - sizeof(ports),sizeof(shmems), - sizeof(ports)+sizeof(shmems)); - - -#if 1 - BUGLVL(D_EXTRA) - { - printk("arcnet: ***\n"); - printk("arcnet: * Read arcnet.txt for important release notes!\n"); - printk("arcnet: *\n"); - printk("arcnet: * This is an ALPHA version! (Last stable release: v2.56) E-mail me if\n"); - printk("arcnet: * you have any questions, comments, or bug reports.\n"); - printk("arcnet: ***\n"); - } -#endif - - BUGMSG(D_INIT,"given: base %lXh, IRQ %d, shmem %lXh\n", - dev->base_addr,dev->irq,dev->mem_start); - - if (dev->base_addr > 0x1ff) /* Check a single specified port */ - { - ports[0]=dev->base_addr; - numports=1; - } - else if (dev->base_addr > 0) /* Don't probe at all. */ - return -ENXIO; - - if (dev->mem_start) - { - shmems[0]=dev->mem_start; - numshmems=1; - } - - - /* Stage 1: abandon any reserved ports, or ones with status==0xFF - * (empty), and reset any others by reading the reset port. - */ - BUGMSG(D_INIT,"Stage 1: "); - numprint=0; - for (port = &ports[0]; port-ports<numports; port++) - { - numprint++; - if (numprint>8) - { - BUGMSG2(D_INIT,"\n"); - BUGMSG(D_INIT,"Stage 1: "); - numprint=1; - } - BUGMSG2(D_INIT,"%Xh ",*port); - - ioaddr=*port; - - if (check_region(*port, ARCNET_TOTAL_SIZE)) - { - BUGMSG2(D_INIT_REASONS,"(check_region)\n"); - BUGMSG(D_INIT_REASONS,"Stage 1: "); - BUGLVL(D_INIT_REASONS) numprint=0; - *port=ports[numports-1]; - numports--; - port--; - continue; - } - - if (ARCSTATUS == 0xFF) - { - BUGMSG2(D_INIT_REASONS,"(empty)\n"); - BUGMSG(D_INIT_REASONS,"Stage 1: "); - BUGLVL(D_INIT_REASONS) numprint=0; - *port=ports[numports-1]; - numports--; - port--; - continue; - } - - ARCRESET; /* begin resetting card */ - - BUGMSG2(D_INIT_REASONS,"\n"); - BUGMSG(D_INIT_REASONS,"Stage 1: "); - BUGLVL(D_INIT_REASONS) numprint=0; - } - BUGMSG2(D_INIT,"\n"); - - if (!numports) - { - BUGMSG(D_NORMAL,"Stage 1: No ARCnet cards found.\n"); - return -ENODEV; - } - - - /* Stage 2: we have now reset any possible ARCnet cards, so we can't - * do anything until they finish. If D_INIT, print the list of - * cards that are left. - */ - BUGMSG(D_INIT,"Stage 2: "); - numprint=0; - for (port = &ports[0]; port-ports<numports; port++) - { - numprint++; - if (numprint>8) - { - BUGMSG2(D_INIT,"\n"); - BUGMSG(D_INIT,"Stage 2: "); - numprint=1; - } - BUGMSG2(D_INIT,"%Xh ",*port); - } - BUGMSG2(D_INIT,"\n"); - JIFFER(RESETtime); - - - /* Stage 3: abandon any shmem addresses that don't have the signature - * 0xD1 byte in the right place, or are read-only. - */ - BUGMSG(D_INIT,"Stage 3: "); - numprint=0; - for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++) - { - u_long ptr; - - numprint++; - if (numprint>8) - { - BUGMSG2(D_INIT,"\n"); - BUGMSG(D_INIT,"Stage 3: "); - numprint=1; - } - BUGMSG2(D_INIT,"%lXh ",*shmem); - - ptr=(u_long)(*shmem); - - if (readb(ptr) != TESTvalue) - { - BUGMSG2(D_INIT_REASONS,"(mem=%02Xh, not %02Xh)\n", - readb(ptr),TESTvalue); - BUGMSG(D_INIT_REASONS,"Stage 3: "); - BUGLVL(D_INIT_REASONS) numprint=0; - *shmem=shmems[numshmems-1]; - numshmems--; - shmem--; - continue; - } - - /* By writing 0x42 to the TESTvalue location, we also make - * sure no "mirror" shmem areas show up - if they occur - * in another pass through this loop, they will be discarded - * because *cptr != TESTvalue. - */ - writeb(0x42,ptr); - if (readb(ptr) != 0x42) - { - BUGMSG2(D_INIT_REASONS,"(read only)\n"); - BUGMSG(D_INIT_REASONS,"Stage 3: "); - *shmem=shmems[numshmems-1]; - numshmems--; - shmem--; - continue; - } - - BUGMSG2(D_INIT_REASONS,"\n"); - BUGMSG(D_INIT_REASONS,"Stage 3: "); - BUGLVL(D_INIT_REASONS) numprint=0; - } - BUGMSG2(D_INIT,"\n"); - - if (!numshmems) - { - BUGMSG(D_NORMAL,"Stage 3: No ARCnet cards found.\n"); - return -ENODEV; - } - - /* Stage 4: something of a dummy, to report the shmems that are - * still possible after stage 3. - */ - BUGMSG(D_INIT,"Stage 4: "); - numprint=0; - for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++) - { - numprint++; - if (numprint>8) - { - BUGMSG2(D_INIT,"\n"); - BUGMSG(D_INIT,"Stage 4: "); - numprint=1; - } - BUGMSG2(D_INIT,"%lXh ",*shmem); - } - BUGMSG2(D_INIT,"\n"); - - - /* Stage 5: for any ports that have the correct status, can disable - * the RESET flag, and (if no irq is given) generate an autoirq, - * register an ARCnet device. - * - * Currently, we can only register one device per probe, so quit - * after the first one is found. - */ - BUGMSG(D_INIT,"Stage 5: "); - numprint=0; - for (port = &ports[0]; port-ports<numports; port++) - { - numprint++; - if (numprint>8) - { - BUGMSG2(D_INIT,"\n"); - BUGMSG(D_INIT,"Stage 5: "); - numprint=1; - } - BUGMSG2(D_INIT,"%Xh ",*port); - - ioaddr=*port; - status=ARCSTATUS; - - if ((status & 0x9D) - != (NORXflag|RECONflag|TXFREEflag|RESETflag)) - { - BUGMSG2(D_INIT_REASONS,"(status=%Xh)\n",status); - BUGMSG(D_INIT_REASONS,"Stage 5: "); - BUGLVL(D_INIT_REASONS) numprint=0; - *port=ports[numports-1]; - numports--; - port--; - continue; - } - - ACOMMAND(CFLAGScmd|RESETclear|CONFIGclear); - status=ARCSTATUS; - if (status & RESETflag) - { - BUGMSG2(D_INIT_REASONS," (eternal reset, status=%Xh)\n", - status); - BUGMSG(D_INIT_REASONS,"Stage 5: "); - BUGLVL(D_INIT_REASONS) numprint=0; - *port=ports[numports-1]; - numports--; - port--; - continue; - } - - /* skip this completely if an IRQ was given, because maybe - * we're on a machine that locks during autoirq! - */ - if (!dev->irq) - { - /* if we do this, we're sure to get an IRQ since the - * card has just reset and the NORXflag is on until - * we tell it to start receiving. - */ - airqmask = probe_irq_on(); - AINTMASK(NORXflag); - udelay(1); - AINTMASK(0); - airq = probe_irq_off(airqmask); - - if (airq<=0) - { - BUGMSG2(D_INIT_REASONS,"(airq=%d)\n",airq); - BUGMSG(D_INIT_REASONS,"Stage 5: "); - BUGLVL(D_INIT_REASONS) numprint=0; - *port=ports[numports-1]; - numports--; - port--; - continue; - } - } - else - { - airq=dev->irq; - } - - BUGMSG2(D_INIT,"(%d,", airq); - openparen=1; - - /* Everything seems okay. But which shmem, if any, puts - * back its signature byte when the card is reset? - * - * If there are multiple cards installed, there might be - * multiple shmems still in the list. - */ -#ifdef FAST_PROBE - if (numports>1 || numshmems>1) - { - ARCRESET; - JIFFER(RESETtime); - } - else - { - /* just one shmem and port, assume they match */ - writeb(TESTvalue,shmems[0]); - } -#else - ARCRESET; - JIFFER(RESETtime); -#endif - - - for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++) - { - u_long ptr; - ptr=(u_long)(*shmem); - - if (readb(ptr) == TESTvalue) /* found one */ - { - BUGMSG2(D_INIT,"%lXh)\n", *shmem); - openparen=0; - - /* register the card */ - retval=arcnet_found(dev,*port,airq,*shmem); - if (retval) openparen=0; - - /* remove shmem from the list */ - *shmem=shmems[numshmems-1]; - numshmems--; - - break; - } - else - { - BUGMSG2(D_INIT_REASONS,"%Xh-", readb(ptr)); - } - } - - if (openparen) - { - BUGMSG2(D_INIT,"no matching shmem)\n"); - BUGMSG(D_INIT_REASONS,"Stage 5: "); - BUGLVL(D_INIT_REASONS) numprint=0; - } - - *port=ports[numports-1]; - numports--; - port--; - - if (!retval) break; - } - BUGMSG(D_INIT_REASONS,"\n"); - - /* Now put back TESTvalue on all leftover shmems. - */ - for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++) - writeb(TESTvalue,*shmem); - - if (retval) BUGMSG(D_NORMAL,"Stage 5: No ARCnet cards found.\n"); - return retval; -} - -#endif /* !RIM_I_MODE */ - - -/* Set up the struct device associated with this card. Called after - * probing succeeds. - */ -__initfunc(int arcnet_found(struct device *dev,int port,int airq, u_long shmem)) -{ - u_long first_mirror,last_mirror; - struct arcnet_local *lp; - int mirror_size; - - /* reserve the irq */ - if (request_irq(airq,&arcnet_interrupt,0,"arcnet",NULL)) - { - BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq); - return -ENODEV; - } - irq2dev_map[airq]=dev; - dev->irq=airq; - -#ifdef RIM_I_MODE - dev->base_addr=0; - writeb(TESTvalue,shmem); - writeb(port,shmem+1); /* actually the node ID */ -#else - /* reserve the I/O region - guaranteed to work by check_region */ - request_region(port,ARCNET_TOTAL_SIZE,"arcnet"); - dev->base_addr=port; -#endif - - /* find the real shared memory start/end points, including mirrors */ - - #define BUFFER_SIZE (512) - #define MIRROR_SIZE (BUFFER_SIZE*4) - - /* guess the actual size of one "memory mirror" - the number of - * bytes between copies of the shared memory. On most cards, it's - * 2k (or there are no mirrors at all) but on some, it's 4k. - */ - mirror_size=MIRROR_SIZE; - if (readb(shmem)==TESTvalue - && readb(shmem-mirror_size)!=TESTvalue - && readb(shmem-2*mirror_size)==TESTvalue) - mirror_size*=2; - - first_mirror=last_mirror=shmem; - while (readb(first_mirror)==TESTvalue) first_mirror-=mirror_size; - first_mirror+=mirror_size; - - while (readb(last_mirror)==TESTvalue) last_mirror+=mirror_size; - last_mirror-=mirror_size; - - dev->mem_start=first_mirror; - dev->mem_end=last_mirror+MIRROR_SIZE-1; - dev->rmem_start=dev->mem_start+BUFFER_SIZE*0; - dev->rmem_end=dev->mem_start+BUFFER_SIZE*2-1; - - /* Initialize the rest of the device structure. */ - - dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (dev->priv == NULL) - { - irq2dev_map[airq] = NULL; - free_irq(airq,NULL); - RELEASE_REGION(port,ARCNET_TOTAL_SIZE); - return -ENOMEM; - } - memset(dev->priv,0,sizeof(struct arcnet_local)); - lp=(struct arcnet_local *)(dev->priv); - - dev->open=arcnet_open; - dev->stop=arcnet_close; - dev->hard_start_xmit=arcnetA_send_packet; - dev->get_stats=arcnet_get_stats; - /*dev->set_multicast_list = &set_multicast_list;*/ - - /* Fill in the fields of the device structure with generic - * values. - */ - arcnet_setup(dev); - - /* And now fill particular fields with arcnet values */ - dev->mtu=1500; /* completely arbitrary - agrees with ether, though */ - dev->hard_header_len=sizeof(struct ClientData); - dev->hard_header=arcnetA_header; - dev->rebuild_header=arcnetA_rebuild_header; - lp->sequence=1; - lp->recbuf=0; - - BUGMSG(D_DURING,"ClientData header size is %d.\n", - sizeof(struct ClientData)); - BUGMSG(D_DURING,"HardHeader size is %d.\n", - sizeof(struct HardHeader)); - - /* get and check the station ID from offset 1 in shmem */ - lp->stationid = readb(first_mirror+1); - if (lp->stationid==0) - BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved " - "for broadcasts!\n"); - else if (lp->stationid==255) - BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse " - "DOS networking programs!\n"); - dev->dev_addr[0]=lp->stationid; - - BUGMSG(D_NORMAL,"ARCnet station %02Xh found at %03lXh, IRQ %d, " - "ShMem %lXh (%ld*%d bytes).\n", - lp->stationid, - dev->base_addr,dev->irq,dev->mem_start, - (dev->mem_end-dev->mem_start+1)/mirror_size,mirror_size); - - return 0; -} - - -/* Do a hardware reset on the card, and set up necessary registers. - * - * This should be called as little as possible, because it disrupts the - * token on the network (causes a RECON) and requires a significant delay. - * - * However, it does make sure the card is in a defined state. - */ -int arcnet_reset(struct device *dev,int reset_delay) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - short ioaddr=IOADDR; - int delayval,recbuf=lp->recbuf; - - /* no IRQ's, please! */ - lp->intmask=0; - SETMASK; - - BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n", - dev->name,ARCSTATUS); - - if (reset_delay) - { - /* reset the card */ - ARCRESET; - JIFFER(RESETtime); - } - - ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */ - ACOMMAND(CFLAGScmd|CONFIGclear); - - /* verify that the ARCnet signature byte is present */ - if (readb(dev->mem_start) != TESTvalue) - { - BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n"); - return 1; - } - - /* clear out status variables */ - recbuf=lp->recbuf=0; - lp->txbuf=2; - - /* enable extended (512-byte) packets */ - ACOMMAND(CONFIGcmd|EXTconf); - -#ifndef SLOW_XMIT_COPY - /* clean out all the memory to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset_io(dev->mem_start,0x42,2048); -#endif - - /* and enable receive of our first packet to the first buffer */ - EnableReceiver(); - - /* re-enable interrupts */ - lp->intmask|=NORXflag; -#ifdef DETECT_RECONFIGS - lp->intmask|=RECONflag; -#endif - SETMASK; - - /* done! return success. */ - return 0; -} - /* Setup a struct device for ARCnet. This should really be in net_init.c * but since there are three different ARCnet devices ANYWAY... <gargle> @@ -1319,9 +373,7 @@ void arcnet_setup(struct device *dev) dev->broadcast[0] = 0x00; /* for us, broadcasts are address 0 */ dev->addr_len = 1; dev->type = ARPHRD_ARCNET; - dev->tx_queue_len = 30; /* fairly long queue - arcnet is - * quite speedy. - */ + dev->tx_queue_len = 30; /* New-style flags. */ dev->flags = IFF_BROADCAST; @@ -1330,6 +382,17 @@ void arcnet_setup(struct device *dev) dev->pa_brdaddr = 0; dev->pa_mask = 0; dev->pa_alen = 4; + + /* Put in this stuff here, so we don't have to export the symbols + * to the chipset drivers. + */ + + dev->open=arcnet_open; + dev->stop=arcnet_close; + dev->hard_start_xmit=arcnetA_send_packet; + dev->get_stats=arcnet_get_stats; + dev->hard_header=arcnetA_header; + dev->rebuild_header=arcnetA_rebuild_header; } @@ -1339,7 +402,6 @@ void arcnet_setup(struct device *dev) * * ****************************************************************************/ - /* Open/initialize the board. This is called sometime after booting when * the 'ifconfig' program is run. * @@ -1350,88 +412,83 @@ void arcnet_setup(struct device *dev) static int arcnet_open(struct device *dev) { - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - int ioaddr=IOADDR; + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - if (dev->metric>=1000) - { - arcnet_debug=dev->metric-1000; - printk(KERN_INFO "%6s: debug level set to %d\n",dev->name,arcnet_debug); - dev->metric=1; - } + if (dev->metric>=1000) + { + arcnet_debug=dev->metric-1000; + printk(KERN_INFO "%6s: debug level set to %d\n",dev->name,arcnet_debug); + dev->metric=1; + } - BUGMSG(D_INIT,"arcnet_open: resetting card.\n"); + BUGMSG(D_INIT,"arcnet_open: resetting card.\n"); -#ifdef FAST_IFCONFIG - /* try to put the card in a defined state - if it fails the first - * time, actually reset it. - */ - if (arcnet_reset(dev,0) && arcnet_reset(dev,1)) - return -ENODEV; -#else - /* reset the card twice in case something goes wrong the first time. - */ - if (arcnet_reset(dev,1) && arcnet_reset(dev,1)) - return -ENODEV; -#endif + /* try to put the card in a defined state - if it fails the first + * time, actually reset it. + */ + if ((*lp->arcnet_reset)(dev,0) && (*lp->arcnet_reset)(dev,1)) + return -ENODEV; - dev->tbusy=0; - dev->interrupt=0; - lp->intx=0; - lp->in_txhandler=0; + dev->tbusy=0; + dev->interrupt=0; + lp->intx=0; + lp->in_txhandler=0; - /* The RFC1201 driver is the default - just store */ - lp->adev=dev; - BUGMSG(D_NORMAL,"ARCnet RFC1201 protocol initialized.\n"); + /* The RFC1201 driver is the default - just store */ + lp->adev=dev; + + /* we're started */ + dev->start=1; #ifdef CONFIG_ARCNET_ETH - /* Initialize the ethernet-encap protocol driver */ - lp->edev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL); - if (lp->edev == NULL) - return -ENOMEM; - memcpy(lp->edev,dev,sizeof(struct device)); - lp->edev->name=(char *)kmalloc(10,GFP_KERNEL); - if (lp->edev->name == NULL) { - kfree(lp->edev); - lp->edev = NULL; - return -ENOMEM; - } - sprintf(lp->edev->name,"%se",dev->name); - lp->edev->init=arcnetE_init; - register_netdev(lp->edev); -#else - BUGMSG(D_NORMAL,"Ethernet-Encap protocol not available (disabled).\n"); + /* Initialize the ethernet-encap protocol driver */ + lp->edev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL); + if (lp->edev == NULL) + return -ENOMEM; + memcpy(lp->edev,dev,sizeof(struct device)); + lp->edev->type=ARPHRD_ETHER; + lp->edev->name=(char *)kmalloc(10,GFP_KERNEL); + if (lp->edev->name == NULL) { + kfree(lp->edev); + lp->edev = NULL; + return -ENOMEM; + } + sprintf(lp->edev->name,"%se",dev->name); + lp->edev->init=arcnetE_init; + register_netdev(lp->edev); #endif #ifdef CONFIG_ARCNET_1051 - /* Initialize the RFC1051-encap protocol driver */ - lp->sdev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL); - memcpy(lp->sdev,dev,sizeof(struct device)); - lp->sdev->name=(char *)kmalloc(10,GFP_KERNEL); - sprintf(lp->sdev->name,"%ss",dev->name); - lp->sdev->init=arcnetS_init; - register_netdev(lp->sdev); -#else - BUGMSG(D_NORMAL,"RFC1051 protocol not available (disabled).\n"); + /* Initialize the RFC1051-encap protocol driver */ + lp->sdev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL); + memcpy(lp->sdev,dev,sizeof(struct device)); + lp->sdev->name=(char *)kmalloc(10,GFP_KERNEL); + sprintf(lp->sdev->name,"%ss",dev->name); + lp->sdev->init=arcnetS_init; + register_netdev(lp->sdev); #endif - /* we're started */ - START=1; + /* Enable TX if we need to */ + if (lp->en_dis_able_TX) + (*lp->en_dis_able_TX)(dev, 1); - /* make sure we're ready to receive IRQ's. - * arcnet_reset sets this for us, but if we receive one before - * START is set to 1, it could be ignored. So, we turn IRQ's - * off, then on again to clean out the IRQ controller. - */ - AINTMASK(0); - udelay(1); /* give it time to set the mask before - * we reset it again. (may not even be - * necessary) - */ - SETMASK; + /* make sure we're ready to receive IRQ's. + * arcnet_reset sets this for us, but if we receive one before + * START is set to 1, it could be ignored. So, we turn IRQ's + * off, then on again to clean out the IRQ controller. + */ - MOD_INC_USE_COUNT; - return 0; + AINTMASK(0); + udelay(1); /* give it time to set the mask before + * we reset it again. (may not even be + * necessary) + */ + SETMASK; + + /* Let it increase its use count */ + (*lp->openclose_device)(1); + + return 0; } @@ -1440,54 +497,74 @@ arcnet_open(struct device *dev) static int arcnet_close(struct device *dev) { - int ioaddr=IOADDR; - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - TBUSY=1; - START=0; + if (test_and_set_bit(0, (int *)&dev->tbusy)) + BUGMSG(D_NORMAL, "arcnet_close: tbusy already set!\n"); - /* Shut down the card */ -#ifdef FAST_IFCONFIG - ARCRESET; /* reset IRQ won't run if START=0 */ -#else - lp->intmask=0; - SETMASK; /* no IRQ's (except RESET, of course) */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ + dev->start=0; +#ifdef CONFIG_ARCNET_1051 + lp->sdev->tbusy=1; + lp->sdev->start=0; +#endif +#ifdef CONFIG_ARCNET_ETH + lp->edev->tbusy=1; + lp->edev->start=0; #endif - /* reset more flags */ - INTERRUPT=0; + /* Shut down the card */ + + /* Disable TX if we need to */ + if (lp->en_dis_able_TX) + (*lp->en_dis_able_TX)(dev, 0); - /* do NOT free lp->adev!! It's static! */ - lp->adev=NULL; + (*lp->arcnet_reset)(dev, 3); /* reset IRQ won't run if START=0 */ +#if 0 + lp->intmask=0; + SETMASK; /* no IRQ's (except RESET, of course) */ + ACOMMAND(NOTXcmd); /* stop transmit */ + ACOMMAND(NORXcmd); /* disable receive */ +#endif + /* reset more flags */ + dev->interrupt=0; #ifdef CONFIG_ARCNET_ETH - /* free the ethernet-encap protocol device */ - lp->edev->priv=NULL; - dev_close(lp->edev); - unregister_netdev(lp->edev); - kfree(lp->edev->name); - kfree(lp->edev); - lp->edev=NULL; + lp->edev->interrupt=0; +#endif +#ifdef CONFIG_ARCNET_1051 + lp->sdev->interrupt=0; +#endif + + /* do NOT free lp->adev!! It's static! */ + lp->adev=NULL; + +#ifdef CONFIG_ARCNET_ETH + /* free the ethernet-encap protocol device */ + lp->edev->priv=NULL; + dev_close(lp->edev); + unregister_netdev(lp->edev); + kfree(lp->edev->name); + kfree(lp->edev); + lp->edev=NULL; #endif #ifdef CONFIG_ARCNET_1051 - /* free the RFC1051-encap protocol device */ - lp->sdev->priv=NULL; - dev_close(lp->sdev); - unregister_netdev(lp->sdev); - kfree(lp->sdev->name); - kfree(lp->sdev); - lp->sdev=NULL; + /* free the RFC1051-encap protocol device */ + lp->sdev->priv=NULL; + dev_close(lp->sdev); + unregister_netdev(lp->sdev); + kfree(lp->sdev->name); + kfree(lp->sdev); + lp->sdev=NULL; #endif - /* Update the statistics here. (not necessary in ARCnet) */ + /* Update the statistics here. (not necessary in ARCnet) */ - MOD_DEC_USE_COUNT; - return 0; -} + /* Decrease the use count */ + (*lp->openclose_device)(0); + return 0; +} /**************************************************************************** @@ -1501,103 +578,116 @@ arcnet_close(struct device *dev) static int arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev) { - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - int ioaddr=IOADDR; - - BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n", - ARCSTATUS,lp->intx); + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - if (lp->in_txhandler) - { - BUGMSG(D_NORMAL,"send_packet called while in txhandler!\n"); - lp->stats.tx_dropped++; - return 1; - } - - if (lp->intx>1) - { - BUGMSG(D_NORMAL,"send_packet called while intx!\n"); - lp->stats.tx_dropped++; - return 1; - } + BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n", + ARCSTATUS,lp->intx); - if (IF_TBUSY) - { - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - int tickssofar = jiffies - dev->trans_start; - /*int recbuf=lp->recbuf;*/ - int status=ARCSTATUS; + if (lp->in_txhandler) + { + BUGMSG(D_NORMAL,"send_packet called while in txhandler!\n"); + lp->stats.tx_dropped++; + return 1; + } - if (tickssofar < TX_TIMEOUT) - { - BUGMSG(D_DURING,"premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n", - status,tickssofar,lp->outgoing.skb, - lp->outgoing.numsegs, - lp->outgoing.segnum); - return 1; - } + if (lp->intx>1) + { + BUGMSG(D_NORMAL,"send_packet called while intx!\n"); + lp->stats.tx_dropped++; + return 1; + } - lp->intmask &= ~TXFREEflag; - SETMASK; + if (test_bit(0, (int *)&dev->tbusy)) + { + /* If we get here, some higher level has decided we are broken. + There should really be a "kick me" function call instead. */ + int tickssofar = jiffies - dev->trans_start; - if (status&TXFREEflag) /* transmit _DID_ finish */ - { - BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n", - status,tickssofar,lp->intmask,lp->lasttrans_dest); - lp->stats.tx_errors++; - } - else - { - BUGMSG(D_EXTRA,"tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n", - status,tickssofar,lp->intmask,lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; + int status=ARCSTATUS; - ACOMMAND(NOTXcmd); - } + if (tickssofar < TX_TIMEOUT) + { + BUGMSG(D_DURING,"premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n", + status,tickssofar,lp->outgoing.skb, + lp->outgoing.numsegs, + lp->outgoing.segnum); + return 1; + } - if (lp->outgoing.skb) - { - dev_kfree_skb(lp->outgoing.skb,FREE_WRITE); - lp->stats.tx_dropped++; - } - lp->outgoing.skb=NULL; + lp->intmask &= ~TXFREEflag; + SETMASK; - TBUSY=0; - lp->txready=0; - lp->sending=0; + if (status&TXFREEflag) /* transmit _DID_ finish */ + { + BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n", + status,tickssofar,lp->intmask,lp->lasttrans_dest); + lp->stats.tx_errors++; + } + else + { + BUGMSG(D_EXTRA,"tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n", + status,tickssofar,lp->intmask,lp->lasttrans_dest); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; - return 1; + ACOMMAND(NOTXcmd); } - if (lp->txready) /* transmit already in progress! */ + if (lp->outgoing.skb) { - BUGMSG(D_NORMAL,"trying to start new packet while busy! (status=%Xh)\n", - ARCSTATUS); - lp->intmask &= ~TXFREEflag; - SETMASK; - ACOMMAND(NOTXcmd); /* abort current send */ - arcnet_inthandler(dev); /* fake an interrupt */ - lp->stats.tx_errors++; - lp->stats.tx_fifo_errors++; - lp->txready=0; /* we definitely need this line! */ - - return 1; + dev_kfree_skb(lp->outgoing.skb,FREE_WRITE); + lp->stats.tx_dropped++; } + lp->outgoing.skb=NULL; - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - { - BUGMSG(D_NORMAL,"transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n", - ARCSTATUS,lp->intx,jiffies-dev->trans_start); - lp->stats.tx_errors++; - lp->stats.tx_fifo_errors++; - return -EBUSY; - } +#ifdef CONFIG_ARCNET_ETH + lp->edev->tbusy=0; +#endif +#ifdef CONFIG_ARCNET_1051 + lp->sdev->tbusy=0; +#endif + if (!test_and_clear_bit(0,(int *)&dev->tbusy)) + BUGMSG(D_EXTRA, "after timing out, tbusy was clear!\n"); + + lp->txready=0; + lp->sending=0; + + return 1; + } + + if (lp->txready) /* transmit already in progress! */ + { + BUGMSG(D_NORMAL,"trying to start new packet while busy! (status=%Xh)\n", + ARCSTATUS); + lp->intmask &= ~TXFREEflag; + SETMASK; + ACOMMAND(NOTXcmd); /* abort current send */ + (*lp->inthandler)(dev); /* fake an interrupt */ + lp->stats.tx_errors++; + lp->stats.tx_fifo_errors++; + lp->txready=0; /* we definitely need this line! */ + + return 1; + } + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (int *)&lp->adev->tbusy)) + { + BUGMSG(D_NORMAL,"transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n", + ARCSTATUS,lp->intx,jiffies-dev->trans_start); + lp->stats.tx_errors++; + lp->stats.tx_fifo_errors++; + return -EBUSY; + } +#ifdef CONFIG_ARCNET_1051 + lp->sdev->tbusy=1; +#endif +#ifdef CONFIG_ARCNET_ETH + lp->edev->tbusy=1; +#endif - return 0; + return 0; } @@ -1606,257 +696,170 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev) static int arcnetA_send_packet(struct sk_buff *skb, struct device *dev) { - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - int ioaddr=IOADDR,bad; - struct Outgoing *out=&(lp->outgoing); - - lp->intx++; - - bad=arcnet_send_packet_bad(skb,dev); - if (bad) - { - lp->intx--; - return bad; - } - - TBUSY=1; - - out->length = 1 < skb->len ? skb->len : 1; - out->hdr=(struct ClientData*)skb->data; - out->skb=skb; - - BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx"); - - out->hdr->sequence=(lp->sequence++); - - /* fits in one packet? */ - if (out->length-EXTRA_CLIENTDATA<=XMTU) - { - BUGMSG(D_DURING,"not splitting %d-byte packet. (split_flag=%d)\n", - out->length,out->hdr->split_flag); - if (out->hdr->split_flag) - BUGMSG(D_NORMAL,"short packet has split_flag set?! (split_flag=%d)\n", - out->hdr->split_flag); - out->numsegs=1; - out->segnum=1; - arcnetAS_prepare_tx(dev, + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + int bad,oldmask=0; + struct Outgoing *out=&(lp->outgoing); + + lp->intx++; + + oldmask |= lp->intmask; + lp->intmask=0; + SETMASK; + + bad=arcnet_send_packet_bad(skb,dev); + if (bad) + { + lp->intx--; + lp->intmask=oldmask; + SETMASK; + return bad; + } + + /* arcnet_send_packet_pad has already set tbusy - don't bother here. */ + + lp->intmask = oldmask & ~TXFREEflag; + SETMASK; + + out->length = 1 < skb->len ? skb->len : 1; + out->hdr=(struct ClientData*)skb->data; + out->skb=skb; + + BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx"); + + out->hdr->sequence=(lp->sequence++); + + /* fits in one packet? */ + if (out->length-EXTRA_CLIENTDATA<=XMTU) + { + BUGMSG(D_DURING,"not splitting %d-byte packet. (split_flag=%d)\n", + out->length,out->hdr->split_flag); + if (out->hdr->split_flag) + BUGMSG(D_NORMAL,"short packet has split_flag set?! (split_flag=%d)\n", + out->hdr->split_flag); + out->numsegs=1; + out->segnum=1; + (*lp->prepare_tx)(dev, ((char *)out->hdr)+EXTRA_CLIENTDATA, sizeof(struct ClientData)-EXTRA_CLIENTDATA, ((char *)skb->data)+sizeof(struct ClientData), out->length-sizeof(struct ClientData), - out->hdr->daddr,1); + out->hdr->daddr,1,0); - /* done right away */ - dev_kfree_skb(out->skb,FREE_WRITE); - out->skb=NULL; + /* done right away */ + lp->stats.tx_bytes += out->skb->len; + dev_kfree_skb(out->skb,FREE_WRITE); + out->skb=NULL; - if (arcnet_go_tx(dev,1)) - { - /* inform upper layers */ - TBUSY=0; - mark_bh(NET_BH); - } - } - else /* too big for one - split it */ + if (arcnet_go_tx(dev,1)) { - int maxsegsize=XMTU-4; - - out->data=(u_char *)skb->data - + sizeof(struct ClientData); - out->dataleft=out->length-sizeof(struct ClientData); - out->numsegs=(out->dataleft+maxsegsize-1)/maxsegsize; - out->segnum=0; - - BUGMSG(D_TX,"packet (%d bytes) split into %d fragments:\n", - out->length,out->numsegs); - - /* if a packet waiting, launch it */ - arcnet_go_tx(dev,1); - - if (!lp->txready) - { - /* prepare a packet, launch it and prepare - * another. - */ - arcnetA_continue_tx(dev); - if (arcnet_go_tx(dev,1)) - { - arcnetA_continue_tx(dev); - arcnet_go_tx(dev,1); - } - } - - /* if segnum==numsegs, the transmission is finished; - * free the skb right away. - */ - if (out->segnum==out->numsegs) - { - /* transmit completed */ - out->segnum++; - if (out->skb) - dev_kfree_skb(out->skb,FREE_WRITE); - out->skb=NULL; - } + /* inform upper layers */ + arcnet_tx_done(dev, lp); } + } + else /* too big for one - split it */ + { + int maxsegsize=XMTU-4; - dev->trans_start=jiffies; - lp->intx--; + out->data=(u_char *)skb->data + + sizeof(struct ClientData); + out->dataleft=out->length-sizeof(struct ClientData); + out->numsegs=(out->dataleft+maxsegsize-1)/maxsegsize; + out->segnum=0; - /* make sure we didn't ignore a TX IRQ while we were in here */ - lp->intmask |= TXFREEflag; - SETMASK; - - return 0; -} + BUGMSG(D_TX,"packet (%d bytes) split into %d fragments:\n", + out->length,out->numsegs); + /* if a packet waiting, launch it */ + arcnet_go_tx(dev,1); -/* After an RFC1201 split packet has been set up, this function calls - * arcnetAS_prepare_tx to load the next segment into the card. This function - * does NOT automatically call arcnet_go_tx. - */ -static void arcnetA_continue_tx(struct device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - int ioaddr=IOADDR,maxsegsize=XMTU-4; - struct Outgoing *out=&(lp->outgoing); - - BUGMSG(D_DURING,"continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n", - ARCSTATUS,lp->intx,lp->in_txhandler,lp->intmask); - - if (lp->txready) + if (!lp->txready) { - BUGMSG(D_NORMAL,"continue_tx: called with packet in buffer!\n"); - return; + /* prepare a packet, launch it and prepare + * another. + */ + arcnetA_continue_tx(dev); + if (arcnet_go_tx(dev,1)) + { + arcnetA_continue_tx(dev); + arcnet_go_tx(dev,1); + } } - if (out->segnum>=out->numsegs) + /* if segnum==numsegs, the transmission is finished; + * free the skb right away. + */ + + if (out->segnum==out->numsegs) { - BUGMSG(D_NORMAL,"continue_tx: building segment %d of %d!\n", - out->segnum+1,out->numsegs); + /* transmit completed */ + out->segnum++; + if (out->skb) + { + lp->stats.tx_bytes += skb->len; + dev_kfree_skb(out->skb,FREE_WRITE); + } + out->skb=NULL; } + } - if (!out->segnum) /* first packet */ - out->hdr->split_flag=((out->numsegs-2)<<1)+1; - else - out->hdr->split_flag=out->segnum<<1; + dev->trans_start=jiffies; + lp->intx--; - out->seglen=maxsegsize; - if (out->seglen>out->dataleft) out->seglen=out->dataleft; + /* make sure we didn't ignore a TX IRQ while we were in here */ + lp->intmask |= TXFREEflag; + SETMASK; - BUGMSG(D_TX,"building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n", - out->segnum+1,out->seglen,out->numsegs, - out->length,out->hdr->split_flag); - - arcnetAS_prepare_tx(dev,((char *)out->hdr)+EXTRA_CLIENTDATA, - sizeof(struct ClientData)-EXTRA_CLIENTDATA, - out->data,out->seglen,out->hdr->daddr,1); - - out->dataleft-=out->seglen; - out->data+=out->seglen; - out->segnum++; + return 0; } -/* Given an skb, copy a packet into the ARCnet buffers for later transmission - * by arcnet_go_tx. +/* After an RFC1201 split packet has been set up, this function calls + * arcnetAS_prepare_tx to load the next segment into the card. This function + * does NOT automatically call arcnet_go_tx. */ -static void -arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA) +void arcnetA_continue_tx(struct device *dev) { - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - struct ClientData *arcsoft; - union ArcPacket *arcpacket = - (union ArcPacket *)phys_to_virt(dev->mem_start+512*(lp->txbuf^1)); - int offset; - -#ifdef SLOW_XMIT_COPY - char *iptr,*iend,*optr; -#endif - - lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */ - - length+=hdrlen; - - BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n", - hdr,length,data); - -#ifndef SLOW_XMIT_COPY - /* clean out the page to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset_io(dev->mem_start+lp->txbuf*512,0x42,512); -#endif - - arcpacket->hardheader.destination=daddr; - - /* load packet into shared memory */ - if (length<=MTU) /* Normal (256-byte) Packet */ - { - arcpacket->hardheader.offset1=offset=256-length; - arcsoft=(struct ClientData *) - (&arcpacket->raw[offset]); - } - else if (length>=MinTU) /* Extended (512-byte) Packet */ - { - arcpacket->hardheader.offset1=0; - arcpacket->hardheader.offset2=offset=512-length; - - arcsoft=(struct ClientData *) - (&arcpacket->raw[offset]); - } - else if (exceptA) /* RFC1201 Exception Packet */ - { - arcpacket->hardheader.offset1=0; - arcpacket->hardheader.offset2=offset=512-length-4; - arcsoft=(struct ClientData *) - (&arcpacket->raw[offset+4]); - - /* exception-specific stuff - these four bytes - * make the packet long enough to fit in a 512-byte - * frame. - */ - arcpacket->raw[offset+0]=hdr[0]; - arcpacket->raw[offset+1]=0xFF; /* FF flag */ - arcpacket->raw[offset+2]=0xFF; /* FF padding */ - arcpacket->raw[offset+3]=0xFF; /* FF padding */ - } - else /* "other" Exception packet */ - { - /* RFC1051 - set 4 trailing bytes to 0 */ - memset(&arcpacket->raw[508],0,4); - - /* now round up to MinTU */ - arcpacket->hardheader.offset1=0; - arcpacket->hardheader.offset2=offset=512-MinTU; - arcsoft=(struct ClientData *)(&arcpacket->raw[offset]); - } - - - /* copy the packet into ARCnet shmem - * - the first bytes of ClientData header are skipped - */ - memcpy((u_char*)arcsoft, - (u_char*)hdr,hdrlen); -#ifdef SLOW_XMIT_COPY - for (iptr=data,iend=iptr+length-hdrlen,optr=(char *)arcsoft+hdrlen; - iptr<iend; iptr++,optr++) - { - *optr=*iptr; - /*udelay(5);*/ - } -#else - memcpy((u_char*)arcsoft+hdrlen, - data,length-hdrlen); -#endif - - BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n", - daddr,length); - - BUGLVL(D_TX) arcnet_dump_packet(dev,arcpacket->raw,length>MTU,"tx"); - lp->lastload_dest=daddr; - lp->txready=lp->txbuf; /* packet is ready for sending */ + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + int maxsegsize=XMTU-4; + struct Outgoing *out=&(lp->outgoing); + + BUGMSG(D_DURING,"continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n", + ARCSTATUS,lp->intx,lp->in_txhandler,lp->intmask); + + if (lp->txready) + { + BUGMSG(D_NORMAL,"continue_tx: called with packet in buffer!\n"); + return; + } + + if (out->segnum>=out->numsegs) + { + BUGMSG(D_NORMAL,"continue_tx: building segment %d of %d!\n", + out->segnum+1,out->numsegs); + } + + if (!out->segnum) /* first packet */ + out->hdr->split_flag=((out->numsegs-2)<<1)+1; + else + out->hdr->split_flag=out->segnum<<1; + + out->seglen=maxsegsize; + if (out->seglen>out->dataleft) out->seglen=out->dataleft; + + BUGMSG(D_TX,"building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n", + out->segnum+1,out->seglen,out->numsegs, + out->length,out->hdr->split_flag); + + (*lp->prepare_tx)(dev,((char *)out->hdr)+EXTRA_CLIENTDATA, + sizeof(struct ClientData)-EXTRA_CLIENTDATA, + out->data,out->seglen,out->hdr->daddr,1,0); + + out->dataleft-=out->seglen; + out->data+=out->seglen; + out->segnum++; } + /* Actually start transmitting a packet that was placed in the card's * buffer by arcnetAS_prepare_tx. Returns 1 if a Tx is really started. * @@ -1867,11 +870,9 @@ arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen, * to the card; TXFREEflag is always OR'ed into the memory variable either * way. */ -static int -arcnet_go_tx(struct device *dev,int enable_irq) +int arcnet_go_tx(struct device *dev,int enable_irq) { struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - int ioaddr=IOADDR; BUGMSG(D_DURING,"go_tx: status=%Xh, intmask=%Xh, txready=%d, sending=%d\n", ARCSTATUS,lp->intmask,lp->txready,lp->sending); @@ -1912,273 +913,80 @@ arcnet_go_tx(struct device *dev,int enable_irq) /* The typical workload of the driver: Handle the network interface - * interrupts. This doesn't do much right now except call arcnet_inthandler, - * which takes different parameters but may be called from other places - * as well. + * interrupts. Establish which device needs attention, and call the correct + * chipset interrupt handler. */ -static void +void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs) { struct device *dev = (struct device *)(irq2dev_map[irq]); - int ioaddr; + struct arcnet_local *lp; if (dev==NULL) - { - BUGLVL(D_DURING) - printk(KERN_DEBUG "arcnet: irq %d for unknown device.\n", irq); - return; - } + { + BUGLVL(D_DURING) + printk(KERN_DEBUG "arcnet: irq %d for unknown device.\n", irq); + return; + } BUGMSG(D_DURING,"in arcnet_interrupt\n"); + lp=(struct arcnet_local *)dev->priv; + /* RESET flag was enabled - if !dev->start, we must clear it right * away (but nothing else) since inthandler() is never called. */ - ioaddr=IOADDR; /* can't do this before checking dev!=NULL */ + if (!dev->start) - { - if (ARCSTATUS & RESETflag) - ACOMMAND(CFLAGScmd|RESETclear); - return; - } + { + if (ARCSTATUS & RESETflag) + ACOMMAND(CFLAGScmd|RESETclear); + return; + } + + + if (test_and_set_bit(0, (int *)&dev->interrupt)) + { + BUGMSG(D_NORMAL,"DRIVER PROBLEM! Nested arcnet interrupts!\n"); + return; /* don't even try. */ + } +#ifdef CONFIG_ARCNET_1051 + lp->sdev->interrupt=1; +#endif +#ifdef CONFIG_ARCNET_ETH + lp->edev->interrupt=1; +#endif /* Call the "real" interrupt handler. */ - arcnet_inthandler(dev); -} - - -/* The actual interrupt handler routine - handle various IRQ's generated - * by the card. - */ -static void -arcnet_inthandler(struct device *dev) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - int ioaddr=IOADDR, status, boguscount = 3, didsomething; - - if (IF_INTERRUPT) - { - BUGMSG(D_NORMAL,"DRIVER PROBLEM! Nested arcnet interrupts!\n"); - return; /* don't even try. */ - } - - AINTMASK(0); - INTERRUPT = 1; - - BUGMSG(D_DURING,"in arcnet_inthandler (status=%Xh, intmask=%Xh)\n", - ARCSTATUS,lp->intmask); - - do - { - status = ARCSTATUS; - didsomething=0; - - - /* RESET flag was enabled - card is resetting and if RX - * is disabled, it's NOT because we just got a packet. - */ - if (status & RESETflag) - { - BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n", - status); - arcnet_reset(dev,0); - - /* all other flag values are just garbage */ - break; - } - + (*lp->inthandler)(dev); - /* RX is inhibited - we must have received something. */ - if (status & lp->intmask & NORXflag) - { - int recbuf=lp->recbuf=!lp->recbuf; - - BUGMSG(D_DURING,"receive irq (status=%Xh)\n", - status); - - /* enable receive of our next packet */ - EnableReceiver(); - - /* Got a packet. */ - arcnet_rx(dev,!recbuf); - didsomething++; - } - - /* it can only be an xmit-done irq if we're xmitting :) */ - /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/ - if (status & lp->intmask & TXFREEflag) - { - struct Outgoing *out=&(lp->outgoing); - int was_sending=lp->sending; - - lp->intmask &= ~TXFREEflag; - - lp->in_txhandler++; - if (was_sending) lp->sending--; - - BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n", - status,out->numsegs,out->segnum,out->skb); - - if (was_sending && !(status&TXACKflag)) - { - if (lp->lasttrans_dest != 0) - { - BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n", - status,lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_carrier_errors++; - } - else - { - BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n", - status, - lp->lasttrans_dest); - } - } - - /* send packet if there is one */ - arcnet_go_tx(dev,0); - didsomething++; - - if (lp->intx) - { - BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n", - ARCSTATUS,lp->intx); - lp->in_txhandler--; - continue; - } - - if (!lp->outgoing.skb) - { - BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n"); - - /* inform upper layers */ - if (!lp->txready && IF_TBUSY) - { - TBUSY=0; - mark_bh(NET_BH); - } - lp->in_txhandler--; - continue; - } - - /* if more than one segment, and not all segments - * are done, then continue xmit. - */ - if (out->segnum<out->numsegs) - arcnetA_continue_tx(dev); - arcnet_go_tx(dev,0); - - /* if segnum==numsegs, the transmission is finished; - * free the skb. - */ - if (out->segnum>=out->numsegs) - { - /* transmit completed */ - out->segnum++; - if (out->skb) - dev_kfree_skb(out->skb,FREE_WRITE); - out->skb=NULL; - - /* inform upper layers */ - if (!lp->txready && IF_TBUSY) - { - TBUSY=0; - mark_bh(NET_BH); - } - } - didsomething++; - - lp->in_txhandler--; - } - else if (lp->txready && !lp->sending && !lp->intx) - { - BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n", - status); - arcnet_go_tx(dev,0); - didsomething++; - } - -#ifdef DETECT_RECONFIGS - if (status & (lp->intmask) & RECONflag) - { - ACOMMAND(CFLAGScmd|CONFIGclear); - lp->stats.tx_carrier_errors++; - - #ifdef SHOW_RECONFIGS - BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n", - status); - #endif /* SHOW_RECONFIGS */ - - #ifdef RECON_THRESHOLD - /* is the RECON info empty or old? */ - if (!lp->first_recon || !lp->last_recon || - jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n"); - lp->first_recon=lp->last_recon=jiffies; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"recon: clearing counters.\n"); - } - else /* add to current RECON counter */ - { - lp->last_recon=jiffies; - lp->num_recons++; - - BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n", - lp->num_recons, - (lp->last_recon-lp->first_recon)/HZ, - lp->network_down); - - /* if network is marked up; - * and first_recon and last_recon are 60+ sec - * apart; - * and the average no. of recons counted is - * > RECON_THRESHOLD/min; - * then print a warning message. - */ - if (!lp->network_down - && (lp->last_recon-lp->first_recon)<=HZ*60 - && lp->num_recons >= RECON_THRESHOLD) - { - lp->network_down=1; - BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n"); - } - else if (!lp->network_down - && lp->last_recon-lp->first_recon > HZ*60) - { - /* reset counters if we've gone for - * over a minute. - */ - lp->first_recon=lp->last_recon; - lp->num_recons=1; - } - } - #endif - } - #ifdef RECON_THRESHOLD - else if (lp->network_down && jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"cabling restored?\n"); - lp->first_recon=lp->last_recon=0; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"not recon: clearing counters anyway.\n"); - } - #endif -#endif /* DETECT_RECONFIGS */ - } while (--boguscount && didsomething); +#ifdef CONFIG_ARCNET_ETH + lp->edev->interrupt=0; +#endif +#ifdef CONFIG_ARCNET_1051 + lp->sdev->interrupt=0; +#endif + if (!test_and_clear_bit(0, (int *)&dev->interrupt)) + BUGMSG(D_NORMAL, "Someone cleared our dev->interrupt flag!\n"); - BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n", - ARCSTATUS,boguscount); - BUGMSG(D_DURING,"\n"); +} - SETMASK; /* put back interrupt mask */ +void arcnet_tx_done(struct device *dev, struct arcnet_local *lp) +{ + if (dev->tbusy) + { +#ifdef CONFIG_ARCNET_ETH + lp->edev->tbusy=0; +#endif +#ifdef CONFIG_ARCNET_1051 + lp->sdev->tbusy=0; +#endif + if (!test_and_clear_bit(0, (int *)&dev->tbusy)) + BUGMSG(D_NORMAL, "In arcnet_tx_done: Someone cleared our dev->tbusy" + " flag!\n"); - INTERRUPT=0; + mark_bh(NET_BH); + } } @@ -2188,377 +996,336 @@ arcnet_inthandler(struct device *dev) * * ****************************************************************************/ - -/* A packet has arrived; grab it from the buffers and possibly unsplit it. +/* * This is a generic packet receiver that calls arcnet??_rx depending on the * protocol ID found. */ -static void -arcnet_rx(struct device *dev,int recbuf) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - int ioaddr=IOADDR; - union ArcPacket *arcpacket= - (union ArcPacket *)phys_to_virt(dev->mem_start+recbuf*512); - u_char *arcsoft; - short length,offset; - u_char daddr,saddr; - - lp->stats.rx_packets++; - - saddr=arcpacket->hardheader.source; - daddr=arcpacket->hardheader.destination; - - /* if source is 0, it's a "used" packet! */ - if (saddr==0) - { - BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n", - ARCSTATUS); - lp->stats.rx_errors++; - return; - } - arcpacket->hardheader.source=0; - if (arcpacket->hardheader.offset1) /* Normal Packet */ - { - offset=arcpacket->hardheader.offset1; - arcsoft=&arcpacket->raw[offset]; - length=256-offset; - } - else /* ExtendedPacket or ExceptionPacket */ - { - offset=arcpacket->hardheader.offset2; - arcsoft=&arcpacket->raw[offset]; - - length=512-offset; - } - - BUGMSG(D_DURING,"received packet from %02Xh to %02Xh (%d bytes)\n", - saddr,daddr,length); - - /* call the right receiver for the protocol */ - switch (arcsoft[0]) - { - case ARC_P_IP: - case ARC_P_ARP: - case ARC_P_RARP: - case ARC_P_IPX: - case ARC_P_NOVELL_EC: - arcnetA_rx(lp->adev,arcsoft,length,saddr,daddr); - break; +void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr) +{ + struct device *dev=lp->adev; + + BUGMSG(D_DURING,"received packet from %02Xh to %02Xh (%d bytes)\n", + saddr,daddr,length); + + /* call the right receiver for the protocol */ + switch (arcsoft[0]) + { + case ARC_P_IP: + case ARC_P_ARP: + case ARC_P_RARP: + case ARC_P_IPX: + case ARC_P_NOVELL_EC: + arcnetA_rx(lp->adev,arcsoft,length,saddr,daddr); + break; #ifdef CONFIG_ARCNET_ETH - case ARC_P_ETHER: - arcnetE_rx(lp->edev,arcsoft,length,saddr,daddr); - break; + case ARC_P_ETHER: + arcnetE_rx(lp->edev,arcsoft,length,saddr,daddr); + break; #endif #ifdef CONFIG_ARCNET_1051 - case ARC_P_IP_RFC1051: - case ARC_P_ARP_RFC1051: - arcnetS_rx(lp->sdev,arcsoft,length,saddr,daddr); - break; -#endif - case ARC_P_DATAPOINT_BOOT: - case ARC_P_DATAPOINT_MOUNT: - break; - case ARC_P_POWERLAN_BEACON: - case ARC_P_POWERLAN_BEACON2: - break; - case ARC_P_LANSOFT: /* don't understand. fall through. */ - default: - BUGMSG(D_EXTRA,"received unknown protocol %d (%Xh) from station %d.\n", - arcsoft[0],arcsoft[0],saddr); - lp->stats.rx_errors++; - lp->stats.rx_crc_errors++; - break; - } - - BUGLVL(D_RX) arcnet_dump_packet(dev,arcpacket->raw,length>240,"rx"); - - -#ifndef SLOW_XMIT_COPY - /* clean out the page to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset((void *)arcpacket->raw,0x42,512); + case ARC_P_IP_RFC1051: + case ARC_P_ARP_RFC1051: + arcnetS_rx(lp->sdev,arcsoft,length,saddr,daddr); + break; #endif + case ARC_P_DATAPOINT_BOOT: + case ARC_P_DATAPOINT_MOUNT: + break; + case ARC_P_POWERLAN_BEACON: + case ARC_P_POWERLAN_BEACON2: + break; + case ARC_P_LANSOFT: /* don't understand. fall through. */ + default: + BUGMSG(D_EXTRA,"received unknown protocol %d (%Xh) from station %d.\n", + arcsoft[0],arcsoft[0],saddr); + lp->stats.rx_errors++; + lp->stats.rx_crc_errors++; + break; + } + + /* If any worth-while packets have been received, a mark_bh(NET_BH) + * has been done by netif_rx and Linux will handle them after we + * return. + */ - /* If any worth-while packets have been received, a mark_bh(NET_BH) - * has been done by netif_rx and Linux will handle them after we - * return. - */ } + /* Packet receiver for "standard" RFC1201-style packets */ static void arcnetA_rx(struct device *dev,u_char *buf, - int length,u_char saddr, u_char daddr) + int length, u_char saddr, u_char daddr) { - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - struct sk_buff *skb; - struct ClientData *arcsoft,*soft; - - BUGMSG(D_DURING,"it's an RFC1201 packet (length=%d)\n", - length); - - /* compensate for EXTRA_CLIENTDATA (which isn't actually in the - * packet) - */ - arcsoft=(struct ClientData *)(buf-EXTRA_CLIENTDATA); - length+=EXTRA_CLIENTDATA; - - if (arcsoft->split_flag==0xFF) /* Exception Packet */ - { - BUGMSG(D_DURING,"compensating for exception packet\n"); - - /* skip over 4-byte junkola */ - arcsoft=(struct ClientData *) - ((u_char *)arcsoft + 4); - length-=4; - } - - if (!arcsoft->split_flag) /* not split */ - { - struct Incoming *in=&lp->incoming[saddr]; - - BUGMSG(D_RX,"incoming is not split (splitflag=%d)\n", - arcsoft->split_flag); - - if (in->skb) /* already assembling one! */ - { - BUGMSG(D_EXTRA,"aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n", - in->sequence,arcsoft->split_flag, - arcsoft->sequence); - kfree_skb(in->skb,FREE_WRITE); - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - in->skb=NULL; - } - - in->sequence=arcsoft->sequence; - - skb = alloc_skb(length, GFP_ATOMIC); - if (skb == NULL) { - BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n"); - lp->stats.rx_dropped++; - return; - } - soft=(struct ClientData *)skb->data; - - skb->len = length; - skb->dev = dev; - - memcpy((u_char *)soft+EXTRA_CLIENTDATA, - (u_char *)arcsoft+EXTRA_CLIENTDATA, - length-EXTRA_CLIENTDATA); - soft->daddr=daddr; - soft->saddr=saddr; - - /* ARP packets have problems when sent from DOS. - * source address is always 0 on some systems! So we take - * the hardware source addr (which is impossible to fumble) - * and insert it ourselves. - */ - if (soft->protocol_id == ARC_P_ARP) - { - struct arphdr *arp=(struct arphdr *) - ((char *)soft+sizeof(struct ClientData)); - - /* make sure addresses are the right length */ - if (arp->ar_hln==1 && arp->ar_pln==4) - { - char *cptr=(char *)(arp)+sizeof(struct arphdr); - - if (!*cptr) /* is saddr = 00? */ - { - BUGMSG(D_EXTRA,"ARP source address was 00h, set to %02Xh.\n", - saddr); - lp->stats.rx_crc_errors++; - *cptr=saddr; - } - else - { - BUGMSG(D_DURING,"ARP source address (%Xh) is fine.\n", - *cptr); - } - } - else - { - BUGMSG(D_NORMAL,"funny-shaped ARP packet. (%Xh, %Xh)\n", - arp->ar_hln,arp->ar_pln); - lp->stats.rx_errors++; - lp->stats.rx_crc_errors++; - } - } - - BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx"); - - skb->protocol=arcnetA_type_trans(skb,dev); - - netif_rx(skb); - } - else /* split packet */ - { - /* NOTE: MSDOS ARP packet correction should only need to - * apply to unsplit packets, since ARP packets are so short. - * - * My interpretation of the RFC1201 (ARCnet) document is that - * if a packet is received out of order, the entire assembly - * process should be aborted. - * - * The RFC also mentions "it is possible for successfully - * received packets to be retransmitted." As of 0.40 all - * previously received packets are allowed, not just the - * most recent one. - * - * We allow multiple assembly processes, one for each - * ARCnet card possible on the network. Seems rather like - * a waste of memory. Necessary? - */ - - struct Incoming *in=&lp->incoming[saddr]; - - BUGMSG(D_RX,"packet is split (splitflag=%d, seq=%d)\n", - arcsoft->split_flag,in->sequence); - - if (in->skb && in->sequence!=arcsoft->sequence) + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + struct sk_buff *skb; + struct ClientData *arcsoft,*soft; + + BUGMSG(D_DURING,"it's an RFC1201 packet (length=%d)\n", + length); + + /* compensate for EXTRA_CLIENTDATA (which isn't actually in the + * packet) + */ + arcsoft=(struct ClientData *)(buf-EXTRA_CLIENTDATA); + length+=EXTRA_CLIENTDATA; + + if (arcsoft->split_flag==0xFF) /* Exception Packet */ + { + BUGMSG(D_DURING,"compensating for exception packet\n"); + + /* skip over 4-byte junkola */ + arcsoft=(struct ClientData *) + ((u_char *)arcsoft + 4); + length-=4; + } + + if (!arcsoft->split_flag) /* not split */ + { + struct Incoming *in=&lp->incoming[saddr]; + + BUGMSG(D_RX,"incoming is not split (splitflag=%d)\n", + arcsoft->split_flag); + + if (in->skb) /* already assembling one! */ + { + BUGMSG(D_EXTRA,"aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n", + in->sequence,arcsoft->split_flag, + arcsoft->sequence); + lp->aborted_seq=arcsoft->sequence; + kfree_skb(in->skb,FREE_WRITE); + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + in->skb=NULL; + } + + in->sequence=arcsoft->sequence; + + skb = alloc_skb(length, GFP_ATOMIC); + if (skb == NULL) { + BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n"); + lp->stats.rx_dropped++; + return; + } + soft=(struct ClientData *)skb->data; + + skb_put(skb,length); + skb->dev = dev; + + memcpy((u_char *)soft+EXTRA_CLIENTDATA, + (u_char *)arcsoft+EXTRA_CLIENTDATA, + length-EXTRA_CLIENTDATA); + soft->daddr=daddr; + soft->saddr=saddr; + + /* ARP packets have problems when sent from DOS. + * source address is always 0 on some systems! So we take + * the hardware source addr (which is impossible to fumble) + * and insert it ourselves. + */ + if (soft->protocol_id == ARC_P_ARP) + { + struct arphdr *arp=(struct arphdr *) + ((char *)soft+sizeof(struct ClientData)); + + /* make sure addresses are the right length */ + if (arp->ar_hln==1 && arp->ar_pln==4) + { + char *cptr=(char *)(arp)+sizeof(struct arphdr); + + if (!*cptr) /* is saddr = 00? */ { - BUGMSG(D_EXTRA,"wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n", - saddr,in->sequence,arcsoft->sequence, - arcsoft->split_flag); - kfree_skb(in->skb,FREE_WRITE); - in->skb=NULL; - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - in->lastpacket=in->numpackets=0; - } - - if (arcsoft->split_flag & 1) /* first packet in split */ - { - BUGMSG(D_RX,"brand new splitpacket (splitflag=%d)\n", - arcsoft->split_flag); - if (in->skb) /* already assembling one! */ - { - BUGMSG(D_EXTRA,"aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n", - in->sequence,arcsoft->split_flag, - arcsoft->sequence); - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - kfree_skb(in->skb,FREE_WRITE); - } - - in->sequence=arcsoft->sequence; - in->numpackets=((unsigned)arcsoft->split_flag>>1)+2; - in->lastpacket=1; - - if (in->numpackets>16) - { - BUGMSG(D_EXTRA,"incoming packet more than 16 segments; dropping. (splitflag=%d)\n", - arcsoft->split_flag); - lp->stats.rx_errors++; - lp->stats.rx_length_errors++; - return; - } - - in->skb=skb=alloc_skb(508*in->numpackets - + sizeof(struct ClientData), - GFP_ATOMIC); - if (skb == NULL) { - BUGMSG(D_NORMAL,"(split) memory squeeze, dropping packet.\n"); - lp->stats.rx_dropped++; - return; - } - - soft=(struct ClientData *)skb->data; - - skb->len=sizeof(struct ClientData); - skb->dev=dev; - - memcpy((u_char *)soft+EXTRA_CLIENTDATA, - (u_char *)arcsoft+EXTRA_CLIENTDATA, - sizeof(struct ClientData)-EXTRA_CLIENTDATA); - soft->split_flag=0; /* final packet won't be split */ - } - else /* not first packet */ - { - int packetnum=((unsigned)arcsoft->split_flag>>1) + 1; - - /* if we're not assembling, there's no point - * trying to continue. - */ - if (!in->skb) - { - BUGMSG(D_EXTRA,"can't continue split without starting first! (splitflag=%d, seq=%d)\n", - arcsoft->split_flag,arcsoft->sequence); - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - return; - } - - in->lastpacket++; - if (packetnum!=in->lastpacket) /* not the right flag! */ - { - /* harmless duplicate? ignore. */ - if (packetnum<=in->lastpacket-1) - { - BUGMSG(D_EXTRA,"duplicate splitpacket ignored! (splitflag=%d)\n", - arcsoft->split_flag); - lp->stats.rx_errors++; - lp->stats.rx_frame_errors++; - return; - } - - /* "bad" duplicate, kill reassembly */ - BUGMSG(D_EXTRA,"out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n", - in->sequence,arcsoft->split_flag, - arcsoft->sequence); - kfree_skb(in->skb,FREE_WRITE); - in->skb=NULL; - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - in->lastpacket=in->numpackets=0; - return; - } - - soft=(struct ClientData *)in->skb->data; - } - - skb=in->skb; - - memcpy(skb->data+skb->len, - (u_char *)arcsoft+sizeof(struct ClientData), - length-sizeof(struct ClientData)); - - skb->len+=length-sizeof(struct ClientData); - - soft->daddr=daddr; - soft->saddr=saddr; - - /* are we done? */ - if (in->lastpacket == in->numpackets) - { - if (!skb || !in->skb) - { - BUGMSG(D_NORMAL,"?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n", - skb,in->skb); - } - else - { - in->skb=NULL; - in->lastpacket=in->numpackets=0; - - BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx"); - - skb->protocol=arcnetA_type_trans(skb,dev); - - netif_rx(skb); - } - } - } -} - + BUGMSG(D_EXTRA,"ARP source address was 00h, set to %02Xh.\n", + saddr); + lp->stats.rx_crc_errors++; + *cptr=saddr; + } + else + { + BUGMSG(D_DURING,"ARP source address (%Xh) is fine.\n", + *cptr); + } + } + else + { + BUGMSG(D_NORMAL,"funny-shaped ARP packet. (%Xh, %Xh)\n", + arp->ar_hln,arp->ar_pln); + lp->stats.rx_errors++; + lp->stats.rx_crc_errors++; + } + } + + BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx"); + + lp->stats.rx_bytes += skb->len; + skb->protocol=arcnetA_type_trans(skb,dev); + netif_rx(skb); + } + else /* split packet */ + { + /* NOTE: MSDOS ARP packet correction should only need to + * apply to unsplit packets, since ARP packets are so short. + * + * My interpretation of the RFC1201 (ARCnet) document is that + * if a packet is received out of order, the entire assembly + * process should be aborted. + * + * The RFC also mentions "it is possible for successfully + * received packets to be retransmitted." As of 0.40 all + * previously received packets are allowed, not just the + * most recent one. + * + * We allow multiple assembly processes, one for each + * ARCnet card possible on the network. Seems rather like + * a waste of memory. Necessary? + */ + + struct Incoming *in=&lp->incoming[saddr]; + + BUGMSG(D_RX,"packet is split (splitflag=%d, seq=%d)\n", + arcsoft->split_flag,in->sequence); + + if (in->skb && in->sequence!=arcsoft->sequence) + { + BUGMSG(D_EXTRA,"wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n", + saddr,in->sequence,arcsoft->sequence, + arcsoft->split_flag); + kfree_skb(in->skb,FREE_WRITE); + in->skb=NULL; + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + in->lastpacket=in->numpackets=0; + } + + if (arcsoft->split_flag & 1) /* first packet in split */ + { + BUGMSG(D_RX,"brand new splitpacket (splitflag=%d)\n", + arcsoft->split_flag); + if (in->skb) /* already assembling one! */ + { + BUGMSG(D_EXTRA,"aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n", + in->sequence,arcsoft->split_flag, + arcsoft->sequence); + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + kfree_skb(in->skb,FREE_WRITE); + } + + in->sequence=arcsoft->sequence; + in->numpackets=((unsigned)arcsoft->split_flag>>1)+2; + in->lastpacket=1; + + if (in->numpackets>16) + { + BUGMSG(D_EXTRA,"incoming packet more than 16 segments; dropping. (splitflag=%d)\n", + arcsoft->split_flag); + lp->stats.rx_errors++; + lp->stats.rx_length_errors++; + return; + } + + in->skb=skb=alloc_skb(508*in->numpackets + + sizeof(struct ClientData), + GFP_ATOMIC); + if (skb == NULL) { + BUGMSG(D_NORMAL,"(split) memory squeeze, dropping packet.\n"); + lp->stats.rx_dropped++; + return; + } + + soft=(struct ClientData *)skb->data; + + skb_put(skb,sizeof(struct ClientData)); + skb->dev=dev; + + memcpy((u_char *)soft+EXTRA_CLIENTDATA, + (u_char *)arcsoft+EXTRA_CLIENTDATA, + sizeof(struct ClientData)-EXTRA_CLIENTDATA); + soft->split_flag=0; /* final packet won't be split */ + } + else /* not first packet */ + { + int packetnum=((unsigned)arcsoft->split_flag>>1) + 1; + + /* if we're not assembling, there's no point + * trying to continue. + */ + if (!in->skb) + { + if (lp->aborted_seq != arcsoft->sequence) + { + BUGMSG(D_EXTRA,"can't continue split without starting first! (splitflag=%d, seq=%d, aborted=%d)\n", + arcsoft->split_flag,arcsoft->sequence, lp->aborted_seq); + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + } + return; + } + + in->lastpacket++; + if (packetnum!=in->lastpacket) /* not the right flag! */ + { + /* harmless duplicate? ignore. */ + if (packetnum<=in->lastpacket-1) + { + BUGMSG(D_EXTRA,"duplicate splitpacket ignored! (splitflag=%d)\n", + arcsoft->split_flag); + lp->stats.rx_errors++; + lp->stats.rx_frame_errors++; + return; + } + /* "bad" duplicate, kill reassembly */ + BUGMSG(D_EXTRA,"out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n", + in->sequence,arcsoft->split_flag, + arcsoft->sequence); + lp->aborted_seq=arcsoft->sequence; + kfree_skb(in->skb,FREE_WRITE); + in->skb=NULL; + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + in->lastpacket=in->numpackets=0; + return; + } + + soft=(struct ClientData *)in->skb->data; + } + + skb=in->skb; + + memcpy(skb->data+skb->len, + (u_char *)arcsoft+sizeof(struct ClientData), + length-sizeof(struct ClientData)); + skb_put(skb,length-sizeof(struct ClientData)); + + soft->daddr=daddr; + soft->saddr=saddr; + + /* are we done? */ + if (in->lastpacket == in->numpackets) + { + if (!skb || !in->skb) + { + BUGMSG(D_NORMAL,"?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n", + skb,in->skb); + } + else + { + in->skb=NULL; + in->lastpacket=in->numpackets=0; + + BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx"); + + lp->stats.rx_bytes += skb->len; + skb->protocol=arcnetA_type_trans(skb,dev); + netif_rx(skb); + } + } + } +} /**************************************************************************** @@ -2567,150 +1334,132 @@ arcnetA_rx(struct device *dev,u_char *buf, * * ****************************************************************************/ - /* Get the current statistics. This may be called with the card open or * closed. */ static struct net_device_stats *arcnet_get_stats(struct device *dev) { - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - return &lp->stats; + return &lp->stats; } -#if 0 /* standard ARCnet cards have no promiscuous mode */ -/* Set or clear the multicast filter for this adaptor. - * num_addrs == -1 Promiscuous mode, receive all packets - * num_addrs == 0 Normal mode, clear multicast list - * num_addrs > 0 Multicast mode, receive normal and MC packets, and do - * best-effort filtering. - */ -static void -set_multicast_list(struct device *dev) -{ - if (num_addrs) { - /* Enable promiscuous mode */ - } else - /* Disable promiscuous mode, use normal mode */ -} -#endif /* Create the ARCnet ClientData header for an arbitrary protocol layer * * saddr=NULL means use device source address (always will anyway) * daddr=NULL means leave destination address (eg unresolved arp) */ -int arcnetA_header(struct sk_buff *skb,struct device *dev, - unsigned short type,void *daddr,void *saddr,unsigned len) +static int arcnetA_header(struct sk_buff *skb,struct device *dev, + unsigned short type,void *daddr,void *saddr,unsigned len) { - struct ClientData *head = (struct ClientData *) - skb_push(skb,dev->hard_header_len); - struct arcnet_local *lp=(struct arcnet_local *)(dev->priv); - - BUGMSG(D_DURING,"create header from %d to %d; protocol %d (%Xh); size %u.\n", - saddr ? *(u_char*)saddr : -1, - daddr ? *(u_char*)daddr : -1, - type,type,len); - - /* set the protocol ID according to RFC1201 */ - switch(type) - { - case ETH_P_IP: - head->protocol_id=ARC_P_IP; - break; - case ETH_P_ARP: - head->protocol_id=ARC_P_ARP; - break; - case ETH_P_RARP: - head->protocol_id=ARC_P_RARP; - break; - case ETH_P_IPX: - case ETH_P_802_3: - case ETH_P_802_2: - head->protocol_id=ARC_P_IPX; - break; - case ETH_P_ATALK: - head->protocol_id=ARC_P_ATALK; - break; - default: - BUGMSG(D_NORMAL,"I don't understand protocol %d (%Xh)\n", - type,type); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - return 0; - } - - /* - * Set the source hardware address. - * - * This is pretty pointless for most purposes, but it can help - * in debugging. saddr is stored in the ClientData header and - * removed before sending the packet (since ARCnet does not allow - * us to change the source address in the actual packet sent) - */ - if(saddr) - head->saddr=((u_char*)saddr)[0]; - else - head->saddr=((u_char*)(dev->dev_addr))[0]; - - head->split_flag=0; /* split packets are done elsewhere */ - head->sequence=0; /* so are sequence numbers */ - - /* supposedly if daddr is NULL, we should ignore it... */ - if(daddr) - { - head->daddr=((u_char*)daddr)[0]; - return dev->hard_header_len; - } - else - head->daddr=0; /* better fill one in anyway */ - - return -dev->hard_header_len; + struct ClientData *head = (struct ClientData *) + skb_push(skb,dev->hard_header_len); + struct arcnet_local *lp=(struct arcnet_local *)(dev->priv); + + BUGMSG(D_DURING,"create header from %d to %d; protocol %d (%Xh); size %u.\n", + saddr ? *(u_char*)saddr : -1, + daddr ? *(u_char*)daddr : -1, + type,type,len); + + /* set the protocol ID according to RFC1201 */ + switch(type) + { + case ETH_P_IP: + head->protocol_id=ARC_P_IP; + break; + case ETH_P_ARP: + head->protocol_id=ARC_P_ARP; + break; + case ETH_P_RARP: + head->protocol_id=ARC_P_RARP; + break; + case ETH_P_IPX: + case ETH_P_802_3: + case ETH_P_802_2: + head->protocol_id=ARC_P_IPX; + break; + case ETH_P_ATALK: + head->protocol_id=ARC_P_ATALK; + break; + default: + BUGMSG(D_NORMAL,"I don't understand protocol %d (%Xh)\n", + type,type); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + return 0; + } + + /* + * Set the source hardware address. + * + * This is pretty pointless for most purposes, but it can help + * in debugging. saddr is stored in the ClientData header and + * removed before sending the packet (since ARCnet does not allow + * us to change the source address in the actual packet sent) + */ + if(saddr) + head->saddr=((u_char*)saddr)[0]; + else + head->saddr=((u_char*)(dev->dev_addr))[0]; + + head->split_flag=0; /* split packets are done elsewhere */ + head->sequence=0; /* so are sequence numbers */ + + /* supposedly if daddr is NULL, we should ignore it... */ + if(daddr) + { + head->daddr=((u_char*)daddr)[0]; + return dev->hard_header_len; + } + else + head->daddr=0; /* better fill one in anyway */ + + return -dev->hard_header_len; } - /* Rebuild the ARCnet ClientData header. This is called after an ARP * (or in future other address resolution) has completed on this * sk_buff. We now let ARP fill in the other fields. */ -int arcnetA_rebuild_header(struct sk_buff *skb) +static int arcnetA_rebuild_header(struct sk_buff *skb) { - struct ClientData *head = (struct ClientData *)skb->data; - struct device *dev=skb->dev; - struct arcnet_local *lp=(struct arcnet_local *)(dev->priv); - int status; - - /* - * Only ARP and IP are currently supported - * - * FIXME: Anyone want to spec IPv6 over ARCnet ? - */ - - if(head->protocol_id != ARC_P_IP) - { - BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n", - head->protocol_id,head->protocol_id); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - head->daddr=0; - /*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/ - return 0; - } - - /* - * Try to get ARP to resolve the header. - */ + struct ClientData *head = (struct ClientData *)skb->data; + struct device *dev=skb->dev; + struct arcnet_local *lp=(struct arcnet_local *)(dev->priv); + int status; + + /* + * Only ARP and IP are currently supported + * + * FIXME: Anyone want to spec IPv6 over ARCnet ? + */ + + if(head->protocol_id != ARC_P_IP) + { + BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n", + head->protocol_id,head->protocol_id); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + head->daddr=0; + /*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/ + return 0; + } + + /* + * Try to get ARP to resolve the header. + */ #ifdef CONFIG_INET - BUGMSG(D_DURING,"rebuild header from %d to %d; protocol %Xh\n", - head->saddr,head->daddr,head->protocol_id); - status=arp_find(&(head->daddr),skb)? 1 : 0; - BUGMSG(D_DURING," rebuilt: from %d to %d; protocol %Xh\n", - head->saddr,head->daddr,head->protocol_id); - return status; + BUGMSG(D_DURING,"rebuild header from %d to %d; protocol %Xh\n", + head->saddr,head->daddr,head->protocol_id); + status=arp_find(&(head->daddr),skb)? 1 : 0; + BUGMSG(D_DURING," rebuilt: from %d to %d; protocol %Xh\n", + head->saddr,head->daddr,head->protocol_id); + return status; #else - return 0; + return 0; #endif } @@ -2719,42 +1468,42 @@ int arcnetA_rebuild_header(struct sk_buff *skb) * * With ARCnet we have to convert everything to Ethernet-style stuff. */ -unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev) +static unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev) { - struct ClientData *head; - struct arcnet_local *lp=(struct arcnet_local *) (dev->priv); - - /* Pull off the arcnet header. */ - skb->mac.raw=skb->data; - skb_pull(skb,dev->hard_header_len); - head=(struct ClientData *)skb->mac.raw; - - if (head->daddr==0) - skb->pkt_type=PACKET_BROADCAST; - else if (dev->flags&IFF_PROMISC) - { - /* if we're not sending to ourselves :) */ - if (head->daddr != dev->dev_addr[0]) - skb->pkt_type=PACKET_OTHERHOST; - } - - /* now return the protocol number */ - switch (head->protocol_id) - { - case ARC_P_IP: return htons(ETH_P_IP); - case ARC_P_ARP: return htons(ETH_P_ARP); - case ARC_P_RARP: return htons(ETH_P_RARP); - - case ARC_P_IPX: - case ARC_P_NOVELL_EC: - return htons(ETH_P_802_3); - default: - lp->stats.rx_errors++; - lp->stats.rx_crc_errors++; - return 0; - } - - return htons(ETH_P_IP); + struct ClientData *head; + struct arcnet_local *lp=(struct arcnet_local *) (dev->priv); + + /* Pull off the arcnet header. */ + skb->mac.raw=skb->data; + skb_pull(skb,dev->hard_header_len); + head=(struct ClientData *)skb->mac.raw; + + if (head->daddr==0) + skb->pkt_type=PACKET_BROADCAST; + else if (dev->flags&IFF_PROMISC) + { + /* if we're not sending to ourselves :) */ + if (head->daddr != dev->dev_addr[0]) + skb->pkt_type=PACKET_OTHERHOST; + } + + /* now return the protocol number */ + switch (head->protocol_id) + { + case ARC_P_IP: return htons(ETH_P_IP); + case ARC_P_ARP: return htons(ETH_P_ARP); + case ARC_P_RARP: return htons(ETH_P_RARP); + + case ARC_P_IPX: + case ARC_P_NOVELL_EC: + return htons(ETH_P_802_3); + default: + lp->stats.rx_errors++; + lp->stats.rx_crc_errors++; + return 0; + } + + return htons(ETH_P_IP); } @@ -2769,19 +1518,17 @@ unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev) */ static int arcnetE_init(struct device *dev) { - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - ether_setup(dev); /* we're emulating ether here, not ARCnet */ - dev->dev_addr[0]=0; - dev->dev_addr[5]=lp->stationid; - dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len-1; - dev->open=arcnetE_open_close; - dev->stop=arcnetE_open_close; - dev->hard_start_xmit=arcnetE_send_packet; + ether_setup(dev); /* we're emulating ether here, not ARCnet */ + dev->dev_addr[0]=0; + dev->dev_addr[5]=lp->stationid; + dev->mtu=512-sizeof(struct archdr)-dev->hard_header_len-1; + dev->open=arcnetE_open_close; + dev->stop=arcnetE_open_close; + dev->hard_start_xmit=arcnetE_send_packet; - BUGMSG(D_NORMAL,"ARCnet Ethernet-Encap protocol initialized.\n"); - - return 0; + return 0; } @@ -2790,7 +1537,7 @@ static int arcnetE_init(struct device *dev) */ static int arcnetE_open_close(struct device *dev) { - return 0; + return 0; } @@ -2799,96 +1546,75 @@ static int arcnetE_open_close(struct device *dev) static int arcnetE_send_packet(struct sk_buff *skb, struct device *dev) { - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - int ioaddr=IOADDR,bad; - union ArcPacket *arcpacket = - (union ArcPacket *)phys_to_virt(dev->mem_start+512*(lp->txbuf^1)); - u_char *arcsoft,daddr; - short offset,length=skb->len+1; - - lp->intx++; - - bad=arcnet_send_packet_bad(skb,dev); - if (bad) - { - lp->intx--; - return bad; - } - - TBUSY=1; - - if (length>XMTU) - { - BUGMSG(D_NORMAL,"MTU must be <= 493 for ethernet encap (length=%d).\n", - length); - BUGMSG(D_NORMAL,"transmit aborted.\n"); - - dev_kfree_skb(skb,FREE_WRITE); - lp->intx--; - return 0; - } - - BUGMSG(D_DURING,"starting tx sequence...\n"); - - lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate btw 2 & 3 */ - -#ifndef SLOW_XMIT_COPY - /* clean out the page to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset_io(dev->mem_start+lp->txbuf*512,0x42,512); -#endif - - /* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */ - if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF) - daddr=arcpacket->hardheader.destination=0; - else - daddr=arcpacket->hardheader.destination= - ((struct ethhdr*)(skb->data))->h_dest[5]; - - /* load packet into shared memory */ - offset=512-length; - if (length>MTU) /* long/exception packet */ - { - if (length<MinTU) offset-=3; - arcpacket->hardheader.offset1=0; - arcpacket->hardheader.offset2=offset; - } - else /* short packet */ - { - arcpacket->hardheader.offset1=(offset-=256); - } - - BUGMSG(D_DURING," length=%Xh, offset=%Xh, offset1=%Xh, offset2=%Xh\n", - length,offset,arcpacket->hardheader.offset1, - arcpacket->hardheader.offset2); - - arcsoft=&arcpacket->raw[offset]; - arcsoft[0]=ARC_P_ETHER; - arcsoft++; - - /* copy the packet into ARCnet shmem - * - the first bytes of ClientData header are skipped - */ - BUGMSG(D_DURING,"ready to memcpy\n"); - - memcpy(arcsoft,skb->data,skb->len); - - BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n", - daddr,length); - - BUGLVL(D_TX) arcnet_dump_packet(dev,arcpacket->raw,length>=240,"tx"); - - lp->lastload_dest=daddr; - lp->txready=lp->txbuf; /* packet is ready for sending */ - - dev_kfree_skb(skb,FREE_WRITE); - - if (arcnet_go_tx(dev,1)) - { - /* inform upper layers */ - TBUSY=0; - mark_bh(NET_BH); - } + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + int bad,oldmask=0; + u_char daddr; + short offset,length=skb->len+1; + u_char proto=ARC_P_ETHER; + + lp->intx++; + + oldmask |= lp->intmask; + lp->intmask=0; + SETMASK; + + bad=arcnet_send_packet_bad(skb,dev); + if (bad) + { + lp->intx--; + lp->intmask=oldmask; + SETMASK; + return bad; + } + + /* arcnet_send_packet_pad has already set tbusy - don't bother here. */ + + lp->intmask=oldmask; + SETMASK; + + if (length>XMTU) + { + BUGMSG(D_NORMAL,"MTU must be <= 493 for ethernet encap (length=%d).\n", + length); + BUGMSG(D_NORMAL,"transmit aborted.\n"); + + dev_kfree_skb(skb,FREE_WRITE); + lp->intx--; + return 0; + } + + BUGMSG(D_DURING,"starting tx sequence...\n"); + + /* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */ + if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF) + daddr=0; + else + daddr=((struct ethhdr*)(skb->data))->h_dest[5]; + + /* load packet into shared memory */ + offset=512-length; + if (length>MTU) /* long/exception packet */ + { + if (length<MinTU) offset-=3; + } + else /* short packet */ + { + offset-=256; + } + + BUGMSG(D_DURING," length=%Xh, offset=%Xh\n", + length,offset); + + (*lp->prepare_tx)(dev, &proto, 1, skb->data, length-1, daddr, 0, + offset); + + dev_kfree_skb(skb,FREE_WRITE); + + if (arcnet_go_tx(dev,1)) + { + /* inform upper layers */ + arcnet_tx_done(lp->adev, lp); + } dev->trans_start=jiffies; lp->intx--; @@ -2920,15 +1646,16 @@ arcnetE_rx(struct device *dev,u_char *arcsoft, return; } - skb->len = length; + skb_put(skb,length); + skb->dev = dev; memcpy(skb->data,(u_char *)arcsoft+1,length-1); BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx"); + lp->stats.rx_bytes += skb->len; skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); } @@ -2945,23 +1672,22 @@ arcnetE_rx(struct device *dev,u_char *arcsoft, */ static int arcnetS_init(struct device *dev) { - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - - arcnet_setup(dev); - - /* And now fill particular fields with arcnet values */ - dev->dev_addr[0]=lp->stationid; - dev->hard_header_len=sizeof(struct S_ClientData); - dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len - + S_EXTRA_CLIENTDATA; - dev->open=arcnetS_open_close; - dev->stop=arcnetS_open_close; - dev->hard_start_xmit=arcnetS_send_packet; - dev->hard_header=arcnetS_header; - dev->rebuild_header=arcnetS_rebuild_header; - BUGMSG(D_NORMAL,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n"); - - return 0; + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + + arcnet_setup(dev); + + /* And now fill particular fields with arcnet values */ + dev->dev_addr[0]=lp->stationid; + dev->hard_header_len=sizeof(struct S_ClientData); + dev->mtu=512-sizeof(struct archdr)-dev->hard_header_len + + S_EXTRA_CLIENTDATA; + dev->open=arcnetS_open_close; + dev->stop=arcnetS_open_close; + dev->hard_start_xmit=arcnetS_send_packet; + dev->hard_header=arcnetS_header; + dev->rebuild_header=arcnetS_rebuild_header; + + return 0; } @@ -2970,7 +1696,7 @@ static int arcnetS_init(struct device *dev) */ static int arcnetS_open_close(struct device *dev) { - return 0; + return 0; } @@ -2979,63 +1705,61 @@ static int arcnetS_open_close(struct device *dev) static int arcnetS_send_packet(struct sk_buff *skb, struct device *dev) { - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - int ioaddr=IOADDR,bad,length; - struct S_ClientData *hdr=(struct S_ClientData *)skb->data; + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + int bad,length; + struct S_ClientData *hdr=(struct S_ClientData *)skb->data; - lp->intx++; + lp->intx++; - bad=arcnet_send_packet_bad(skb,dev); - if (bad) - { - lp->intx--; - return bad; - } + bad=arcnet_send_packet_bad(skb,dev); + if (bad) + { + lp->intx--; + return bad; + } - TBUSY=1; + /* arcnet_send_packet_pad has already set tbusy - don't bother here. */ - length = 1 < skb->len ? skb->len : 1; + length = 1 < skb->len ? skb->len : 1; - BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx"); + BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx"); - /* fits in one packet? */ - if (length-S_EXTRA_CLIENTDATA<=XMTU) - { - arcnetAS_prepare_tx(dev, + /* fits in one packet? */ + if (length-S_EXTRA_CLIENTDATA<=XMTU) + { + (*lp->prepare_tx)(dev, skb->data+S_EXTRA_CLIENTDATA, sizeof(struct S_ClientData)-S_EXTRA_CLIENTDATA, skb->data+sizeof(struct S_ClientData), length-sizeof(struct S_ClientData), - hdr->daddr,0); + hdr->daddr,0,0); - /* done right away */ - dev_kfree_skb(skb,FREE_WRITE); + /* done right away */ + dev_kfree_skb(skb,FREE_WRITE); - if (arcnet_go_tx(dev,1)) - { - /* inform upper layers */ - TBUSY=0; - mark_bh(NET_BH); - } - } - else /* too big for one - not accepted */ + if (arcnet_go_tx(dev,1)) { - BUGMSG(D_NORMAL,"packet too long (length=%d)\n", - length); - dev_kfree_skb(skb,FREE_WRITE); - lp->stats.tx_dropped++; - TBUSY=0; - mark_bh(NET_BH); + /* inform upper layers */ + arcnet_tx_done(lp->adev, lp); } + } + else /* too big for one - not accepted */ + { + BUGMSG(D_NORMAL,"packet too long (length=%d)\n", + length); + dev_kfree_skb(skb,FREE_WRITE); + lp->stats.tx_dropped++; + arcnet_tx_done(lp->adev, lp); + } - dev->trans_start=jiffies; - lp->intx--; + dev->trans_start=jiffies; + lp->intx--; - /* make sure we didn't ignore a TX IRQ while we were in here */ - lp->intmask |= TXFREEflag; - SETMASK; + /* make sure we didn't ignore a TX IRQ while we were in here */ + lp->intmask |= TXFREEflag; + SETMASK; - return 0; + return 0; } @@ -3043,47 +1767,43 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev) */ static void arcnetS_rx(struct device *dev,u_char *buf, - int length,u_char saddr, u_char daddr) + int length,u_char saddr, u_char daddr) { - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - struct sk_buff *skb; - struct S_ClientData *arcsoft,*soft; - - arcsoft=(struct S_ClientData *)(buf-S_EXTRA_CLIENTDATA); - length+=S_EXTRA_CLIENTDATA; - - BUGMSG(D_DURING,"it's an RFC1051 packet (length=%d)\n", - length); - - - - { /* was "if not split" in A protocol, S is never split */ - - skb = alloc_skb(length, GFP_ATOMIC); - if (skb == NULL) { - BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n"); - lp->stats.rx_dropped++; - return; - } - soft=(struct S_ClientData *)skb->data; - skb->len = length; - memcpy((u_char *)soft + sizeof(struct S_ClientData) - - S_EXTRA_CLIENTDATA, - (u_char *)arcsoft + sizeof(struct S_ClientData) - - S_EXTRA_CLIENTDATA, - length - sizeof(struct S_ClientData) - + S_EXTRA_CLIENTDATA); - soft->protocol_id=arcsoft->protocol_id; - soft->daddr=daddr; - soft->saddr=saddr; - skb->dev = dev; /* is already lp->sdev */ - - BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx"); - - skb->protocol=arcnetS_type_trans(skb,dev); - - netif_rx(skb); - } + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + struct sk_buff *skb; + struct S_ClientData *arcsoft,*soft; + + arcsoft=(struct S_ClientData *)(buf-S_EXTRA_CLIENTDATA); + length+=S_EXTRA_CLIENTDATA; + + BUGMSG(D_DURING,"it's an RFC1051 packet (length=%d)\n", + length); + + { /* was "if not split" in A protocol, S is never split */ + + skb = alloc_skb(length, GFP_ATOMIC); + if (skb == NULL) { + BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n"); + lp->stats.rx_dropped++; + return; + } + soft=(struct S_ClientData *)skb->data; + skb_put(skb,length); + + memcpy((u_char *)soft + sizeof(struct S_ClientData) - S_EXTRA_CLIENTDATA, + (u_char *)arcsoft + sizeof(struct S_ClientData) -S_EXTRA_CLIENTDATA, + length - sizeof(struct S_ClientData) + S_EXTRA_CLIENTDATA); + soft->protocol_id=arcsoft->protocol_id; + soft->daddr=daddr; + soft->saddr=saddr; + skb->dev = dev; /* is already lp->sdev */ + + BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx"); + + lp->stats.rx_bytes += skb->len; + skb->protocol=arcnetS_type_trans(skb,dev); + netif_rx(skb); + } } @@ -3092,55 +1812,55 @@ arcnetS_rx(struct device *dev,u_char *buf, * saddr=NULL means use device source address (always will anyway) * daddr=NULL means leave destination address (eg unresolved arp) */ -int arcnetS_header(struct sk_buff *skb,struct device *dev, - unsigned short type,void *daddr,void *saddr,unsigned len) +static int arcnetS_header(struct sk_buff *skb,struct device *dev, + unsigned short type,void *daddr,void *saddr,unsigned len) { - struct S_ClientData *head = (struct S_ClientData *) - skb_push(skb,dev->hard_header_len); - struct arcnet_local *lp=(struct arcnet_local *)(dev->priv); - - /* set the protocol ID according to RFC1051 */ - switch(type) - { - case ETH_P_IP: - head->protocol_id=ARC_P_IP_RFC1051; - BUGMSG(D_DURING,"S_header: IP_RFC1051 packet.\n"); - break; - case ETH_P_ARP: - head->protocol_id=ARC_P_ARP_RFC1051; - BUGMSG(D_DURING,"S_header: ARP_RFC1051 packet.\n"); - break; - default: - BUGMSG(D_NORMAL,"I don't understand protocol %d (%Xh)\n", - type,type); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - return 0; - } - - /* - * Set the source hardware address. - * - * This is pretty pointless for most purposes, but it can help - * in debugging. saddr is stored in the ClientData header and - * removed before sending the packet (since ARCnet does not allow - * us to change the source address in the actual packet sent) - */ - if(saddr) - head->saddr=((u_char*)saddr)[0]; - else - head->saddr=((u_char*)(dev->dev_addr))[0]; - - /* supposedly if daddr is NULL, we should ignore it... */ - if(daddr) - { + struct S_ClientData *head = (struct S_ClientData *) + skb_push(skb,dev->hard_header_len); + struct arcnet_local *lp=(struct arcnet_local *)(dev->priv); + + /* set the protocol ID according to RFC1051 */ + switch(type) + { + case ETH_P_IP: + head->protocol_id=ARC_P_IP_RFC1051; + BUGMSG(D_DURING,"S_header: IP_RFC1051 packet.\n"); + break; + case ETH_P_ARP: + head->protocol_id=ARC_P_ARP_RFC1051; + BUGMSG(D_DURING,"S_header: ARP_RFC1051 packet.\n"); + break; + default: + BUGMSG(D_NORMAL,"I don't understand protocol %d (%Xh)\n", + type,type); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + return 0; + } + + /* + * Set the source hardware address. + * + * This is pretty pointless for most purposes, but it can help + * in debugging. saddr is stored in the ClientData header and + * removed before sending the packet (since ARCnet does not allow + * us to change the source address in the actual packet sent) + */ + if(saddr) + head->saddr=((u_char*)saddr)[0]; + else + head->saddr=((u_char*)(dev->dev_addr))[0]; + + /* supposedly if daddr is NULL, we should ignore it... */ + if(daddr) + { head->daddr=((u_char*)daddr)[0]; return dev->hard_header_len; - } - else - head->daddr=0; /* better fill one in anyway */ + } + else + head->daddr=0; /* better fill one in anyway */ - return -dev->hard_header_len; + return -dev->hard_header_len; } @@ -3148,34 +1868,34 @@ int arcnetS_header(struct sk_buff *skb,struct device *dev, * (or in future other address resolution) has completed on this * sk_buff. We now let ARP fill in the other fields. */ -int arcnetS_rebuild_header(struct sk_buff *skb) +static int arcnetS_rebuild_header(struct sk_buff *skb) { - struct device *dev=skb->dev; - struct S_ClientData *head = (struct S_ClientData *)skb->data; - struct arcnet_local *lp=(struct arcnet_local *)(dev->priv); - - /* - * Only ARP and IP are currently supported - */ - - if(head->protocol_id != ARC_P_IP_RFC1051) - { - BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n", - head->protocol_id,head->protocol_id); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - head->daddr=0; - /*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/ - return 0; - } - - /* - * Try to get ARP to resolve the header. - */ + struct device *dev=skb->dev; + struct S_ClientData *head = (struct S_ClientData *)skb->data; + struct arcnet_local *lp=(struct arcnet_local *)(dev->priv); + + /* + * Only ARP and IP are currently supported + */ + + if(head->protocol_id != ARC_P_IP_RFC1051) + { + BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n", + head->protocol_id,head->protocol_id); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + head->daddr=0; + /*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/ + return 0; + } + + /* + * Try to get ARP to resolve the header. + */ #ifdef CONFIG_INET - return arp_find(&(head->daddr),skb)? 1 : 0; + return arp_find(&(head->daddr),skb)? 1 : 0; #else - return 0; + return 0; #endif } @@ -3186,129 +1906,164 @@ int arcnetS_rebuild_header(struct sk_buff *skb) */ unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev) { - struct S_ClientData *head; - struct arcnet_local *lp=(struct arcnet_local *) (dev->priv); - - /* Pull off the arcnet header. */ - skb->mac.raw=skb->data; - skb_pull(skb,dev->hard_header_len); - head=(struct S_ClientData *)skb->mac.raw; - - if (head->daddr==0) - skb->pkt_type=PACKET_BROADCAST; - else if (dev->flags&IFF_PROMISC) - { - /* if we're not sending to ourselves :) */ - if (head->daddr != dev->dev_addr[0]) - skb->pkt_type=PACKET_OTHERHOST; - } - - /* now return the protocol number */ - switch (head->protocol_id) - { - case ARC_P_IP_RFC1051: return htons(ETH_P_IP); - case ARC_P_ARP_RFC1051: return htons(ETH_P_ARP); - case ARC_P_ATALK: return htons(ETH_P_ATALK); /* untested appletalk */ - default: - lp->stats.rx_errors++; - lp->stats.rx_crc_errors++; - return 0; - } - - return htons(ETH_P_IP); + struct S_ClientData *head; + struct arcnet_local *lp=(struct arcnet_local *) (dev->priv); + + /* Pull off the arcnet header. */ + skb->mac.raw=skb->data; + skb_pull(skb,dev->hard_header_len); + head=(struct S_ClientData *)skb->mac.raw; + + if (head->daddr==0) + skb->pkt_type=PACKET_BROADCAST; + else if (dev->flags&IFF_PROMISC) + { + /* if we're not sending to ourselves :) */ + if (head->daddr != dev->dev_addr[0]) + skb->pkt_type=PACKET_OTHERHOST; + } + + /* now return the protocol number */ + switch (head->protocol_id) + { + case ARC_P_IP_RFC1051: return htons(ETH_P_IP); + case ARC_P_ARP_RFC1051: return htons(ETH_P_ARP); + case ARC_P_ATALK: return htons(ETH_P_ATALK); /* untested appletalk */ + default: + lp->stats.rx_errors++; + lp->stats.rx_crc_errors++; + return 0; + } + + return htons(ETH_P_IP); } #endif /* CONFIG_ARCNET_1051 */ + /**************************************************************************** * * * Kernel Loadable Module Support * * * ****************************************************************************/ - #ifdef MODULE -static char devicename[9] = ""; -static struct device thiscard = { - devicename, /* device name is inserted by linux/drivers/net/net_init.c */ - 0, 0, 0, 0, - 0, 0, /* I/O address, IRQ */ - 0, 0, 0, NULL, arcnet_probe -}; +void cleanup_module(void) +{ + printk("Generic arcnet support removed.\n"); +} +void arcnet_use_count(int open) +{ + if (open) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} -static int io=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irqnum=0; /* or use the insmod io= irq= shmem= options */ -static int irq=0; -static int shmem=0; -static char *device = NULL; /* use eg. device="arc1" to change name */ +#else -MODULE_PARM(io, "i"); -MODULE_PARM(irqnum, "i"); -MODULE_PARM(shmem, "i"); +void arcnet_use_count(int open) +{ +} -#ifdef RIM_I_MODE - static int node=0; /* you must specify the node ID for RIM I cards */ -#endif +struct device arcnet_devs[MAX_ARCNET_DEVS]; +int arcnet_num_devs=0; +char arcnet_dev_names[MAX_ARCNET_DEVS][10]; -int init_module(void) +__initfunc(void arcnet_init(void)) { - struct device *dev=&thiscard; - if (device) - strcpy(dev->name,device); - #ifndef CONFIG_ARCNET_ETHNAME - else if (!dev->name[0]) strcpy(dev->name,"arc0"); - #endif + int c; - #ifdef RIM_I_MODE - if (node) io=node; - #endif + init_module(); - dev->base_addr=io; + /* Don't register_netdev here. The chain hasn't been initialised. */ - if (irq) irqnum=irq; - dev->irq=irqnum; - if (dev->irq==2) dev->irq=9; +#ifdef CONFIG_ARCNET_COM90xx + if ((!com90xx_explicit) && arcnet_num_devs < MAX_ARCNET_DEVS) + { + arcnet_devs[arcnet_num_devs].init=arc90xx_probe; + arcnet_devs[arcnet_num_devs].name= + (char *)&arcnet_dev_names[arcnet_num_devs]; + arcnet_num_devs++; + } +#endif - if (shmem) - { - dev->mem_start=shmem; - dev->mem_end=thiscard.mem_start+512*4-1; - dev->rmem_start=thiscard.mem_start+512*0; - dev->rmem_end=thiscard.mem_start+512*2-1; - } + if (!arcnet_num_devs) + { + printk("Don't forget to load the chipset driver.\n"); + return; + } - if (register_netdev(dev) != 0) - return -EIO; - return 0; -} + /* Link into the device chain */ -void cleanup_module(void) -{ - struct device *dev=&thiscard; - int ioaddr=IOADDR; + /* Q: Should we put ourselves at the beginning or the end of the chain? */ + /* Probably the end, because we're not so fast, but... */ - if (dev->start) arcnet_close(dev); + for (c=0; c< (arcnet_num_devs-1); c++) + arcnet_devs[c].next=&arcnet_devs[c+1]; - /* Flush TX and disable RX */ - if (ioaddr) - { - AINTMASK(0); /* disable IRQ's */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ - } + arcnet_devs[c].next=dev_base; + dev_base=&arcnet_devs[0]; - if (dev->irq) - { - irq2dev_map[dev->irq] = NULL; - free_irq(dev->irq,NULL); - } + /* Give names to those without them */ - if (dev->base_addr) RELEASE_REGION(dev->base_addr,ARCNET_TOTAL_SIZE); - unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; + for (c=0; c< arcnet_num_devs; c++) + if (!arcnet_dev_names[c][0]) + arcnet_makename((char *)&arcnet_dev_names[c]); } #endif /* MODULE */ + + +#ifdef MODULE +int init_module(void) +#else +__initfunc(static int init_module(void)) +#endif +{ +#ifdef ALPHA_WARNING + BUGLVL(D_EXTRA) + { + printk("arcnet: ***\n"); + printk("arcnet: * Read arcnet.txt for important release notes!\n"); + printk("arcnet: *\n"); + printk("arcnet: * This is an ALPHA version! (Last stable release: v2.56) E-mail me if\n"); + printk("arcnet: * you have any questions, comments, or bug reports.\n"); + printk("arcnet: ***\n"); + } +#endif + + printk("%sAvailable protocols: ARCnet RFC1201" +#ifdef CONFIG_ARCNET_ETH + ", Ethernet-Encap" +#endif +#ifdef CONFIG_ARCNET_1051 + ", ARCnet RFC1051" +#endif +#ifdef MODULE + ".\nDon't forget to load the chipset driver" +#endif + ".\n",version); + return 0; +} + + +void arcnet_makename(char *device) +{ + struct device *dev; + int arcnum; + + arcnum = 0; + for (;;) + { + sprintf(device, "arc%d", arcnum); + for (dev = dev_base; dev; dev=dev->next) + if (dev->name != device && !strcmp(dev->name, device)) + break; + if (!dev) + return; + arcnum++; + } +} |