162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-1.0+
262306a36Sopenharmony_ci/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as
362306a36Sopenharmony_ci   munged into HPPA boxen .
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci   This driver is based upon 82596.c, original credits are below...
662306a36Sopenharmony_ci   but there were too many hoops which HP wants jumped through to
762306a36Sopenharmony_ci   keep this code in there in a sane manner.
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci   3 primary sources of the mess --
1062306a36Sopenharmony_ci   1) hppa needs *lots* of cacheline flushing to keep this kind of
1162306a36Sopenharmony_ci   MMIO running.
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci   2) The 82596 needs to see all of its pointers as their physical
1462306a36Sopenharmony_ci   address.  Thus virt_to_bus/bus_to_virt are *everywhere*.
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci   3) The implementation HP is using seems to be significantly pickier
1762306a36Sopenharmony_ci   about when and how the command and RX units are started.  some
1862306a36Sopenharmony_ci   command ordering was changed.
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci   Examination of the mach driver leads one to believe that there
2162306a36Sopenharmony_ci   might be a saner way to pull this off...  anyone who feels like a
2262306a36Sopenharmony_ci   full rewrite can be my guest.
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci   Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci   02/01/2000  Initial modifications for parisc by Helge Deller (deller@gmx.de)
2762306a36Sopenharmony_ci   03/02/2000  changes for better/correct(?) cache-flushing (deller)
2862306a36Sopenharmony_ci*/
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/* 82596.c: A generic 82596 ethernet driver for linux. */
3162306a36Sopenharmony_ci/*
3262306a36Sopenharmony_ci   Based on Apricot.c
3362306a36Sopenharmony_ci   Written 1994 by Mark Evans.
3462306a36Sopenharmony_ci   This driver is for the Apricot 82596 bus-master interface
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci   Modularised 12/94 Mark Evans
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci   Modified to support the 82596 ethernet chips on 680x0 VME boards.
4062306a36Sopenharmony_ci   by Richard Hirst <richard@sleepie.demon.co.uk>
4162306a36Sopenharmony_ci   Renamed to be 82596.c
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci   980825:  Changed to receive directly in to sk_buffs which are
4462306a36Sopenharmony_ci   allocated at open() time.  Eliminates copy on incoming frames
4562306a36Sopenharmony_ci   (small ones are still copied).  Shared data now held in a
4662306a36Sopenharmony_ci   non-cached page, so we can run on 68060 in copyback mode.
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci   TBD:
4962306a36Sopenharmony_ci   * look at deferring rx frames rather than discarding (as per tulip)
5062306a36Sopenharmony_ci   * handle tx ring full as per tulip
5162306a36Sopenharmony_ci   * performance test to tune rx_copybreak
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci   Most of my modifications relate to the braindead big-endian
5462306a36Sopenharmony_ci   implementation by Intel.  When the i596 is operating in
5562306a36Sopenharmony_ci   'big-endian' mode, it thinks a 32 bit value of 0x12345678
5662306a36Sopenharmony_ci   should be stored as 0x56781234.  This is a real pain, when
5762306a36Sopenharmony_ci   you have linked lists which are shared by the 680x0 and the
5862306a36Sopenharmony_ci   i596.
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci   Driver skeleton
6162306a36Sopenharmony_ci   Written 1993 by Donald Becker.
6262306a36Sopenharmony_ci   Copyright 1993 United States Government as represented by the Director,
6362306a36Sopenharmony_ci   National Security Agency.
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci   The author may be reached as becker@scyld.com, or C/O
6662306a36Sopenharmony_ci   Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci */
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#include <linux/module.h>
7162306a36Sopenharmony_ci#include <linux/kernel.h>
7262306a36Sopenharmony_ci#include <linux/string.h>
7362306a36Sopenharmony_ci#include <linux/errno.h>
7462306a36Sopenharmony_ci#include <linux/ioport.h>
7562306a36Sopenharmony_ci#include <linux/interrupt.h>
7662306a36Sopenharmony_ci#include <linux/delay.h>
7762306a36Sopenharmony_ci#include <linux/netdevice.h>
7862306a36Sopenharmony_ci#include <linux/etherdevice.h>
7962306a36Sopenharmony_ci#include <linux/skbuff.h>
8062306a36Sopenharmony_ci#include <linux/types.h>
8162306a36Sopenharmony_ci#include <linux/bitops.h>
8262306a36Sopenharmony_ci#include <linux/dma-mapping.h>
8362306a36Sopenharmony_ci#include <linux/io.h>
8462306a36Sopenharmony_ci#include <linux/irq.h>
8562306a36Sopenharmony_ci#include <linux/gfp.h>
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* DEBUG flags
8862306a36Sopenharmony_ci */
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#define DEB_INIT	0x0001
9162306a36Sopenharmony_ci#define DEB_PROBE	0x0002
9262306a36Sopenharmony_ci#define DEB_SERIOUS	0x0004
9362306a36Sopenharmony_ci#define DEB_ERRORS	0x0008
9462306a36Sopenharmony_ci#define DEB_MULTI	0x0010
9562306a36Sopenharmony_ci#define DEB_TDR		0x0020
9662306a36Sopenharmony_ci#define DEB_OPEN	0x0040
9762306a36Sopenharmony_ci#define DEB_RESET	0x0080
9862306a36Sopenharmony_ci#define DEB_ADDCMD	0x0100
9962306a36Sopenharmony_ci#define DEB_STATUS	0x0200
10062306a36Sopenharmony_ci#define DEB_STARTTX	0x0400
10162306a36Sopenharmony_ci#define DEB_RXADDR	0x0800
10262306a36Sopenharmony_ci#define DEB_TXADDR	0x1000
10362306a36Sopenharmony_ci#define DEB_RXFRAME	0x2000
10462306a36Sopenharmony_ci#define DEB_INTS	0x4000
10562306a36Sopenharmony_ci#define DEB_STRUCT	0x8000
10662306a36Sopenharmony_ci#define DEB_ANY		0xffff
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define DEB(x, y)	if (i596_debug & (x)) { y; }
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/*
11362306a36Sopenharmony_ci * The MPU_PORT command allows direct access to the 82596. With PORT access
11462306a36Sopenharmony_ci * the following commands are available (p5-18). The 32-bit port command
11562306a36Sopenharmony_ci * must be word-swapped with the most significant word written first.
11662306a36Sopenharmony_ci * This only applies to VME boards.
11762306a36Sopenharmony_ci */
11862306a36Sopenharmony_ci#define PORT_RESET		0x00	/* reset 82596 */
11962306a36Sopenharmony_ci#define PORT_SELFTEST		0x01	/* selftest */
12062306a36Sopenharmony_ci#define PORT_ALTSCP		0x02	/* alternate SCB address */
12162306a36Sopenharmony_ci#define PORT_ALTDUMP		0x03	/* Alternate DUMP address */
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int i596_debug = (DEB_SERIOUS|DEB_PROBE);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/* Copy frames shorter than rx_copybreak, otherwise pass on up in
12662306a36Sopenharmony_ci * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
12762306a36Sopenharmony_ci */
12862306a36Sopenharmony_cistatic int rx_copybreak = 100;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci#define PKT_BUF_SZ	1536
13162306a36Sopenharmony_ci#define MAX_MC_CNT	64
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci#define ISCP_BUSY	0x0001
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#define I596_NULL ((u32)0xffffffff)
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci#define CMD_EOL		0x8000	/* The last command of the list, stop. */
13862306a36Sopenharmony_ci#define CMD_SUSP	0x4000	/* Suspend after doing cmd. */
13962306a36Sopenharmony_ci#define CMD_INTR	0x2000	/* Interrupt after doing cmd. */
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci#define CMD_FLEX	0x0008	/* Enable flexible memory model */
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cienum commands {
14462306a36Sopenharmony_ci	CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
14562306a36Sopenharmony_ci	CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
14662306a36Sopenharmony_ci};
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci#define STAT_C		0x8000	/* Set to 0 after execution */
14962306a36Sopenharmony_ci#define STAT_B		0x4000	/* Command being executed */
15062306a36Sopenharmony_ci#define STAT_OK		0x2000	/* Command executed ok */
15162306a36Sopenharmony_ci#define STAT_A		0x1000	/* Command aborted */
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci#define	 CUC_START	0x0100
15462306a36Sopenharmony_ci#define	 CUC_RESUME	0x0200
15562306a36Sopenharmony_ci#define	 CUC_SUSPEND    0x0300
15662306a36Sopenharmony_ci#define	 CUC_ABORT	0x0400
15762306a36Sopenharmony_ci#define	 RX_START	0x0010
15862306a36Sopenharmony_ci#define	 RX_RESUME	0x0020
15962306a36Sopenharmony_ci#define	 RX_SUSPEND	0x0030
16062306a36Sopenharmony_ci#define	 RX_ABORT	0x0040
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci#define TX_TIMEOUT	(HZ/20)
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistruct i596_reg {
16662306a36Sopenharmony_ci	unsigned short porthi;
16762306a36Sopenharmony_ci	unsigned short portlo;
16862306a36Sopenharmony_ci	u32            ca;
16962306a36Sopenharmony_ci};
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci#define EOF		0x8000
17262306a36Sopenharmony_ci#define SIZE_MASK	0x3fff
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistruct i596_tbd {
17562306a36Sopenharmony_ci	unsigned short size;
17662306a36Sopenharmony_ci	unsigned short pad;
17762306a36Sopenharmony_ci	u32            next;
17862306a36Sopenharmony_ci	u32            data;
17962306a36Sopenharmony_ci	u32 cache_pad[5];		/* Total 32 bytes... */
18062306a36Sopenharmony_ci};
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/* The command structure has two 'next' pointers; v_next is the address of
18362306a36Sopenharmony_ci * the next command as seen by the CPU, b_next is the address of the next
18462306a36Sopenharmony_ci * command as seen by the 82596.  The b_next pointer, as used by the 82596
18562306a36Sopenharmony_ci * always references the status field of the next command, rather than the
18662306a36Sopenharmony_ci * v_next field, because the 82596 is unaware of v_next.  It may seem more
18762306a36Sopenharmony_ci * logical to put v_next at the end of the structure, but we cannot do that
18862306a36Sopenharmony_ci * because the 82596 expects other fields to be there, depending on command
18962306a36Sopenharmony_ci * type.
19062306a36Sopenharmony_ci */
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistruct i596_cmd {
19362306a36Sopenharmony_ci	struct i596_cmd *v_next;	/* Address from CPUs viewpoint */
19462306a36Sopenharmony_ci	unsigned short status;
19562306a36Sopenharmony_ci	unsigned short command;
19662306a36Sopenharmony_ci	u32            b_next;	/* Address from i596 viewpoint */
19762306a36Sopenharmony_ci};
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistruct tx_cmd {
20062306a36Sopenharmony_ci	struct i596_cmd cmd;
20162306a36Sopenharmony_ci	u32            tbd;
20262306a36Sopenharmony_ci	unsigned short size;
20362306a36Sopenharmony_ci	unsigned short pad;
20462306a36Sopenharmony_ci	struct sk_buff *skb;		/* So we can free it after tx */
20562306a36Sopenharmony_ci	dma_addr_t dma_addr;
20662306a36Sopenharmony_ci#ifdef __LP64__
20762306a36Sopenharmony_ci	u32 cache_pad[6];		/* Total 64 bytes... */
20862306a36Sopenharmony_ci#else
20962306a36Sopenharmony_ci	u32 cache_pad[1];		/* Total 32 bytes... */
21062306a36Sopenharmony_ci#endif
21162306a36Sopenharmony_ci};
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistruct tdr_cmd {
21462306a36Sopenharmony_ci	struct i596_cmd cmd;
21562306a36Sopenharmony_ci	unsigned short status;
21662306a36Sopenharmony_ci	unsigned short pad;
21762306a36Sopenharmony_ci};
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistruct mc_cmd {
22062306a36Sopenharmony_ci	struct i596_cmd cmd;
22162306a36Sopenharmony_ci	short mc_cnt;
22262306a36Sopenharmony_ci	char mc_addrs[MAX_MC_CNT*6];
22362306a36Sopenharmony_ci};
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistruct sa_cmd {
22662306a36Sopenharmony_ci	struct i596_cmd cmd;
22762306a36Sopenharmony_ci	char eth_addr[8];
22862306a36Sopenharmony_ci};
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistruct cf_cmd {
23162306a36Sopenharmony_ci	struct i596_cmd cmd;
23262306a36Sopenharmony_ci	char i596_config[16];
23362306a36Sopenharmony_ci};
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistruct i596_rfd {
23662306a36Sopenharmony_ci	unsigned short stat;
23762306a36Sopenharmony_ci	unsigned short cmd;
23862306a36Sopenharmony_ci	u32            b_next;	/* Address from i596 viewpoint */
23962306a36Sopenharmony_ci	u32            rbd;
24062306a36Sopenharmony_ci	unsigned short count;
24162306a36Sopenharmony_ci	unsigned short size;
24262306a36Sopenharmony_ci	struct i596_rfd *v_next;	/* Address from CPUs viewpoint */
24362306a36Sopenharmony_ci	struct i596_rfd *v_prev;
24462306a36Sopenharmony_ci#ifndef __LP64__
24562306a36Sopenharmony_ci	u32 cache_pad[2];		/* Total 32 bytes... */
24662306a36Sopenharmony_ci#endif
24762306a36Sopenharmony_ci};
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistruct i596_rbd {
25062306a36Sopenharmony_ci	/* hardware data */
25162306a36Sopenharmony_ci	unsigned short count;
25262306a36Sopenharmony_ci	unsigned short zero1;
25362306a36Sopenharmony_ci	u32            b_next;
25462306a36Sopenharmony_ci	u32            b_data;		/* Address from i596 viewpoint */
25562306a36Sopenharmony_ci	unsigned short size;
25662306a36Sopenharmony_ci	unsigned short zero2;
25762306a36Sopenharmony_ci	/* driver data */
25862306a36Sopenharmony_ci	struct sk_buff *skb;
25962306a36Sopenharmony_ci	struct i596_rbd *v_next;
26062306a36Sopenharmony_ci	u32            b_addr;		/* This rbd addr from i596 view */
26162306a36Sopenharmony_ci	unsigned char *v_data;		/* Address from CPUs viewpoint */
26262306a36Sopenharmony_ci					/* Total 32 bytes... */
26362306a36Sopenharmony_ci#ifdef __LP64__
26462306a36Sopenharmony_ci    u32 cache_pad[4];
26562306a36Sopenharmony_ci#endif
26662306a36Sopenharmony_ci};
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci/* These values as chosen so struct i596_dma fits in one page... */
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci#define TX_RING_SIZE 32
27162306a36Sopenharmony_ci#define RX_RING_SIZE 16
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistruct i596_scb {
27462306a36Sopenharmony_ci	unsigned short status;
27562306a36Sopenharmony_ci	unsigned short command;
27662306a36Sopenharmony_ci	u32           cmd;
27762306a36Sopenharmony_ci	u32           rfd;
27862306a36Sopenharmony_ci	u32           crc_err;
27962306a36Sopenharmony_ci	u32           align_err;
28062306a36Sopenharmony_ci	u32           resource_err;
28162306a36Sopenharmony_ci	u32           over_err;
28262306a36Sopenharmony_ci	u32           rcvdt_err;
28362306a36Sopenharmony_ci	u32           short_err;
28462306a36Sopenharmony_ci	unsigned short t_on;
28562306a36Sopenharmony_ci	unsigned short t_off;
28662306a36Sopenharmony_ci};
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistruct i596_iscp {
28962306a36Sopenharmony_ci	u32 stat;
29062306a36Sopenharmony_ci	u32 scb;
29162306a36Sopenharmony_ci};
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistruct i596_scp {
29462306a36Sopenharmony_ci	u32 sysbus;
29562306a36Sopenharmony_ci	u32 pad;
29662306a36Sopenharmony_ci	u32 iscp;
29762306a36Sopenharmony_ci};
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistruct i596_dma {
30062306a36Sopenharmony_ci	struct i596_scp scp		        __attribute__((aligned(32)));
30162306a36Sopenharmony_ci	volatile struct i596_iscp iscp		__attribute__((aligned(32)));
30262306a36Sopenharmony_ci	volatile struct i596_scb scb		__attribute__((aligned(32)));
30362306a36Sopenharmony_ci	struct sa_cmd sa_cmd			__attribute__((aligned(32)));
30462306a36Sopenharmony_ci	struct cf_cmd cf_cmd			__attribute__((aligned(32)));
30562306a36Sopenharmony_ci	struct tdr_cmd tdr_cmd			__attribute__((aligned(32)));
30662306a36Sopenharmony_ci	struct mc_cmd mc_cmd			__attribute__((aligned(32)));
30762306a36Sopenharmony_ci	struct i596_rfd rfds[RX_RING_SIZE]	__attribute__((aligned(32)));
30862306a36Sopenharmony_ci	struct i596_rbd rbds[RX_RING_SIZE]	__attribute__((aligned(32)));
30962306a36Sopenharmony_ci	struct tx_cmd tx_cmds[TX_RING_SIZE]	__attribute__((aligned(32)));
31062306a36Sopenharmony_ci	struct i596_tbd tbds[TX_RING_SIZE]	__attribute__((aligned(32)));
31162306a36Sopenharmony_ci};
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistruct i596_private {
31462306a36Sopenharmony_ci	struct i596_dma *dma;
31562306a36Sopenharmony_ci	u32    stat;
31662306a36Sopenharmony_ci	int last_restart;
31762306a36Sopenharmony_ci	struct i596_rfd *rfd_head;
31862306a36Sopenharmony_ci	struct i596_rbd *rbd_head;
31962306a36Sopenharmony_ci	struct i596_cmd *cmd_tail;
32062306a36Sopenharmony_ci	struct i596_cmd *cmd_head;
32162306a36Sopenharmony_ci	int cmd_backlog;
32262306a36Sopenharmony_ci	u32    last_cmd;
32362306a36Sopenharmony_ci	int next_tx_cmd;
32462306a36Sopenharmony_ci	int options;
32562306a36Sopenharmony_ci	spinlock_t lock;       /* serialize access to chip */
32662306a36Sopenharmony_ci	dma_addr_t dma_addr;
32762306a36Sopenharmony_ci	void __iomem *mpu_port;
32862306a36Sopenharmony_ci	void __iomem *ca;
32962306a36Sopenharmony_ci};
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic const char init_setup[] =
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	0x8E,		/* length, prefetch on */
33462306a36Sopenharmony_ci	0xC8,		/* fifo to 8, monitor off */
33562306a36Sopenharmony_ci	0x80,		/* don't save bad frames */
33662306a36Sopenharmony_ci	0x2E,		/* No source address insertion, 8 byte preamble */
33762306a36Sopenharmony_ci	0x00,		/* priority and backoff defaults */
33862306a36Sopenharmony_ci	0x60,		/* interframe spacing */
33962306a36Sopenharmony_ci	0x00,		/* slot time LSB */
34062306a36Sopenharmony_ci	0xf2,		/* slot time and retries */
34162306a36Sopenharmony_ci	0x00,		/* promiscuous mode */
34262306a36Sopenharmony_ci	0x00,		/* collision detect */
34362306a36Sopenharmony_ci	0x40,		/* minimum frame length */
34462306a36Sopenharmony_ci	0xff,
34562306a36Sopenharmony_ci	0x00,
34662306a36Sopenharmony_ci	0x7f /*  *multi IA */ };
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic int i596_open(struct net_device *dev);
34962306a36Sopenharmony_cistatic netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
35062306a36Sopenharmony_cistatic irqreturn_t i596_interrupt(int irq, void *dev_id);
35162306a36Sopenharmony_cistatic int i596_close(struct net_device *dev);
35262306a36Sopenharmony_cistatic void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
35362306a36Sopenharmony_cistatic void i596_tx_timeout (struct net_device *dev, unsigned int txqueue);
35462306a36Sopenharmony_cistatic void print_eth(unsigned char *buf, char *str);
35562306a36Sopenharmony_cistatic void set_multicast_list(struct net_device *dev);
35662306a36Sopenharmony_cistatic inline void ca(struct net_device *dev);
35762306a36Sopenharmony_cistatic void mpu_port(struct net_device *dev, int c, dma_addr_t x);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic int rx_ring_size = RX_RING_SIZE;
36062306a36Sopenharmony_cistatic int ticks_limit = 100;
36162306a36Sopenharmony_cistatic int max_cmd_backlog = TX_RING_SIZE-1;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
36462306a36Sopenharmony_cistatic void i596_poll_controller(struct net_device *dev);
36562306a36Sopenharmony_ci#endif
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic inline dma_addr_t virt_to_dma(struct i596_private *lp, volatile void *v)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	return lp->dma_addr + ((unsigned long)v - (unsigned long)lp->dma);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci#ifdef NONCOHERENT_DMA
37362306a36Sopenharmony_cistatic inline void dma_sync_dev(struct net_device *ndev, volatile void *addr,
37462306a36Sopenharmony_ci		size_t len)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	dma_sync_single_for_device(ndev->dev.parent,
37762306a36Sopenharmony_ci			virt_to_dma(netdev_priv(ndev), addr), len,
37862306a36Sopenharmony_ci			DMA_BIDIRECTIONAL);
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic inline void dma_sync_cpu(struct net_device *ndev, volatile void *addr,
38262306a36Sopenharmony_ci		size_t len)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	dma_sync_single_for_cpu(ndev->dev.parent,
38562306a36Sopenharmony_ci			virt_to_dma(netdev_priv(ndev), addr), len,
38662306a36Sopenharmony_ci			DMA_BIDIRECTIONAL);
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci#else
38962306a36Sopenharmony_cistatic inline void dma_sync_dev(struct net_device *ndev, volatile void *addr,
39062306a36Sopenharmony_ci		size_t len)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_cistatic inline void dma_sync_cpu(struct net_device *ndev, volatile void *addr,
39462306a36Sopenharmony_ci		size_t len)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci#endif /* NONCOHERENT_DMA */
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic inline int wait_istat(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	dma_sync_cpu(dev, &(dma->iscp), sizeof(struct i596_iscp));
40262306a36Sopenharmony_ci	while (--delcnt && dma->iscp.stat) {
40362306a36Sopenharmony_ci		udelay(10);
40462306a36Sopenharmony_ci		dma_sync_cpu(dev, &(dma->iscp), sizeof(struct i596_iscp));
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci	if (!delcnt) {
40762306a36Sopenharmony_ci		printk(KERN_ERR "%s: %s, iscp.stat %04x, didn't clear\n",
40862306a36Sopenharmony_ci		     dev->name, str, SWAP16(dma->iscp.stat));
40962306a36Sopenharmony_ci		return -1;
41062306a36Sopenharmony_ci	} else
41162306a36Sopenharmony_ci		return 0;
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic inline int wait_cmd(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	dma_sync_cpu(dev, &(dma->scb), sizeof(struct i596_scb));
41862306a36Sopenharmony_ci	while (--delcnt && dma->scb.command) {
41962306a36Sopenharmony_ci		udelay(10);
42062306a36Sopenharmony_ci		dma_sync_cpu(dev, &(dma->scb), sizeof(struct i596_scb));
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci	if (!delcnt) {
42362306a36Sopenharmony_ci		printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
42462306a36Sopenharmony_ci		       dev->name, str,
42562306a36Sopenharmony_ci		       SWAP16(dma->scb.status),
42662306a36Sopenharmony_ci		       SWAP16(dma->scb.command));
42762306a36Sopenharmony_ci		return -1;
42862306a36Sopenharmony_ci	} else
42962306a36Sopenharmony_ci		return 0;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic void i596_display_data(struct net_device *dev)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	struct i596_private *lp = netdev_priv(dev);
43662306a36Sopenharmony_ci	struct i596_dma *dma = lp->dma;
43762306a36Sopenharmony_ci	struct i596_cmd *cmd;
43862306a36Sopenharmony_ci	struct i596_rfd *rfd;
43962306a36Sopenharmony_ci	struct i596_rbd *rbd;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	printk(KERN_DEBUG "lp and scp at %p, .sysbus = %08x, .iscp = %08x\n",
44262306a36Sopenharmony_ci	       &dma->scp, dma->scp.sysbus, SWAP32(dma->scp.iscp));
44362306a36Sopenharmony_ci	printk(KERN_DEBUG "iscp at %p, iscp.stat = %08x, .scb = %08x\n",
44462306a36Sopenharmony_ci	       &dma->iscp, SWAP32(dma->iscp.stat), SWAP32(dma->iscp.scb));
44562306a36Sopenharmony_ci	printk(KERN_DEBUG "scb at %p, scb.status = %04x, .command = %04x,"
44662306a36Sopenharmony_ci		" .cmd = %08x, .rfd = %08x\n",
44762306a36Sopenharmony_ci	       &dma->scb, SWAP16(dma->scb.status), SWAP16(dma->scb.command),
44862306a36Sopenharmony_ci		SWAP16(dma->scb.cmd), SWAP32(dma->scb.rfd));
44962306a36Sopenharmony_ci	printk(KERN_DEBUG "   errors: crc %x, align %x, resource %x,"
45062306a36Sopenharmony_ci	       " over %x, rcvdt %x, short %x\n",
45162306a36Sopenharmony_ci	       SWAP32(dma->scb.crc_err), SWAP32(dma->scb.align_err),
45262306a36Sopenharmony_ci	       SWAP32(dma->scb.resource_err), SWAP32(dma->scb.over_err),
45362306a36Sopenharmony_ci	       SWAP32(dma->scb.rcvdt_err), SWAP32(dma->scb.short_err));
45462306a36Sopenharmony_ci	cmd = lp->cmd_head;
45562306a36Sopenharmony_ci	while (cmd != NULL) {
45662306a36Sopenharmony_ci		printk(KERN_DEBUG
45762306a36Sopenharmony_ci		       "cmd at %p, .status = %04x, .command = %04x,"
45862306a36Sopenharmony_ci		       " .b_next = %08x\n",
45962306a36Sopenharmony_ci		       cmd, SWAP16(cmd->status), SWAP16(cmd->command),
46062306a36Sopenharmony_ci		       SWAP32(cmd->b_next));
46162306a36Sopenharmony_ci		cmd = cmd->v_next;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci	rfd = lp->rfd_head;
46462306a36Sopenharmony_ci	printk(KERN_DEBUG "rfd_head = %p\n", rfd);
46562306a36Sopenharmony_ci	do {
46662306a36Sopenharmony_ci		printk(KERN_DEBUG
46762306a36Sopenharmony_ci		       "   %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x,"
46862306a36Sopenharmony_ci		       " count %04x\n",
46962306a36Sopenharmony_ci		       rfd, SWAP16(rfd->stat), SWAP16(rfd->cmd),
47062306a36Sopenharmony_ci		       SWAP32(rfd->b_next), SWAP32(rfd->rbd),
47162306a36Sopenharmony_ci		       SWAP16(rfd->count));
47262306a36Sopenharmony_ci		rfd = rfd->v_next;
47362306a36Sopenharmony_ci	} while (rfd != lp->rfd_head);
47462306a36Sopenharmony_ci	rbd = lp->rbd_head;
47562306a36Sopenharmony_ci	printk(KERN_DEBUG "rbd_head = %p\n", rbd);
47662306a36Sopenharmony_ci	do {
47762306a36Sopenharmony_ci		printk(KERN_DEBUG
47862306a36Sopenharmony_ci		       "   %p .count %04x, b_next %08x, b_data %08x,"
47962306a36Sopenharmony_ci		       " size %04x\n",
48062306a36Sopenharmony_ci			rbd, SWAP16(rbd->count), SWAP32(rbd->b_next),
48162306a36Sopenharmony_ci		       SWAP32(rbd->b_data), SWAP16(rbd->size));
48262306a36Sopenharmony_ci		rbd = rbd->v_next;
48362306a36Sopenharmony_ci	} while (rbd != lp->rbd_head);
48462306a36Sopenharmony_ci	dma_sync_cpu(dev, dma, sizeof(struct i596_dma));
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic inline int init_rx_bufs(struct net_device *dev)
48862306a36Sopenharmony_ci{
48962306a36Sopenharmony_ci	struct i596_private *lp = netdev_priv(dev);
49062306a36Sopenharmony_ci	struct i596_dma *dma = lp->dma;
49162306a36Sopenharmony_ci	int i;
49262306a36Sopenharmony_ci	struct i596_rfd *rfd;
49362306a36Sopenharmony_ci	struct i596_rbd *rbd;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	/* First build the Receive Buffer Descriptor List */
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	for (i = 0, rbd = dma->rbds; i < rx_ring_size; i++, rbd++) {
49862306a36Sopenharmony_ci		dma_addr_t dma_addr;
49962306a36Sopenharmony_ci		struct sk_buff *skb;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci		skb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ);
50262306a36Sopenharmony_ci		if (skb == NULL)
50362306a36Sopenharmony_ci			return -1;
50462306a36Sopenharmony_ci		dma_addr = dma_map_single(dev->dev.parent, skb->data,
50562306a36Sopenharmony_ci					  PKT_BUF_SZ, DMA_FROM_DEVICE);
50662306a36Sopenharmony_ci		rbd->v_next = rbd+1;
50762306a36Sopenharmony_ci		rbd->b_next = SWAP32(virt_to_dma(lp, rbd+1));
50862306a36Sopenharmony_ci		rbd->b_addr = SWAP32(virt_to_dma(lp, rbd));
50962306a36Sopenharmony_ci		rbd->skb = skb;
51062306a36Sopenharmony_ci		rbd->v_data = skb->data;
51162306a36Sopenharmony_ci		rbd->b_data = SWAP32(dma_addr);
51262306a36Sopenharmony_ci		rbd->size = SWAP16(PKT_BUF_SZ);
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci	lp->rbd_head = dma->rbds;
51562306a36Sopenharmony_ci	rbd = dma->rbds + rx_ring_size - 1;
51662306a36Sopenharmony_ci	rbd->v_next = dma->rbds;
51762306a36Sopenharmony_ci	rbd->b_next = SWAP32(virt_to_dma(lp, dma->rbds));
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	/* Now build the Receive Frame Descriptor List */
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	for (i = 0, rfd = dma->rfds; i < rx_ring_size; i++, rfd++) {
52262306a36Sopenharmony_ci		rfd->rbd = I596_NULL;
52362306a36Sopenharmony_ci		rfd->v_next = rfd+1;
52462306a36Sopenharmony_ci		rfd->v_prev = rfd-1;
52562306a36Sopenharmony_ci		rfd->b_next = SWAP32(virt_to_dma(lp, rfd+1));
52662306a36Sopenharmony_ci		rfd->cmd = SWAP16(CMD_FLEX);
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci	lp->rfd_head = dma->rfds;
52962306a36Sopenharmony_ci	dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
53062306a36Sopenharmony_ci	rfd = dma->rfds;
53162306a36Sopenharmony_ci	rfd->rbd = SWAP32(virt_to_dma(lp, lp->rbd_head));
53262306a36Sopenharmony_ci	rfd->v_prev = dma->rfds + rx_ring_size - 1;
53362306a36Sopenharmony_ci	rfd = dma->rfds + rx_ring_size - 1;
53462306a36Sopenharmony_ci	rfd->v_next = dma->rfds;
53562306a36Sopenharmony_ci	rfd->b_next = SWAP32(virt_to_dma(lp, dma->rfds));
53662306a36Sopenharmony_ci	rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	dma_sync_dev(dev, dma, sizeof(struct i596_dma));
53962306a36Sopenharmony_ci	return 0;
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic inline void remove_rx_bufs(struct net_device *dev)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct i596_private *lp = netdev_priv(dev);
54562306a36Sopenharmony_ci	struct i596_rbd *rbd;
54662306a36Sopenharmony_ci	int i;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	for (i = 0, rbd = lp->dma->rbds; i < rx_ring_size; i++, rbd++) {
54962306a36Sopenharmony_ci		if (rbd->skb == NULL)
55062306a36Sopenharmony_ci			break;
55162306a36Sopenharmony_ci		dma_unmap_single(dev->dev.parent,
55262306a36Sopenharmony_ci				 (dma_addr_t)SWAP32(rbd->b_data),
55362306a36Sopenharmony_ci				 PKT_BUF_SZ, DMA_FROM_DEVICE);
55462306a36Sopenharmony_ci		dev_kfree_skb(rbd->skb);
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic void rebuild_rx_bufs(struct net_device *dev)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	struct i596_private *lp = netdev_priv(dev);
56262306a36Sopenharmony_ci	struct i596_dma *dma = lp->dma;
56362306a36Sopenharmony_ci	int i;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* Ensure rx frame/buffer descriptors are tidy */
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	for (i = 0; i < rx_ring_size; i++) {
56862306a36Sopenharmony_ci		dma->rfds[i].rbd = I596_NULL;
56962306a36Sopenharmony_ci		dma->rfds[i].cmd = SWAP16(CMD_FLEX);
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci	dma->rfds[rx_ring_size-1].cmd = SWAP16(CMD_EOL|CMD_FLEX);
57262306a36Sopenharmony_ci	lp->rfd_head = dma->rfds;
57362306a36Sopenharmony_ci	dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
57462306a36Sopenharmony_ci	lp->rbd_head = dma->rbds;
57562306a36Sopenharmony_ci	dma->rfds[0].rbd = SWAP32(virt_to_dma(lp, dma->rbds));
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	dma_sync_dev(dev, dma, sizeof(struct i596_dma));
57862306a36Sopenharmony_ci}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic int init_i596_mem(struct net_device *dev)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	struct i596_private *lp = netdev_priv(dev);
58462306a36Sopenharmony_ci	struct i596_dma *dma = lp->dma;
58562306a36Sopenharmony_ci	unsigned long flags;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	mpu_port(dev, PORT_RESET, 0);
58862306a36Sopenharmony_ci	udelay(100);			/* Wait 100us - seems to help */
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	/* change the scp address */
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	lp->last_cmd = jiffies;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	dma->scp.sysbus = SYSBUS;
59562306a36Sopenharmony_ci	dma->scp.iscp = SWAP32(virt_to_dma(lp, &(dma->iscp)));
59662306a36Sopenharmony_ci	dma->iscp.scb = SWAP32(virt_to_dma(lp, &(dma->scb)));
59762306a36Sopenharmony_ci	dma->iscp.stat = SWAP32(ISCP_BUSY);
59862306a36Sopenharmony_ci	lp->cmd_backlog = 0;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	lp->cmd_head = NULL;
60162306a36Sopenharmony_ci	dma->scb.cmd = I596_NULL;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	DEB(DEB_INIT, printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	dma_sync_dev(dev, &(dma->scp), sizeof(struct i596_scp));
60662306a36Sopenharmony_ci	dma_sync_dev(dev, &(dma->iscp), sizeof(struct i596_iscp));
60762306a36Sopenharmony_ci	dma_sync_dev(dev, &(dma->scb), sizeof(struct i596_scb));
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	mpu_port(dev, PORT_ALTSCP, virt_to_dma(lp, &dma->scp));
61062306a36Sopenharmony_ci	ca(dev);
61162306a36Sopenharmony_ci	if (wait_istat(dev, dma, 1000, "initialization timed out"))
61262306a36Sopenharmony_ci		goto failed;
61362306a36Sopenharmony_ci	DEB(DEB_INIT, printk(KERN_DEBUG
61462306a36Sopenharmony_ci			     "%s: i82596 initialization successful\n",
61562306a36Sopenharmony_ci			     dev->name));
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if (request_irq(dev->irq, i596_interrupt, 0, "i82596", dev)) {
61862306a36Sopenharmony_ci		printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
61962306a36Sopenharmony_ci		goto failed;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	/* Ensure rx frame/buffer descriptors are tidy */
62362306a36Sopenharmony_ci	rebuild_rx_bufs(dev);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	dma->scb.command = 0;
62662306a36Sopenharmony_ci	dma_sync_dev(dev, &(dma->scb), sizeof(struct i596_scb));
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	DEB(DEB_INIT, printk(KERN_DEBUG
62962306a36Sopenharmony_ci			     "%s: queuing CmdConfigure\n", dev->name));
63062306a36Sopenharmony_ci	memcpy(dma->cf_cmd.i596_config, init_setup, 14);
63162306a36Sopenharmony_ci	dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
63262306a36Sopenharmony_ci	dma_sync_dev(dev, &(dma->cf_cmd), sizeof(struct cf_cmd));
63362306a36Sopenharmony_ci	i596_add_cmd(dev, &dma->cf_cmd.cmd);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name));
63662306a36Sopenharmony_ci	memcpy(dma->sa_cmd.eth_addr, dev->dev_addr, ETH_ALEN);
63762306a36Sopenharmony_ci	dma->sa_cmd.cmd.command = SWAP16(CmdSASetup);
63862306a36Sopenharmony_ci	dma_sync_dev(dev, &(dma->sa_cmd), sizeof(struct sa_cmd));
63962306a36Sopenharmony_ci	i596_add_cmd(dev, &dma->sa_cmd.cmd);
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name));
64262306a36Sopenharmony_ci	dma->tdr_cmd.cmd.command = SWAP16(CmdTDR);
64362306a36Sopenharmony_ci	dma_sync_dev(dev, &(dma->tdr_cmd), sizeof(struct tdr_cmd));
64462306a36Sopenharmony_ci	i596_add_cmd(dev, &dma->tdr_cmd.cmd);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	spin_lock_irqsave (&lp->lock, flags);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	if (wait_cmd(dev, dma, 1000, "timed out waiting to issue RX_START")) {
64962306a36Sopenharmony_ci		spin_unlock_irqrestore (&lp->lock, flags);
65062306a36Sopenharmony_ci		goto failed_free_irq;
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci	DEB(DEB_INIT, printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name));
65362306a36Sopenharmony_ci	dma->scb.command = SWAP16(RX_START);
65462306a36Sopenharmony_ci	dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
65562306a36Sopenharmony_ci	dma_sync_dev(dev, &(dma->scb), sizeof(struct i596_scb));
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	ca(dev);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	spin_unlock_irqrestore (&lp->lock, flags);
66062306a36Sopenharmony_ci	if (wait_cmd(dev, dma, 1000, "RX_START not processed"))
66162306a36Sopenharmony_ci		goto failed_free_irq;
66262306a36Sopenharmony_ci	DEB(DEB_INIT, printk(KERN_DEBUG
66362306a36Sopenharmony_ci			     "%s: Receive unit started OK\n", dev->name));
66462306a36Sopenharmony_ci	return 0;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cifailed_free_irq:
66762306a36Sopenharmony_ci	free_irq(dev->irq, dev);
66862306a36Sopenharmony_cifailed:
66962306a36Sopenharmony_ci	printk(KERN_ERR "%s: Failed to initialise 82596\n", dev->name);
67062306a36Sopenharmony_ci	mpu_port(dev, PORT_RESET, 0);
67162306a36Sopenharmony_ci	return -1;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cistatic inline int i596_rx(struct net_device *dev)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	struct i596_private *lp = netdev_priv(dev);
67862306a36Sopenharmony_ci	struct i596_rfd *rfd;
67962306a36Sopenharmony_ci	struct i596_rbd *rbd;
68062306a36Sopenharmony_ci	int frames = 0;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	DEB(DEB_RXFRAME, printk(KERN_DEBUG
68362306a36Sopenharmony_ci				"i596_rx(), rfd_head %p, rbd_head %p\n",
68462306a36Sopenharmony_ci				lp->rfd_head, lp->rbd_head));
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	rfd = lp->rfd_head;		/* Ref next frame to check */
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	dma_sync_cpu(dev, rfd, sizeof(struct i596_rfd));
69062306a36Sopenharmony_ci	while (rfd->stat & SWAP16(STAT_C)) {	/* Loop while complete frames */
69162306a36Sopenharmony_ci		if (rfd->rbd == I596_NULL)
69262306a36Sopenharmony_ci			rbd = NULL;
69362306a36Sopenharmony_ci		else if (rfd->rbd == lp->rbd_head->b_addr) {
69462306a36Sopenharmony_ci			rbd = lp->rbd_head;
69562306a36Sopenharmony_ci			dma_sync_cpu(dev, rbd, sizeof(struct i596_rbd));
69662306a36Sopenharmony_ci		} else {
69762306a36Sopenharmony_ci			printk(KERN_ERR "%s: rbd chain broken!\n", dev->name);
69862306a36Sopenharmony_ci			/* XXX Now what? */
69962306a36Sopenharmony_ci			rbd = NULL;
70062306a36Sopenharmony_ci		}
70162306a36Sopenharmony_ci		DEB(DEB_RXFRAME, printk(KERN_DEBUG
70262306a36Sopenharmony_ci				      "  rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
70362306a36Sopenharmony_ci				      rfd, rfd->rbd, rfd->stat));
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		if (rbd != NULL && (rfd->stat & SWAP16(STAT_OK))) {
70662306a36Sopenharmony_ci			/* a good frame */
70762306a36Sopenharmony_ci			int pkt_len = SWAP16(rbd->count) & 0x3fff;
70862306a36Sopenharmony_ci			struct sk_buff *skb = rbd->skb;
70962306a36Sopenharmony_ci			int rx_in_place = 0;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci			DEB(DEB_RXADDR, print_eth(rbd->v_data, "received"));
71262306a36Sopenharmony_ci			frames++;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci			/* Check if the packet is long enough to just accept
71562306a36Sopenharmony_ci			 * without copying to a properly sized skbuff.
71662306a36Sopenharmony_ci			 */
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci			if (pkt_len > rx_copybreak) {
71962306a36Sopenharmony_ci				struct sk_buff *newskb;
72062306a36Sopenharmony_ci				dma_addr_t dma_addr;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci				dma_unmap_single(dev->dev.parent,
72362306a36Sopenharmony_ci						 (dma_addr_t)SWAP32(rbd->b_data),
72462306a36Sopenharmony_ci						 PKT_BUF_SZ, DMA_FROM_DEVICE);
72562306a36Sopenharmony_ci				/* Get fresh skbuff to replace filled one. */
72662306a36Sopenharmony_ci				newskb = netdev_alloc_skb_ip_align(dev,
72762306a36Sopenharmony_ci								   PKT_BUF_SZ);
72862306a36Sopenharmony_ci				if (newskb == NULL) {
72962306a36Sopenharmony_ci					skb = NULL;	/* drop pkt */
73062306a36Sopenharmony_ci					goto memory_squeeze;
73162306a36Sopenharmony_ci				}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci				/* Pass up the skb already on the Rx ring. */
73462306a36Sopenharmony_ci				skb_put(skb, pkt_len);
73562306a36Sopenharmony_ci				rx_in_place = 1;
73662306a36Sopenharmony_ci				rbd->skb = newskb;
73762306a36Sopenharmony_ci				dma_addr = dma_map_single(dev->dev.parent,
73862306a36Sopenharmony_ci							  newskb->data,
73962306a36Sopenharmony_ci							  PKT_BUF_SZ,
74062306a36Sopenharmony_ci							  DMA_FROM_DEVICE);
74162306a36Sopenharmony_ci				rbd->v_data = newskb->data;
74262306a36Sopenharmony_ci				rbd->b_data = SWAP32(dma_addr);
74362306a36Sopenharmony_ci				dma_sync_dev(dev, rbd, sizeof(struct i596_rbd));
74462306a36Sopenharmony_ci			} else {
74562306a36Sopenharmony_ci				skb = netdev_alloc_skb_ip_align(dev, pkt_len);
74662306a36Sopenharmony_ci			}
74762306a36Sopenharmony_cimemory_squeeze:
74862306a36Sopenharmony_ci			if (skb == NULL) {
74962306a36Sopenharmony_ci				/* XXX tulip.c can defer packets here!! */
75062306a36Sopenharmony_ci				dev->stats.rx_dropped++;
75162306a36Sopenharmony_ci			} else {
75262306a36Sopenharmony_ci				if (!rx_in_place) {
75362306a36Sopenharmony_ci					/* 16 byte align the data fields */
75462306a36Sopenharmony_ci					dma_sync_single_for_cpu(dev->dev.parent,
75562306a36Sopenharmony_ci								(dma_addr_t)SWAP32(rbd->b_data),
75662306a36Sopenharmony_ci								PKT_BUF_SZ, DMA_FROM_DEVICE);
75762306a36Sopenharmony_ci					skb_put_data(skb, rbd->v_data,
75862306a36Sopenharmony_ci						     pkt_len);
75962306a36Sopenharmony_ci					dma_sync_single_for_device(dev->dev.parent,
76062306a36Sopenharmony_ci								   (dma_addr_t)SWAP32(rbd->b_data),
76162306a36Sopenharmony_ci								   PKT_BUF_SZ, DMA_FROM_DEVICE);
76262306a36Sopenharmony_ci				}
76362306a36Sopenharmony_ci				skb->len = pkt_len;
76462306a36Sopenharmony_ci				skb->protocol = eth_type_trans(skb, dev);
76562306a36Sopenharmony_ci				netif_rx(skb);
76662306a36Sopenharmony_ci				dev->stats.rx_packets++;
76762306a36Sopenharmony_ci				dev->stats.rx_bytes += pkt_len;
76862306a36Sopenharmony_ci			}
76962306a36Sopenharmony_ci		} else {
77062306a36Sopenharmony_ci			DEB(DEB_ERRORS, printk(KERN_DEBUG
77162306a36Sopenharmony_ci					       "%s: Error, rfd.stat = 0x%04x\n",
77262306a36Sopenharmony_ci					       dev->name, rfd->stat));
77362306a36Sopenharmony_ci			dev->stats.rx_errors++;
77462306a36Sopenharmony_ci			if (rfd->stat & SWAP16(0x0100))
77562306a36Sopenharmony_ci				dev->stats.collisions++;
77662306a36Sopenharmony_ci			if (rfd->stat & SWAP16(0x8000))
77762306a36Sopenharmony_ci				dev->stats.rx_length_errors++;
77862306a36Sopenharmony_ci			if (rfd->stat & SWAP16(0x0001))
77962306a36Sopenharmony_ci				dev->stats.rx_over_errors++;
78062306a36Sopenharmony_ci			if (rfd->stat & SWAP16(0x0002))
78162306a36Sopenharmony_ci				dev->stats.rx_fifo_errors++;
78262306a36Sopenharmony_ci			if (rfd->stat & SWAP16(0x0004))
78362306a36Sopenharmony_ci				dev->stats.rx_frame_errors++;
78462306a36Sopenharmony_ci			if (rfd->stat & SWAP16(0x0008))
78562306a36Sopenharmony_ci				dev->stats.rx_crc_errors++;
78662306a36Sopenharmony_ci			if (rfd->stat & SWAP16(0x0010))
78762306a36Sopenharmony_ci				dev->stats.rx_length_errors++;
78862306a36Sopenharmony_ci		}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci		/* Clear the buffer descriptor count and EOF + F flags */
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci		if (rbd != NULL && (rbd->count & SWAP16(0x4000))) {
79362306a36Sopenharmony_ci			rbd->count = 0;
79462306a36Sopenharmony_ci			lp->rbd_head = rbd->v_next;
79562306a36Sopenharmony_ci			dma_sync_dev(dev, rbd, sizeof(struct i596_rbd));
79662306a36Sopenharmony_ci		}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci		/* Tidy the frame descriptor, marking it as end of list */
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci		rfd->rbd = I596_NULL;
80162306a36Sopenharmony_ci		rfd->stat = 0;
80262306a36Sopenharmony_ci		rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
80362306a36Sopenharmony_ci		rfd->count = 0;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci		/* Update record of next frame descriptor to process */
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		lp->dma->scb.rfd = rfd->b_next;
80862306a36Sopenharmony_ci		lp->rfd_head = rfd->v_next;
80962306a36Sopenharmony_ci		dma_sync_dev(dev, rfd, sizeof(struct i596_rfd));
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci		/* Remove end-of-list from old end descriptor */
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci		rfd->v_prev->cmd = SWAP16(CMD_FLEX);
81462306a36Sopenharmony_ci		dma_sync_dev(dev, rfd->v_prev, sizeof(struct i596_rfd));
81562306a36Sopenharmony_ci		rfd = lp->rfd_head;
81662306a36Sopenharmony_ci		dma_sync_cpu(dev, rfd, sizeof(struct i596_rfd));
81762306a36Sopenharmony_ci	}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	DEB(DEB_RXFRAME, printk(KERN_DEBUG "frames %d\n", frames));
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	return 0;
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cistatic inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	struct i596_cmd *ptr;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	while (lp->cmd_head != NULL) {
83062306a36Sopenharmony_ci		ptr = lp->cmd_head;
83162306a36Sopenharmony_ci		lp->cmd_head = ptr->v_next;
83262306a36Sopenharmony_ci		lp->cmd_backlog--;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci		switch (SWAP16(ptr->command) & 0x7) {
83562306a36Sopenharmony_ci		case CmdTx:
83662306a36Sopenharmony_ci			{
83762306a36Sopenharmony_ci				struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
83862306a36Sopenharmony_ci				struct sk_buff *skb = tx_cmd->skb;
83962306a36Sopenharmony_ci				dma_unmap_single(dev->dev.parent,
84062306a36Sopenharmony_ci						 tx_cmd->dma_addr,
84162306a36Sopenharmony_ci						 skb->len, DMA_TO_DEVICE);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci				dev_kfree_skb(skb);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci				dev->stats.tx_errors++;
84662306a36Sopenharmony_ci				dev->stats.tx_aborted_errors++;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci				ptr->v_next = NULL;
84962306a36Sopenharmony_ci				ptr->b_next = I596_NULL;
85062306a36Sopenharmony_ci				tx_cmd->cmd.command = 0;  /* Mark as free */
85162306a36Sopenharmony_ci				break;
85262306a36Sopenharmony_ci			}
85362306a36Sopenharmony_ci		default:
85462306a36Sopenharmony_ci			ptr->v_next = NULL;
85562306a36Sopenharmony_ci			ptr->b_next = I596_NULL;
85662306a36Sopenharmony_ci		}
85762306a36Sopenharmony_ci		dma_sync_dev(dev, ptr, sizeof(struct i596_cmd));
85862306a36Sopenharmony_ci	}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	wait_cmd(dev, lp->dma, 100, "i596_cleanup_cmd timed out");
86162306a36Sopenharmony_ci	lp->dma->scb.cmd = I596_NULL;
86262306a36Sopenharmony_ci	dma_sync_dev(dev, &(lp->dma->scb), sizeof(struct i596_scb));
86362306a36Sopenharmony_ci}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_cistatic inline void i596_reset(struct net_device *dev, struct i596_private *lp)
86762306a36Sopenharmony_ci{
86862306a36Sopenharmony_ci	unsigned long flags;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	DEB(DEB_RESET, printk(KERN_DEBUG "i596_reset\n"));
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	spin_lock_irqsave (&lp->lock, flags);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	wait_cmd(dev, lp->dma, 100, "i596_reset timed out");
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	netif_stop_queue(dev);
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	/* FIXME: this command might cause an lpmc */
87962306a36Sopenharmony_ci	lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
88062306a36Sopenharmony_ci	dma_sync_dev(dev, &(lp->dma->scb), sizeof(struct i596_scb));
88162306a36Sopenharmony_ci	ca(dev);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	/* wait for shutdown */
88462306a36Sopenharmony_ci	wait_cmd(dev, lp->dma, 1000, "i596_reset 2 timed out");
88562306a36Sopenharmony_ci	spin_unlock_irqrestore (&lp->lock, flags);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	i596_cleanup_cmd(dev, lp);
88862306a36Sopenharmony_ci	i596_rx(dev);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	netif_start_queue(dev);
89162306a36Sopenharmony_ci	init_i596_mem(dev);
89262306a36Sopenharmony_ci}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_cistatic void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	struct i596_private *lp = netdev_priv(dev);
89862306a36Sopenharmony_ci	struct i596_dma *dma = lp->dma;
89962306a36Sopenharmony_ci	unsigned long flags;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	DEB(DEB_ADDCMD, printk(KERN_DEBUG "i596_add_cmd cmd_head %p\n",
90262306a36Sopenharmony_ci			       lp->cmd_head));
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	cmd->status = 0;
90562306a36Sopenharmony_ci	cmd->command |= SWAP16(CMD_EOL | CMD_INTR);
90662306a36Sopenharmony_ci	cmd->v_next = NULL;
90762306a36Sopenharmony_ci	cmd->b_next = I596_NULL;
90862306a36Sopenharmony_ci	dma_sync_dev(dev, cmd, sizeof(struct i596_cmd));
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	spin_lock_irqsave (&lp->lock, flags);
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	if (lp->cmd_head != NULL) {
91362306a36Sopenharmony_ci		lp->cmd_tail->v_next = cmd;
91462306a36Sopenharmony_ci		lp->cmd_tail->b_next = SWAP32(virt_to_dma(lp, &cmd->status));
91562306a36Sopenharmony_ci		dma_sync_dev(dev, lp->cmd_tail, sizeof(struct i596_cmd));
91662306a36Sopenharmony_ci	} else {
91762306a36Sopenharmony_ci		lp->cmd_head = cmd;
91862306a36Sopenharmony_ci		wait_cmd(dev, dma, 100, "i596_add_cmd timed out");
91962306a36Sopenharmony_ci		dma->scb.cmd = SWAP32(virt_to_dma(lp, &cmd->status));
92062306a36Sopenharmony_ci		dma->scb.command = SWAP16(CUC_START);
92162306a36Sopenharmony_ci		dma_sync_dev(dev, &(dma->scb), sizeof(struct i596_scb));
92262306a36Sopenharmony_ci		ca(dev);
92362306a36Sopenharmony_ci	}
92462306a36Sopenharmony_ci	lp->cmd_tail = cmd;
92562306a36Sopenharmony_ci	lp->cmd_backlog++;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	spin_unlock_irqrestore (&lp->lock, flags);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	if (lp->cmd_backlog > max_cmd_backlog) {
93062306a36Sopenharmony_ci		unsigned long tickssofar = jiffies - lp->last_cmd;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci		if (tickssofar < ticks_limit)
93362306a36Sopenharmony_ci			return;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci		printk(KERN_ERR
93662306a36Sopenharmony_ci		       "%s: command unit timed out, status resetting.\n",
93762306a36Sopenharmony_ci		       dev->name);
93862306a36Sopenharmony_ci#if 1
93962306a36Sopenharmony_ci		i596_reset(dev, lp);
94062306a36Sopenharmony_ci#endif
94162306a36Sopenharmony_ci	}
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic int i596_open(struct net_device *dev)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	DEB(DEB_OPEN, printk(KERN_DEBUG
94762306a36Sopenharmony_ci			     "%s: i596_open() irq %d.\n", dev->name, dev->irq));
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	if (init_rx_bufs(dev)) {
95062306a36Sopenharmony_ci		printk(KERN_ERR "%s: Failed to init rx bufs\n", dev->name);
95162306a36Sopenharmony_ci		return -EAGAIN;
95262306a36Sopenharmony_ci	}
95362306a36Sopenharmony_ci	if (init_i596_mem(dev)) {
95462306a36Sopenharmony_ci		printk(KERN_ERR "%s: Failed to init memory\n", dev->name);
95562306a36Sopenharmony_ci		goto out_remove_rx_bufs;
95662306a36Sopenharmony_ci	}
95762306a36Sopenharmony_ci	netif_start_queue(dev);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	return 0;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ciout_remove_rx_bufs:
96262306a36Sopenharmony_ci	remove_rx_bufs(dev);
96362306a36Sopenharmony_ci	return -EAGAIN;
96462306a36Sopenharmony_ci}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_cistatic void i596_tx_timeout (struct net_device *dev, unsigned int txqueue)
96762306a36Sopenharmony_ci{
96862306a36Sopenharmony_ci	struct i596_private *lp = netdev_priv(dev);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	/* Transmitter timeout, serious problems. */
97162306a36Sopenharmony_ci	DEB(DEB_ERRORS, printk(KERN_DEBUG
97262306a36Sopenharmony_ci			       "%s: transmit timed out, status resetting.\n",
97362306a36Sopenharmony_ci			       dev->name));
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	dev->stats.tx_errors++;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	/* Try to restart the adaptor */
97862306a36Sopenharmony_ci	if (lp->last_restart == dev->stats.tx_packets) {
97962306a36Sopenharmony_ci		DEB(DEB_ERRORS, printk(KERN_DEBUG "Resetting board.\n"));
98062306a36Sopenharmony_ci		/* Shutdown and restart */
98162306a36Sopenharmony_ci		i596_reset (dev, lp);
98262306a36Sopenharmony_ci	} else {
98362306a36Sopenharmony_ci		/* Issue a channel attention signal */
98462306a36Sopenharmony_ci		DEB(DEB_ERRORS, printk(KERN_DEBUG "Kicking board.\n"));
98562306a36Sopenharmony_ci		lp->dma->scb.command = SWAP16(CUC_START | RX_START);
98662306a36Sopenharmony_ci		dma_sync_dev(dev, &(lp->dma->scb), sizeof(struct i596_scb));
98762306a36Sopenharmony_ci		ca (dev);
98862306a36Sopenharmony_ci		lp->last_restart = dev->stats.tx_packets;
98962306a36Sopenharmony_ci	}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	netif_trans_update(dev); /* prevent tx timeout */
99262306a36Sopenharmony_ci	netif_wake_queue (dev);
99362306a36Sopenharmony_ci}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_cistatic netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
99762306a36Sopenharmony_ci{
99862306a36Sopenharmony_ci	struct i596_private *lp = netdev_priv(dev);
99962306a36Sopenharmony_ci	struct tx_cmd *tx_cmd;
100062306a36Sopenharmony_ci	struct i596_tbd *tbd;
100162306a36Sopenharmony_ci	short length = skb->len;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	DEB(DEB_STARTTX, printk(KERN_DEBUG
100462306a36Sopenharmony_ci				"%s: i596_start_xmit(%x,%p) called\n",
100562306a36Sopenharmony_ci				dev->name, skb->len, skb->data));
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	if (length < ETH_ZLEN) {
100862306a36Sopenharmony_ci		if (skb_padto(skb, ETH_ZLEN))
100962306a36Sopenharmony_ci			return NETDEV_TX_OK;
101062306a36Sopenharmony_ci		length = ETH_ZLEN;
101162306a36Sopenharmony_ci	}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	netif_stop_queue(dev);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	tx_cmd = lp->dma->tx_cmds + lp->next_tx_cmd;
101662306a36Sopenharmony_ci	tbd = lp->dma->tbds + lp->next_tx_cmd;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	if (tx_cmd->cmd.command) {
101962306a36Sopenharmony_ci		DEB(DEB_ERRORS, printk(KERN_DEBUG
102062306a36Sopenharmony_ci				       "%s: xmit ring full, dropping packet.\n",
102162306a36Sopenharmony_ci				       dev->name));
102262306a36Sopenharmony_ci		dev->stats.tx_dropped++;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
102562306a36Sopenharmony_ci	} else {
102662306a36Sopenharmony_ci		if (++lp->next_tx_cmd == TX_RING_SIZE)
102762306a36Sopenharmony_ci			lp->next_tx_cmd = 0;
102862306a36Sopenharmony_ci		tx_cmd->tbd = SWAP32(virt_to_dma(lp, tbd));
102962306a36Sopenharmony_ci		tbd->next = I596_NULL;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci		tx_cmd->cmd.command = SWAP16(CMD_FLEX | CmdTx);
103262306a36Sopenharmony_ci		tx_cmd->skb = skb;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci		tx_cmd->pad = 0;
103562306a36Sopenharmony_ci		tx_cmd->size = 0;
103662306a36Sopenharmony_ci		tbd->pad = 0;
103762306a36Sopenharmony_ci		tbd->size = SWAP16(EOF | length);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci		tx_cmd->dma_addr = dma_map_single(dev->dev.parent, skb->data,
104062306a36Sopenharmony_ci						  skb->len, DMA_TO_DEVICE);
104162306a36Sopenharmony_ci		tbd->data = SWAP32(tx_cmd->dma_addr);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci		DEB(DEB_TXADDR, print_eth(skb->data, "tx-queued"));
104462306a36Sopenharmony_ci		dma_sync_dev(dev, tx_cmd, sizeof(struct tx_cmd));
104562306a36Sopenharmony_ci		dma_sync_dev(dev, tbd, sizeof(struct i596_tbd));
104662306a36Sopenharmony_ci		i596_add_cmd(dev, &tx_cmd->cmd);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci		dev->stats.tx_packets++;
104962306a36Sopenharmony_ci		dev->stats.tx_bytes += length;
105062306a36Sopenharmony_ci	}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	netif_start_queue(dev);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	return NETDEV_TX_OK;
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_cistatic void print_eth(unsigned char *add, char *str)
105862306a36Sopenharmony_ci{
105962306a36Sopenharmony_ci	printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n",
106062306a36Sopenharmony_ci	       add, add + 6, add, add[12], add[13], str);
106162306a36Sopenharmony_ci}
106262306a36Sopenharmony_cistatic const struct net_device_ops i596_netdev_ops = {
106362306a36Sopenharmony_ci	.ndo_open		= i596_open,
106462306a36Sopenharmony_ci	.ndo_stop		= i596_close,
106562306a36Sopenharmony_ci	.ndo_start_xmit		= i596_start_xmit,
106662306a36Sopenharmony_ci	.ndo_set_rx_mode	= set_multicast_list,
106762306a36Sopenharmony_ci	.ndo_tx_timeout		= i596_tx_timeout,
106862306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
106962306a36Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
107062306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
107162306a36Sopenharmony_ci	.ndo_poll_controller	= i596_poll_controller,
107262306a36Sopenharmony_ci#endif
107362306a36Sopenharmony_ci};
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_cistatic int i82596_probe(struct net_device *dev)
107662306a36Sopenharmony_ci{
107762306a36Sopenharmony_ci	struct i596_private *lp = netdev_priv(dev);
107862306a36Sopenharmony_ci	int ret;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	/* This lot is ensure things have been cache line aligned. */
108162306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct i596_rfd) != 32);
108262306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct i596_rbd) &  31);
108362306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct tx_cmd)   &  31);
108462306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct i596_tbd) != 32);
108562306a36Sopenharmony_ci#ifndef __LP64__
108662306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct i596_dma) > 4096);
108762306a36Sopenharmony_ci#endif
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	if (!dev->base_addr || !dev->irq)
109062306a36Sopenharmony_ci		return -ENODEV;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	dev->netdev_ops = &i596_netdev_ops;
109362306a36Sopenharmony_ci	dev->watchdog_timeo = TX_TIMEOUT;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	memset(lp->dma, 0, sizeof(struct i596_dma));
109662306a36Sopenharmony_ci	lp->dma->scb.command = 0;
109762306a36Sopenharmony_ci	lp->dma->scb.cmd = I596_NULL;
109862306a36Sopenharmony_ci	lp->dma->scb.rfd = I596_NULL;
109962306a36Sopenharmony_ci	spin_lock_init(&lp->lock);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	dma_sync_dev(dev, lp->dma, sizeof(struct i596_dma));
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	ret = register_netdev(dev);
110462306a36Sopenharmony_ci	if (ret)
110562306a36Sopenharmony_ci		return ret;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx, %pM IRQ %d.\n",
110862306a36Sopenharmony_ci			      dev->name, dev->base_addr, dev->dev_addr,
110962306a36Sopenharmony_ci			      dev->irq));
111062306a36Sopenharmony_ci	DEB(DEB_INIT, printk(KERN_INFO
111162306a36Sopenharmony_ci			     "%s: dma at 0x%p (%d bytes), lp->scb at 0x%p\n",
111262306a36Sopenharmony_ci			     dev->name, lp->dma, (int)sizeof(struct i596_dma),
111362306a36Sopenharmony_ci			     &lp->dma->scb));
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	return 0;
111662306a36Sopenharmony_ci}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
111962306a36Sopenharmony_cistatic void i596_poll_controller(struct net_device *dev)
112062306a36Sopenharmony_ci{
112162306a36Sopenharmony_ci	disable_irq(dev->irq);
112262306a36Sopenharmony_ci	i596_interrupt(dev->irq, dev);
112362306a36Sopenharmony_ci	enable_irq(dev->irq);
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci#endif
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_cistatic irqreturn_t i596_interrupt(int irq, void *dev_id)
112862306a36Sopenharmony_ci{
112962306a36Sopenharmony_ci	struct net_device *dev = dev_id;
113062306a36Sopenharmony_ci	struct i596_private *lp;
113162306a36Sopenharmony_ci	struct i596_dma *dma;
113262306a36Sopenharmony_ci	unsigned short status, ack_cmd = 0;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	lp = netdev_priv(dev);
113562306a36Sopenharmony_ci	dma = lp->dma;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	spin_lock (&lp->lock);
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
114062306a36Sopenharmony_ci	status = SWAP16(dma->scb.status);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	DEB(DEB_INTS, printk(KERN_DEBUG
114362306a36Sopenharmony_ci			     "%s: i596 interrupt, IRQ %d, status %4.4x.\n",
114462306a36Sopenharmony_ci			dev->name, dev->irq, status));
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	ack_cmd = status & 0xf000;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	if (!ack_cmd) {
114962306a36Sopenharmony_ci		DEB(DEB_ERRORS, printk(KERN_DEBUG
115062306a36Sopenharmony_ci				       "%s: interrupt with no events\n",
115162306a36Sopenharmony_ci				       dev->name));
115262306a36Sopenharmony_ci		spin_unlock (&lp->lock);
115362306a36Sopenharmony_ci		return IRQ_NONE;
115462306a36Sopenharmony_ci	}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	if ((status & 0x8000) || (status & 0x2000)) {
115762306a36Sopenharmony_ci		struct i596_cmd *ptr;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci		if ((status & 0x8000))
116062306a36Sopenharmony_ci			DEB(DEB_INTS,
116162306a36Sopenharmony_ci			    printk(KERN_DEBUG
116262306a36Sopenharmony_ci				   "%s: i596 interrupt completed command.\n",
116362306a36Sopenharmony_ci				   dev->name));
116462306a36Sopenharmony_ci		if ((status & 0x2000))
116562306a36Sopenharmony_ci			DEB(DEB_INTS,
116662306a36Sopenharmony_ci			    printk(KERN_DEBUG
116762306a36Sopenharmony_ci				   "%s: i596 interrupt command unit inactive %x.\n",
116862306a36Sopenharmony_ci				   dev->name, status & 0x0700));
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci		while (lp->cmd_head != NULL) {
117162306a36Sopenharmony_ci			dma_sync_cpu(dev, lp->cmd_head, sizeof(struct i596_cmd));
117262306a36Sopenharmony_ci			if (!(lp->cmd_head->status & SWAP16(STAT_C)))
117362306a36Sopenharmony_ci				break;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci			ptr = lp->cmd_head;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci			DEB(DEB_STATUS,
117862306a36Sopenharmony_ci			    printk(KERN_DEBUG
117962306a36Sopenharmony_ci				   "cmd_head->status = %04x, ->command = %04x\n",
118062306a36Sopenharmony_ci				   SWAP16(lp->cmd_head->status),
118162306a36Sopenharmony_ci				   SWAP16(lp->cmd_head->command)));
118262306a36Sopenharmony_ci			lp->cmd_head = ptr->v_next;
118362306a36Sopenharmony_ci			lp->cmd_backlog--;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci			switch (SWAP16(ptr->command) & 0x7) {
118662306a36Sopenharmony_ci			case CmdTx:
118762306a36Sopenharmony_ci			    {
118862306a36Sopenharmony_ci				struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
118962306a36Sopenharmony_ci				struct sk_buff *skb = tx_cmd->skb;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci				if (ptr->status & SWAP16(STAT_OK)) {
119262306a36Sopenharmony_ci					DEB(DEB_TXADDR,
119362306a36Sopenharmony_ci					    print_eth(skb->data, "tx-done"));
119462306a36Sopenharmony_ci				} else {
119562306a36Sopenharmony_ci					dev->stats.tx_errors++;
119662306a36Sopenharmony_ci					if (ptr->status & SWAP16(0x0020))
119762306a36Sopenharmony_ci						dev->stats.collisions++;
119862306a36Sopenharmony_ci					if (!(ptr->status & SWAP16(0x0040)))
119962306a36Sopenharmony_ci						dev->stats.tx_heartbeat_errors++;
120062306a36Sopenharmony_ci					if (ptr->status & SWAP16(0x0400))
120162306a36Sopenharmony_ci						dev->stats.tx_carrier_errors++;
120262306a36Sopenharmony_ci					if (ptr->status & SWAP16(0x0800))
120362306a36Sopenharmony_ci						dev->stats.collisions++;
120462306a36Sopenharmony_ci					if (ptr->status & SWAP16(0x1000))
120562306a36Sopenharmony_ci						dev->stats.tx_aborted_errors++;
120662306a36Sopenharmony_ci				}
120762306a36Sopenharmony_ci				dma_unmap_single(dev->dev.parent,
120862306a36Sopenharmony_ci						 tx_cmd->dma_addr,
120962306a36Sopenharmony_ci						 skb->len, DMA_TO_DEVICE);
121062306a36Sopenharmony_ci				dev_consume_skb_irq(skb);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci				tx_cmd->cmd.command = 0; /* Mark free */
121362306a36Sopenharmony_ci				break;
121462306a36Sopenharmony_ci			    }
121562306a36Sopenharmony_ci			case CmdTDR:
121662306a36Sopenharmony_ci			    {
121762306a36Sopenharmony_ci				unsigned short status = SWAP16(((struct tdr_cmd *)ptr)->status);
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci				if (status & 0x8000) {
122062306a36Sopenharmony_ci					DEB(DEB_ANY,
122162306a36Sopenharmony_ci					    printk(KERN_DEBUG "%s: link ok.\n",
122262306a36Sopenharmony_ci						   dev->name));
122362306a36Sopenharmony_ci				} else {
122462306a36Sopenharmony_ci					if (status & 0x4000)
122562306a36Sopenharmony_ci						printk(KERN_ERR
122662306a36Sopenharmony_ci						       "%s: Transceiver problem.\n",
122762306a36Sopenharmony_ci						       dev->name);
122862306a36Sopenharmony_ci					if (status & 0x2000)
122962306a36Sopenharmony_ci						printk(KERN_ERR
123062306a36Sopenharmony_ci						       "%s: Termination problem.\n",
123162306a36Sopenharmony_ci						       dev->name);
123262306a36Sopenharmony_ci					if (status & 0x1000)
123362306a36Sopenharmony_ci						printk(KERN_ERR
123462306a36Sopenharmony_ci						       "%s: Short circuit.\n",
123562306a36Sopenharmony_ci						       dev->name);
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci					DEB(DEB_TDR,
123862306a36Sopenharmony_ci					    printk(KERN_DEBUG "%s: Time %d.\n",
123962306a36Sopenharmony_ci						   dev->name, status & 0x07ff));
124062306a36Sopenharmony_ci				}
124162306a36Sopenharmony_ci				break;
124262306a36Sopenharmony_ci			    }
124362306a36Sopenharmony_ci			case CmdConfigure:
124462306a36Sopenharmony_ci				/*
124562306a36Sopenharmony_ci				 * Zap command so set_multicast_list() know
124662306a36Sopenharmony_ci				 * it is free
124762306a36Sopenharmony_ci				 */
124862306a36Sopenharmony_ci				ptr->command = 0;
124962306a36Sopenharmony_ci				break;
125062306a36Sopenharmony_ci			}
125162306a36Sopenharmony_ci			ptr->v_next = NULL;
125262306a36Sopenharmony_ci			ptr->b_next = I596_NULL;
125362306a36Sopenharmony_ci			dma_sync_dev(dev, ptr, sizeof(struct i596_cmd));
125462306a36Sopenharmony_ci			lp->last_cmd = jiffies;
125562306a36Sopenharmony_ci		}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci		/* This mess is arranging that only the last of any outstanding
125862306a36Sopenharmony_ci		 * commands has the interrupt bit set.  Should probably really
125962306a36Sopenharmony_ci		 * only add to the cmd queue when the CU is stopped.
126062306a36Sopenharmony_ci		 */
126162306a36Sopenharmony_ci		ptr = lp->cmd_head;
126262306a36Sopenharmony_ci		while ((ptr != NULL) && (ptr != lp->cmd_tail)) {
126362306a36Sopenharmony_ci			struct i596_cmd *prev = ptr;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci			ptr->command &= SWAP16(0x1fff);
126662306a36Sopenharmony_ci			ptr = ptr->v_next;
126762306a36Sopenharmony_ci			dma_sync_dev(dev, prev, sizeof(struct i596_cmd));
126862306a36Sopenharmony_ci		}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci		if (lp->cmd_head != NULL)
127162306a36Sopenharmony_ci			ack_cmd |= CUC_START;
127262306a36Sopenharmony_ci		dma->scb.cmd = SWAP32(virt_to_dma(lp, &lp->cmd_head->status));
127362306a36Sopenharmony_ci		dma_sync_dev(dev, &dma->scb, sizeof(struct i596_scb));
127462306a36Sopenharmony_ci	}
127562306a36Sopenharmony_ci	if ((status & 0x1000) || (status & 0x4000)) {
127662306a36Sopenharmony_ci		if ((status & 0x4000))
127762306a36Sopenharmony_ci			DEB(DEB_INTS,
127862306a36Sopenharmony_ci			    printk(KERN_DEBUG
127962306a36Sopenharmony_ci				   "%s: i596 interrupt received a frame.\n",
128062306a36Sopenharmony_ci				   dev->name));
128162306a36Sopenharmony_ci		i596_rx(dev);
128262306a36Sopenharmony_ci		/* Only RX_START if stopped - RGH 07-07-96 */
128362306a36Sopenharmony_ci		if (status & 0x1000) {
128462306a36Sopenharmony_ci			if (netif_running(dev)) {
128562306a36Sopenharmony_ci				DEB(DEB_ERRORS,
128662306a36Sopenharmony_ci				    printk(KERN_DEBUG
128762306a36Sopenharmony_ci					   "%s: i596 interrupt receive unit inactive, status 0x%x\n",
128862306a36Sopenharmony_ci					   dev->name, status));
128962306a36Sopenharmony_ci				ack_cmd |= RX_START;
129062306a36Sopenharmony_ci				dev->stats.rx_errors++;
129162306a36Sopenharmony_ci				dev->stats.rx_fifo_errors++;
129262306a36Sopenharmony_ci				rebuild_rx_bufs(dev);
129362306a36Sopenharmony_ci			}
129462306a36Sopenharmony_ci		}
129562306a36Sopenharmony_ci	}
129662306a36Sopenharmony_ci	wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
129762306a36Sopenharmony_ci	dma->scb.command = SWAP16(ack_cmd);
129862306a36Sopenharmony_ci	dma_sync_dev(dev, &dma->scb, sizeof(struct i596_scb));
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	/* DANGER: I suspect that some kind of interrupt
130162306a36Sopenharmony_ci	 acknowledgement aside from acking the 82596 might be needed
130262306a36Sopenharmony_ci	 here...  but it's running acceptably without */
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	ca(dev);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	wait_cmd(dev, dma, 100, "i596 interrupt, exit timeout");
130762306a36Sopenharmony_ci	DEB(DEB_INTS, printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name));
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	spin_unlock (&lp->lock);
131062306a36Sopenharmony_ci	return IRQ_HANDLED;
131162306a36Sopenharmony_ci}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_cistatic int i596_close(struct net_device *dev)
131462306a36Sopenharmony_ci{
131562306a36Sopenharmony_ci	struct i596_private *lp = netdev_priv(dev);
131662306a36Sopenharmony_ci	unsigned long flags;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	netif_stop_queue(dev);
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	DEB(DEB_INIT,
132162306a36Sopenharmony_ci	    printk(KERN_DEBUG
132262306a36Sopenharmony_ci		   "%s: Shutting down ethercard, status was %4.4x.\n",
132362306a36Sopenharmony_ci		   dev->name, SWAP16(lp->dma->scb.status)));
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	spin_lock_irqsave(&lp->lock, flags);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	wait_cmd(dev, lp->dma, 100, "close1 timed out");
132862306a36Sopenharmony_ci	lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
132962306a36Sopenharmony_ci	dma_sync_dev(dev, &lp->dma->scb, sizeof(struct i596_scb));
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	ca(dev);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	wait_cmd(dev, lp->dma, 100, "close2 timed out");
133462306a36Sopenharmony_ci	spin_unlock_irqrestore(&lp->lock, flags);
133562306a36Sopenharmony_ci	DEB(DEB_STRUCT, i596_display_data(dev));
133662306a36Sopenharmony_ci	i596_cleanup_cmd(dev, lp);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	free_irq(dev->irq, dev);
133962306a36Sopenharmony_ci	remove_rx_bufs(dev);
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	return 0;
134262306a36Sopenharmony_ci}
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci/*
134562306a36Sopenharmony_ci *    Set or clear the multicast filter for this adaptor.
134662306a36Sopenharmony_ci */
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_cistatic void set_multicast_list(struct net_device *dev)
134962306a36Sopenharmony_ci{
135062306a36Sopenharmony_ci	struct i596_private *lp = netdev_priv(dev);
135162306a36Sopenharmony_ci	struct i596_dma *dma = lp->dma;
135262306a36Sopenharmony_ci	int config = 0, cnt;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	DEB(DEB_MULTI,
135562306a36Sopenharmony_ci	    printk(KERN_DEBUG
135662306a36Sopenharmony_ci		   "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
135762306a36Sopenharmony_ci		   dev->name, netdev_mc_count(dev),
135862306a36Sopenharmony_ci		   dev->flags & IFF_PROMISC ? "ON" : "OFF",
135962306a36Sopenharmony_ci		   dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	if ((dev->flags & IFF_PROMISC) &&
136262306a36Sopenharmony_ci	    !(dma->cf_cmd.i596_config[8] & 0x01)) {
136362306a36Sopenharmony_ci		dma->cf_cmd.i596_config[8] |= 0x01;
136462306a36Sopenharmony_ci		config = 1;
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci	if (!(dev->flags & IFF_PROMISC) &&
136762306a36Sopenharmony_ci	    (dma->cf_cmd.i596_config[8] & 0x01)) {
136862306a36Sopenharmony_ci		dma->cf_cmd.i596_config[8] &= ~0x01;
136962306a36Sopenharmony_ci		config = 1;
137062306a36Sopenharmony_ci	}
137162306a36Sopenharmony_ci	if ((dev->flags & IFF_ALLMULTI) &&
137262306a36Sopenharmony_ci	    (dma->cf_cmd.i596_config[11] & 0x20)) {
137362306a36Sopenharmony_ci		dma->cf_cmd.i596_config[11] &= ~0x20;
137462306a36Sopenharmony_ci		config = 1;
137562306a36Sopenharmony_ci	}
137662306a36Sopenharmony_ci	if (!(dev->flags & IFF_ALLMULTI) &&
137762306a36Sopenharmony_ci	    !(dma->cf_cmd.i596_config[11] & 0x20)) {
137862306a36Sopenharmony_ci		dma->cf_cmd.i596_config[11] |= 0x20;
137962306a36Sopenharmony_ci		config = 1;
138062306a36Sopenharmony_ci	}
138162306a36Sopenharmony_ci	if (config) {
138262306a36Sopenharmony_ci		if (dma->cf_cmd.cmd.command)
138362306a36Sopenharmony_ci			printk(KERN_INFO
138462306a36Sopenharmony_ci			       "%s: config change request already queued\n",
138562306a36Sopenharmony_ci			       dev->name);
138662306a36Sopenharmony_ci		else {
138762306a36Sopenharmony_ci			dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
138862306a36Sopenharmony_ci			dma_sync_dev(dev, &dma->cf_cmd, sizeof(struct cf_cmd));
138962306a36Sopenharmony_ci			i596_add_cmd(dev, &dma->cf_cmd.cmd);
139062306a36Sopenharmony_ci		}
139162306a36Sopenharmony_ci	}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	cnt = netdev_mc_count(dev);
139462306a36Sopenharmony_ci	if (cnt > MAX_MC_CNT) {
139562306a36Sopenharmony_ci		cnt = MAX_MC_CNT;
139662306a36Sopenharmony_ci		printk(KERN_NOTICE "%s: Only %d multicast addresses supported",
139762306a36Sopenharmony_ci			dev->name, cnt);
139862306a36Sopenharmony_ci	}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	if (!netdev_mc_empty(dev)) {
140162306a36Sopenharmony_ci		struct netdev_hw_addr *ha;
140262306a36Sopenharmony_ci		unsigned char *cp;
140362306a36Sopenharmony_ci		struct mc_cmd *cmd;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci		cmd = &dma->mc_cmd;
140662306a36Sopenharmony_ci		cmd->cmd.command = SWAP16(CmdMulticastList);
140762306a36Sopenharmony_ci		cmd->mc_cnt = SWAP16(netdev_mc_count(dev) * 6);
140862306a36Sopenharmony_ci		cp = cmd->mc_addrs;
140962306a36Sopenharmony_ci		netdev_for_each_mc_addr(ha, dev) {
141062306a36Sopenharmony_ci			if (!cnt--)
141162306a36Sopenharmony_ci				break;
141262306a36Sopenharmony_ci			memcpy(cp, ha->addr, ETH_ALEN);
141362306a36Sopenharmony_ci			if (i596_debug > 1)
141462306a36Sopenharmony_ci				DEB(DEB_MULTI,
141562306a36Sopenharmony_ci				    printk(KERN_DEBUG
141662306a36Sopenharmony_ci					   "%s: Adding address %pM\n",
141762306a36Sopenharmony_ci					   dev->name, cp));
141862306a36Sopenharmony_ci			cp += ETH_ALEN;
141962306a36Sopenharmony_ci		}
142062306a36Sopenharmony_ci		dma_sync_dev(dev, &dma->mc_cmd, sizeof(struct mc_cmd));
142162306a36Sopenharmony_ci		i596_add_cmd(dev, &cmd->cmd);
142262306a36Sopenharmony_ci	}
142362306a36Sopenharmony_ci}
1424