xref: /linux/drivers/net/ethernet/8390/axnet_cs.c (revision cdd5b5a9761fd66d17586e4f4ba6588c70e640ea)
1*dc3eb2f4SBagas Sanjaya // SPDX-License-Identifier: GPL-1.0+
2*dc3eb2f4SBagas Sanjaya 
3644570b8SJeff Kirsher /*======================================================================
4644570b8SJeff Kirsher 
5644570b8SJeff Kirsher     A PCMCIA ethernet driver for Asix AX88190-based cards
6644570b8SJeff Kirsher 
7644570b8SJeff Kirsher     The Asix AX88190 is a NS8390-derived chipset with a few nasty
8644570b8SJeff Kirsher     idiosyncracies that make it very inconvenient to support with a
9644570b8SJeff Kirsher     standard 8390 driver.  This driver is based on pcnet_cs, with the
10644570b8SJeff Kirsher     tweaked 8390 code grafted on the end.  Much of what I did was to
11644570b8SJeff Kirsher     clean up and update a similar driver supplied by Asix, which was
12644570b8SJeff Kirsher     adapted by William Lee, william@asix.com.tw.
13644570b8SJeff Kirsher 
14644570b8SJeff Kirsher     Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net
15644570b8SJeff Kirsher 
16644570b8SJeff Kirsher     axnet_cs.c 1.28 2002/06/29 06:27:37
17644570b8SJeff Kirsher 
18644570b8SJeff Kirsher     The network driver code is based on Donald Becker's NE2000 code:
19644570b8SJeff Kirsher 
20644570b8SJeff Kirsher     Written 1992,1993 by Donald Becker.
21644570b8SJeff Kirsher     Copyright 1993 United States Government as represented by the
22*dc3eb2f4SBagas Sanjaya     Director, National Security Agency.
23644570b8SJeff Kirsher     Donald Becker may be reached at becker@scyld.com
24644570b8SJeff Kirsher 
25644570b8SJeff Kirsher ======================================================================*/
26644570b8SJeff Kirsher 
27644570b8SJeff Kirsher #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
28644570b8SJeff Kirsher 
29644570b8SJeff Kirsher #include <linux/kernel.h>
30644570b8SJeff Kirsher #include <linux/module.h>
31644570b8SJeff Kirsher #include <linux/ptrace.h>
32644570b8SJeff Kirsher #include <linux/string.h>
33644570b8SJeff Kirsher #include <linux/timer.h>
34644570b8SJeff Kirsher #include <linux/delay.h>
35644570b8SJeff Kirsher #include <linux/spinlock.h>
36644570b8SJeff Kirsher #include <linux/netdevice.h>
37644570b8SJeff Kirsher #include <linux/etherdevice.h>
38644570b8SJeff Kirsher #include <linux/crc32.h>
39644570b8SJeff Kirsher #include <linux/mii.h>
40644570b8SJeff Kirsher #include "8390.h"
41644570b8SJeff Kirsher 
42644570b8SJeff Kirsher #include <pcmcia/cistpl.h>
43644570b8SJeff Kirsher #include <pcmcia/ciscode.h>
44644570b8SJeff Kirsher #include <pcmcia/ds.h>
45644570b8SJeff Kirsher #include <pcmcia/cisreg.h>
46644570b8SJeff Kirsher 
47644570b8SJeff Kirsher #include <asm/io.h>
48644570b8SJeff Kirsher #include <asm/byteorder.h>
497c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
50644570b8SJeff Kirsher 
51644570b8SJeff Kirsher #define AXNET_CMD	0x00
52644570b8SJeff Kirsher #define AXNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
53644570b8SJeff Kirsher #define AXNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
54644570b8SJeff Kirsher #define AXNET_MII_EEP	0x14	/* Offset of MII access port */
55644570b8SJeff Kirsher #define AXNET_TEST	0x15	/* Offset of TEST Register port */
56644570b8SJeff Kirsher #define AXNET_GPIO	0x17	/* Offset of General Purpose Register Port */
57644570b8SJeff Kirsher 
58644570b8SJeff Kirsher #define AXNET_START_PG	0x40	/* First page of TX buffer */
59644570b8SJeff Kirsher #define AXNET_STOP_PG	0x80	/* Last page +1 of RX ring */
60644570b8SJeff Kirsher 
61644570b8SJeff Kirsher #define AXNET_RDC_TIMEOUT 0x02	/* Max wait in jiffies for Tx RDC */
62644570b8SJeff Kirsher 
63644570b8SJeff Kirsher #define IS_AX88190	0x0001
64644570b8SJeff Kirsher #define IS_AX88790	0x0002
65644570b8SJeff Kirsher 
66644570b8SJeff Kirsher /*====================================================================*/
67644570b8SJeff Kirsher 
68644570b8SJeff Kirsher /* Module parameters */
69644570b8SJeff Kirsher 
70644570b8SJeff Kirsher MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
71644570b8SJeff Kirsher MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver");
72644570b8SJeff Kirsher MODULE_LICENSE("GPL");
73644570b8SJeff Kirsher 
74644570b8SJeff Kirsher 
75644570b8SJeff Kirsher /*====================================================================*/
76644570b8SJeff Kirsher 
77644570b8SJeff Kirsher static int axnet_config(struct pcmcia_device *link);
78644570b8SJeff Kirsher static void axnet_release(struct pcmcia_device *link);
79644570b8SJeff Kirsher static int axnet_open(struct net_device *dev);
80644570b8SJeff Kirsher static int axnet_close(struct net_device *dev);
81644570b8SJeff Kirsher static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
82644570b8SJeff Kirsher static netdev_tx_t axnet_start_xmit(struct sk_buff *skb,
83644570b8SJeff Kirsher 					  struct net_device *dev);
84644570b8SJeff Kirsher static struct net_device_stats *get_stats(struct net_device *dev);
85644570b8SJeff Kirsher static void set_multicast_list(struct net_device *dev);
860290bd29SMichael S. Tsirkin static void axnet_tx_timeout(struct net_device *dev, unsigned int txqueue);
87644570b8SJeff Kirsher static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
88c63144e4SKees Cook static void ei_watchdog(struct timer_list *t);
89644570b8SJeff Kirsher static void axnet_reset_8390(struct net_device *dev);
90644570b8SJeff Kirsher 
91644570b8SJeff Kirsher static int mdio_read(unsigned int addr, int phy_id, int loc);
92644570b8SJeff Kirsher static void mdio_write(unsigned int addr, int phy_id, int loc, int value);
93644570b8SJeff Kirsher 
94644570b8SJeff Kirsher static void get_8390_hdr(struct net_device *,
95644570b8SJeff Kirsher 			 struct e8390_pkt_hdr *, int);
96644570b8SJeff Kirsher static void block_input(struct net_device *dev, int count,
97644570b8SJeff Kirsher 			struct sk_buff *skb, int ring_offset);
98644570b8SJeff Kirsher static void block_output(struct net_device *dev, int count,
99644570b8SJeff Kirsher 			 const u_char *buf, const int start_page);
100644570b8SJeff Kirsher 
101644570b8SJeff Kirsher static void axnet_detach(struct pcmcia_device *p_dev);
102644570b8SJeff Kirsher 
103644570b8SJeff Kirsher static void AX88190_init(struct net_device *dev, int startp);
104644570b8SJeff Kirsher static int ax_open(struct net_device *dev);
105644570b8SJeff Kirsher static int ax_close(struct net_device *dev);
106644570b8SJeff Kirsher static irqreturn_t ax_interrupt(int irq, void *dev_id);
107644570b8SJeff Kirsher 
108644570b8SJeff Kirsher /*====================================================================*/
109644570b8SJeff Kirsher 
110abac0d3fSHimangi Saraogi struct axnet_dev {
111644570b8SJeff Kirsher 	struct pcmcia_device	*p_dev;
112644570b8SJeff Kirsher 	caddr_t	base;
113644570b8SJeff Kirsher 	struct timer_list	watchdog;
114644570b8SJeff Kirsher 	int	stale, fast_poll;
115644570b8SJeff Kirsher 	u_short	link_status;
116644570b8SJeff Kirsher 	u_char	duplex_flag;
117644570b8SJeff Kirsher 	int	phy_id;
118644570b8SJeff Kirsher 	int	flags;
119644570b8SJeff Kirsher 	int	active_low;
120abac0d3fSHimangi Saraogi };
121644570b8SJeff Kirsher 
PRIV(struct net_device * dev)122abac0d3fSHimangi Saraogi static inline struct axnet_dev *PRIV(struct net_device *dev)
123644570b8SJeff Kirsher {
124644570b8SJeff Kirsher 	void *p = (char *)netdev_priv(dev) + sizeof(struct ei_device);
125644570b8SJeff Kirsher 	return p;
126644570b8SJeff Kirsher }
127644570b8SJeff Kirsher 
128644570b8SJeff Kirsher static const struct net_device_ops axnet_netdev_ops = {
129644570b8SJeff Kirsher 	.ndo_open 		= axnet_open,
130644570b8SJeff Kirsher 	.ndo_stop		= axnet_close,
131a7605370SArnd Bergmann 	.ndo_eth_ioctl		= axnet_ioctl,
132644570b8SJeff Kirsher 	.ndo_start_xmit		= axnet_start_xmit,
133644570b8SJeff Kirsher 	.ndo_tx_timeout		= axnet_tx_timeout,
134644570b8SJeff Kirsher 	.ndo_get_stats		= get_stats,
135afc4b13dSJiri Pirko 	.ndo_set_rx_mode	= set_multicast_list,
136644570b8SJeff Kirsher 	.ndo_set_mac_address 	= eth_mac_addr,
137644570b8SJeff Kirsher 	.ndo_validate_addr	= eth_validate_addr,
138644570b8SJeff Kirsher };
139644570b8SJeff Kirsher 
axnet_probe(struct pcmcia_device * link)140644570b8SJeff Kirsher static int axnet_probe(struct pcmcia_device *link)
141644570b8SJeff Kirsher {
142abac0d3fSHimangi Saraogi     struct axnet_dev *info;
143644570b8SJeff Kirsher     struct net_device *dev;
144644570b8SJeff Kirsher     struct ei_device *ei_local;
145644570b8SJeff Kirsher 
146644570b8SJeff Kirsher     dev_dbg(&link->dev, "axnet_attach()\n");
147644570b8SJeff Kirsher 
148abac0d3fSHimangi Saraogi     dev = alloc_etherdev(sizeof(struct ei_device) + sizeof(struct axnet_dev));
149644570b8SJeff Kirsher     if (!dev)
150644570b8SJeff Kirsher 	return -ENOMEM;
151644570b8SJeff Kirsher 
152644570b8SJeff Kirsher     ei_local = netdev_priv(dev);
153644570b8SJeff Kirsher     spin_lock_init(&ei_local->page_lock);
154644570b8SJeff Kirsher 
155644570b8SJeff Kirsher     info = PRIV(dev);
156644570b8SJeff Kirsher     info->p_dev = link;
157644570b8SJeff Kirsher     link->priv = dev;
158644570b8SJeff Kirsher     link->config_flags |= CONF_ENABLE_IRQ;
159644570b8SJeff Kirsher 
160644570b8SJeff Kirsher     dev->netdev_ops = &axnet_netdev_ops;
161644570b8SJeff Kirsher 
162644570b8SJeff Kirsher     dev->watchdog_timeo = TX_TIMEOUT;
163644570b8SJeff Kirsher 
164644570b8SJeff Kirsher     return axnet_config(link);
165644570b8SJeff Kirsher } /* axnet_attach */
166644570b8SJeff Kirsher 
axnet_detach(struct pcmcia_device * link)167644570b8SJeff Kirsher static void axnet_detach(struct pcmcia_device *link)
168644570b8SJeff Kirsher {
169644570b8SJeff Kirsher     struct net_device *dev = link->priv;
170644570b8SJeff Kirsher 
171644570b8SJeff Kirsher     dev_dbg(&link->dev, "axnet_detach(0x%p)\n", link);
172644570b8SJeff Kirsher 
173644570b8SJeff Kirsher     unregister_netdev(dev);
174644570b8SJeff Kirsher 
175644570b8SJeff Kirsher     axnet_release(link);
176644570b8SJeff Kirsher 
177644570b8SJeff Kirsher     free_netdev(dev);
178644570b8SJeff Kirsher } /* axnet_detach */
179644570b8SJeff Kirsher 
180644570b8SJeff Kirsher /*======================================================================
181644570b8SJeff Kirsher 
182644570b8SJeff Kirsher     This probes for a card's hardware address by reading the PROM.
183644570b8SJeff Kirsher 
184644570b8SJeff Kirsher ======================================================================*/
185644570b8SJeff Kirsher 
get_prom(struct pcmcia_device * link)186644570b8SJeff Kirsher static int get_prom(struct pcmcia_device *link)
187644570b8SJeff Kirsher {
188644570b8SJeff Kirsher     struct net_device *dev = link->priv;
189644570b8SJeff Kirsher     unsigned int ioaddr = dev->base_addr;
1908ce218b6SJakub Kicinski     u8 addr[ETH_ALEN];
191644570b8SJeff Kirsher     int i, j;
192644570b8SJeff Kirsher 
1933396c782SPaul Gortmaker     /* This is based on drivers/net/ethernet/8390/ne.c */
194644570b8SJeff Kirsher     struct {
195644570b8SJeff Kirsher 	u_char value, offset;
196644570b8SJeff Kirsher     } program_seq[] = {
197644570b8SJeff Kirsher 	{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
198644570b8SJeff Kirsher 	{0x01,	EN0_DCFG},	/* Set word-wide access. */
199644570b8SJeff Kirsher 	{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
200644570b8SJeff Kirsher 	{0x00,	EN0_RCNTHI},
201644570b8SJeff Kirsher 	{0x00,	EN0_IMR},	/* Mask completion irq. */
202644570b8SJeff Kirsher 	{0xFF,	EN0_ISR},
203644570b8SJeff Kirsher 	{E8390_RXOFF|0x40, EN0_RXCR},	/* 0x60  Set to monitor */
204644570b8SJeff Kirsher 	{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
205644570b8SJeff Kirsher 	{0x10,	EN0_RCNTLO},
206644570b8SJeff Kirsher 	{0x00,	EN0_RCNTHI},
207644570b8SJeff Kirsher 	{0x00,	EN0_RSARLO},	/* DMA starting at 0x0400. */
208644570b8SJeff Kirsher 	{0x04,	EN0_RSARHI},
209644570b8SJeff Kirsher 	{E8390_RREAD+E8390_START, E8390_CMD},
210644570b8SJeff Kirsher     };
211644570b8SJeff Kirsher 
212644570b8SJeff Kirsher     /* Not much of a test, but the alternatives are messy */
213644570b8SJeff Kirsher     if (link->config_base != 0x03c0)
214644570b8SJeff Kirsher 	return 0;
215644570b8SJeff Kirsher 
216644570b8SJeff Kirsher     axnet_reset_8390(dev);
217644570b8SJeff Kirsher     mdelay(10);
218644570b8SJeff Kirsher 
219644570b8SJeff Kirsher     for (i = 0; i < ARRAY_SIZE(program_seq); i++)
220644570b8SJeff Kirsher 	outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
221644570b8SJeff Kirsher 
222644570b8SJeff Kirsher     for (i = 0; i < 6; i += 2) {
223644570b8SJeff Kirsher 	j = inw(ioaddr + AXNET_DATAPORT);
2248ce218b6SJakub Kicinski 	addr[i] = j & 0xff;
2258ce218b6SJakub Kicinski 	addr[i+1] = j >> 8;
226644570b8SJeff Kirsher     }
2278ce218b6SJakub Kicinski     eth_hw_addr_set(dev, addr);
2288ce218b6SJakub Kicinski 
229644570b8SJeff Kirsher     return 1;
230644570b8SJeff Kirsher } /* get_prom */
231644570b8SJeff Kirsher 
try_io_port(struct pcmcia_device * link)232644570b8SJeff Kirsher static int try_io_port(struct pcmcia_device *link)
233644570b8SJeff Kirsher {
234644570b8SJeff Kirsher     int j, ret;
235644570b8SJeff Kirsher     link->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
236644570b8SJeff Kirsher     link->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
237644570b8SJeff Kirsher     if (link->resource[0]->end == 32) {
238644570b8SJeff Kirsher 	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
239644570b8SJeff Kirsher 	/* for master/slave multifunction cards */
240644570b8SJeff Kirsher 	if (link->resource[1]->end > 0)
241644570b8SJeff Kirsher 	    link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
242644570b8SJeff Kirsher     } else {
243644570b8SJeff Kirsher 	/* This should be two 16-port windows */
244644570b8SJeff Kirsher 	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
245644570b8SJeff Kirsher 	link->resource[1]->flags |= IO_DATA_PATH_WIDTH_16;
246644570b8SJeff Kirsher     }
247644570b8SJeff Kirsher     if (link->resource[0]->start == 0) {
248644570b8SJeff Kirsher 	for (j = 0; j < 0x400; j += 0x20) {
249644570b8SJeff Kirsher 	    link->resource[0]->start = j ^ 0x300;
250644570b8SJeff Kirsher 	    link->resource[1]->start = (j ^ 0x300) + 0x10;
251644570b8SJeff Kirsher 	    link->io_lines = 16;
252644570b8SJeff Kirsher 	    ret = pcmcia_request_io(link);
253644570b8SJeff Kirsher 	    if (ret == 0)
254644570b8SJeff Kirsher 		    return ret;
255644570b8SJeff Kirsher 	}
256644570b8SJeff Kirsher 	return ret;
257644570b8SJeff Kirsher     } else {
258644570b8SJeff Kirsher 	return pcmcia_request_io(link);
259644570b8SJeff Kirsher     }
260644570b8SJeff Kirsher }
261644570b8SJeff Kirsher 
axnet_configcheck(struct pcmcia_device * p_dev,void * priv_data)262644570b8SJeff Kirsher static int axnet_configcheck(struct pcmcia_device *p_dev, void *priv_data)
263644570b8SJeff Kirsher {
264644570b8SJeff Kirsher 	if (p_dev->config_index == 0)
265644570b8SJeff Kirsher 		return -EINVAL;
266644570b8SJeff Kirsher 
267644570b8SJeff Kirsher 	p_dev->config_index = 0x05;
268644570b8SJeff Kirsher 	if (p_dev->resource[0]->end + p_dev->resource[1]->end < 32)
269644570b8SJeff Kirsher 		return -ENODEV;
270644570b8SJeff Kirsher 
271644570b8SJeff Kirsher 	return try_io_port(p_dev);
272644570b8SJeff Kirsher }
273644570b8SJeff Kirsher 
axnet_config(struct pcmcia_device * link)274644570b8SJeff Kirsher static int axnet_config(struct pcmcia_device *link)
275644570b8SJeff Kirsher {
276644570b8SJeff Kirsher     struct net_device *dev = link->priv;
277abac0d3fSHimangi Saraogi     struct axnet_dev *info = PRIV(dev);
278644570b8SJeff Kirsher     int i, j, j2, ret;
279644570b8SJeff Kirsher 
280644570b8SJeff Kirsher     dev_dbg(&link->dev, "axnet_config(0x%p)\n", link);
281644570b8SJeff Kirsher 
282644570b8SJeff Kirsher     /* don't trust the CIS on this; Linksys got it wrong */
283644570b8SJeff Kirsher     link->config_regs = 0x63;
284644570b8SJeff Kirsher     link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
285644570b8SJeff Kirsher     ret = pcmcia_loop_config(link, axnet_configcheck, NULL);
286644570b8SJeff Kirsher     if (ret != 0)
287644570b8SJeff Kirsher 	goto failed;
288644570b8SJeff Kirsher 
289644570b8SJeff Kirsher     if (!link->irq)
290644570b8SJeff Kirsher 	    goto failed;
291644570b8SJeff Kirsher 
292644570b8SJeff Kirsher     if (resource_size(link->resource[1]) == 8)
293644570b8SJeff Kirsher 	link->config_flags |= CONF_ENABLE_SPKR;
294644570b8SJeff Kirsher 
295644570b8SJeff Kirsher     ret = pcmcia_enable_device(link);
296644570b8SJeff Kirsher     if (ret)
297644570b8SJeff Kirsher 	    goto failed;
298644570b8SJeff Kirsher 
299644570b8SJeff Kirsher     dev->irq = link->irq;
300644570b8SJeff Kirsher     dev->base_addr = link->resource[0]->start;
301644570b8SJeff Kirsher 
302644570b8SJeff Kirsher     if (!get_prom(link)) {
303644570b8SJeff Kirsher 	pr_notice("this is not an AX88190 card!\n");
304644570b8SJeff Kirsher 	pr_notice("use pcnet_cs instead.\n");
305644570b8SJeff Kirsher 	goto failed;
306644570b8SJeff Kirsher     }
307644570b8SJeff Kirsher 
308644570b8SJeff Kirsher     ei_status.name = "AX88190";
309644570b8SJeff Kirsher     ei_status.word16 = 1;
310644570b8SJeff Kirsher     ei_status.tx_start_page = AXNET_START_PG;
311644570b8SJeff Kirsher     ei_status.rx_start_page = AXNET_START_PG + TX_PAGES;
312644570b8SJeff Kirsher     ei_status.stop_page = AXNET_STOP_PG;
313644570b8SJeff Kirsher     ei_status.reset_8390 = axnet_reset_8390;
314644570b8SJeff Kirsher     ei_status.get_8390_hdr = get_8390_hdr;
315644570b8SJeff Kirsher     ei_status.block_input = block_input;
316644570b8SJeff Kirsher     ei_status.block_output = block_output;
317644570b8SJeff Kirsher 
318644570b8SJeff Kirsher     if (inb(dev->base_addr + AXNET_TEST) != 0)
319644570b8SJeff Kirsher 	info->flags |= IS_AX88790;
320644570b8SJeff Kirsher     else
321644570b8SJeff Kirsher 	info->flags |= IS_AX88190;
322644570b8SJeff Kirsher 
323644570b8SJeff Kirsher     if (info->flags & IS_AX88790)
324644570b8SJeff Kirsher 	outb(0x10, dev->base_addr + AXNET_GPIO);  /* select Internal PHY */
325644570b8SJeff Kirsher 
326644570b8SJeff Kirsher     info->active_low = 0;
327644570b8SJeff Kirsher 
328644570b8SJeff Kirsher     for (i = 0; i < 32; i++) {
329644570b8SJeff Kirsher 	j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
330644570b8SJeff Kirsher 	j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2);
331644570b8SJeff Kirsher 	if (j == j2) continue;
332644570b8SJeff Kirsher 	if ((j != 0) && (j != 0xffff)) break;
333644570b8SJeff Kirsher     }
334644570b8SJeff Kirsher 
335644570b8SJeff Kirsher     if (i == 32) {
336644570b8SJeff Kirsher 	/* Maybe PHY is in power down mode. (PPD_SET = 1)
337644570b8SJeff Kirsher 	   Bit 2 of CCSR is active low. */
338644570b8SJeff Kirsher 	pcmcia_write_config_byte(link, CISREG_CCSR, 0x04);
339644570b8SJeff Kirsher 	for (i = 0; i < 32; i++) {
340644570b8SJeff Kirsher 	    j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
341644570b8SJeff Kirsher 	    j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2);
342644570b8SJeff Kirsher 	    if (j == j2) continue;
343644570b8SJeff Kirsher 	    if ((j != 0) && (j != 0xffff)) {
344644570b8SJeff Kirsher 		info->active_low = 1;
345644570b8SJeff Kirsher 		break;
346644570b8SJeff Kirsher 	    }
347644570b8SJeff Kirsher 	}
348644570b8SJeff Kirsher     }
349644570b8SJeff Kirsher 
350644570b8SJeff Kirsher     info->phy_id = (i < 32) ? i : -1;
351644570b8SJeff Kirsher     SET_NETDEV_DEV(dev, &link->dev);
352644570b8SJeff Kirsher 
353644570b8SJeff Kirsher     if (register_netdev(dev) != 0) {
354644570b8SJeff Kirsher 	pr_notice("register_netdev() failed\n");
355644570b8SJeff Kirsher 	goto failed;
356644570b8SJeff Kirsher     }
357644570b8SJeff Kirsher 
358644570b8SJeff Kirsher     netdev_info(dev, "Asix AX88%d90: io %#3lx, irq %d, hw_addr %pM\n",
359644570b8SJeff Kirsher 		((info->flags & IS_AX88790) ? 7 : 1),
360644570b8SJeff Kirsher 		dev->base_addr, dev->irq, dev->dev_addr);
361644570b8SJeff Kirsher     if (info->phy_id != -1) {
362644570b8SJeff Kirsher 	netdev_dbg(dev, "  MII transceiver at index %d, status %x\n",
363644570b8SJeff Kirsher 		   info->phy_id, j);
364644570b8SJeff Kirsher     } else {
365644570b8SJeff Kirsher 	netdev_notice(dev, "  No MII transceivers found!\n");
366644570b8SJeff Kirsher     }
367644570b8SJeff Kirsher     return 0;
368644570b8SJeff Kirsher 
369644570b8SJeff Kirsher failed:
370644570b8SJeff Kirsher     axnet_release(link);
371644570b8SJeff Kirsher     return -ENODEV;
372644570b8SJeff Kirsher } /* axnet_config */
373644570b8SJeff Kirsher 
axnet_release(struct pcmcia_device * link)374644570b8SJeff Kirsher static void axnet_release(struct pcmcia_device *link)
375644570b8SJeff Kirsher {
376644570b8SJeff Kirsher 	pcmcia_disable_device(link);
377644570b8SJeff Kirsher }
378644570b8SJeff Kirsher 
axnet_suspend(struct pcmcia_device * link)379644570b8SJeff Kirsher static int axnet_suspend(struct pcmcia_device *link)
380644570b8SJeff Kirsher {
381644570b8SJeff Kirsher 	struct net_device *dev = link->priv;
382644570b8SJeff Kirsher 
383644570b8SJeff Kirsher 	if (link->open)
384644570b8SJeff Kirsher 		netif_device_detach(dev);
385644570b8SJeff Kirsher 
386644570b8SJeff Kirsher 	return 0;
387644570b8SJeff Kirsher }
388644570b8SJeff Kirsher 
axnet_resume(struct pcmcia_device * link)389644570b8SJeff Kirsher static int axnet_resume(struct pcmcia_device *link)
390644570b8SJeff Kirsher {
391644570b8SJeff Kirsher 	struct net_device *dev = link->priv;
392abac0d3fSHimangi Saraogi 	struct axnet_dev *info = PRIV(dev);
393644570b8SJeff Kirsher 
394644570b8SJeff Kirsher 	if (link->open) {
395644570b8SJeff Kirsher 		if (info->active_low == 1)
396644570b8SJeff Kirsher 			pcmcia_write_config_byte(link, CISREG_CCSR, 0x04);
397644570b8SJeff Kirsher 
398644570b8SJeff Kirsher 		axnet_reset_8390(dev);
399644570b8SJeff Kirsher 		AX88190_init(dev, 1);
400644570b8SJeff Kirsher 		netif_device_attach(dev);
401644570b8SJeff Kirsher 	}
402644570b8SJeff Kirsher 
403644570b8SJeff Kirsher 	return 0;
404644570b8SJeff Kirsher }
405644570b8SJeff Kirsher 
406644570b8SJeff Kirsher 
407644570b8SJeff Kirsher /*======================================================================
408644570b8SJeff Kirsher 
409644570b8SJeff Kirsher     MII interface support
410644570b8SJeff Kirsher 
411644570b8SJeff Kirsher ======================================================================*/
412644570b8SJeff Kirsher 
413644570b8SJeff Kirsher #define MDIO_SHIFT_CLK		0x01
414644570b8SJeff Kirsher #define MDIO_DATA_WRITE0	0x00
415644570b8SJeff Kirsher #define MDIO_DATA_WRITE1	0x08
416644570b8SJeff Kirsher #define MDIO_DATA_READ		0x04
417644570b8SJeff Kirsher #define MDIO_MASK		0x0f
418644570b8SJeff Kirsher #define MDIO_ENB_IN		0x02
419644570b8SJeff Kirsher 
mdio_sync(unsigned int addr)420644570b8SJeff Kirsher static void mdio_sync(unsigned int addr)
421644570b8SJeff Kirsher {
422644570b8SJeff Kirsher     int bits;
423644570b8SJeff Kirsher     for (bits = 0; bits < 32; bits++) {
424644570b8SJeff Kirsher 	outb_p(MDIO_DATA_WRITE1, addr);
425644570b8SJeff Kirsher 	outb_p(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
426644570b8SJeff Kirsher     }
427644570b8SJeff Kirsher }
428644570b8SJeff Kirsher 
mdio_read(unsigned int addr,int phy_id,int loc)429644570b8SJeff Kirsher static int mdio_read(unsigned int addr, int phy_id, int loc)
430644570b8SJeff Kirsher {
431644570b8SJeff Kirsher     u_int cmd = (0xf6<<10)|(phy_id<<5)|loc;
432644570b8SJeff Kirsher     int i, retval = 0;
433644570b8SJeff Kirsher 
434644570b8SJeff Kirsher     mdio_sync(addr);
435644570b8SJeff Kirsher     for (i = 14; i >= 0; i--) {
436644570b8SJeff Kirsher 	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
437644570b8SJeff Kirsher 	outb_p(dat, addr);
438644570b8SJeff Kirsher 	outb_p(dat | MDIO_SHIFT_CLK, addr);
439644570b8SJeff Kirsher     }
440644570b8SJeff Kirsher     for (i = 19; i > 0; i--) {
441644570b8SJeff Kirsher 	outb_p(MDIO_ENB_IN, addr);
442644570b8SJeff Kirsher 	retval = (retval << 1) | ((inb_p(addr) & MDIO_DATA_READ) != 0);
443644570b8SJeff Kirsher 	outb_p(MDIO_ENB_IN | MDIO_SHIFT_CLK, addr);
444644570b8SJeff Kirsher     }
445644570b8SJeff Kirsher     return (retval>>1) & 0xffff;
446644570b8SJeff Kirsher }
447644570b8SJeff Kirsher 
mdio_write(unsigned int addr,int phy_id,int loc,int value)448644570b8SJeff Kirsher static void mdio_write(unsigned int addr, int phy_id, int loc, int value)
449644570b8SJeff Kirsher {
450644570b8SJeff Kirsher     u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
451644570b8SJeff Kirsher     int i;
452644570b8SJeff Kirsher 
453644570b8SJeff Kirsher     mdio_sync(addr);
454644570b8SJeff Kirsher     for (i = 31; i >= 0; i--) {
455644570b8SJeff Kirsher 	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
456644570b8SJeff Kirsher 	outb_p(dat, addr);
457644570b8SJeff Kirsher 	outb_p(dat | MDIO_SHIFT_CLK, addr);
458644570b8SJeff Kirsher     }
459644570b8SJeff Kirsher     for (i = 1; i >= 0; i--) {
460644570b8SJeff Kirsher 	outb_p(MDIO_ENB_IN, addr);
461644570b8SJeff Kirsher 	outb_p(MDIO_ENB_IN | MDIO_SHIFT_CLK, addr);
462644570b8SJeff Kirsher     }
463644570b8SJeff Kirsher }
464644570b8SJeff Kirsher 
465644570b8SJeff Kirsher /*====================================================================*/
466644570b8SJeff Kirsher 
axnet_open(struct net_device * dev)467644570b8SJeff Kirsher static int axnet_open(struct net_device *dev)
468644570b8SJeff Kirsher {
469644570b8SJeff Kirsher     int ret;
470abac0d3fSHimangi Saraogi     struct axnet_dev *info = PRIV(dev);
471644570b8SJeff Kirsher     struct pcmcia_device *link = info->p_dev;
472644570b8SJeff Kirsher     unsigned int nic_base = dev->base_addr;
473644570b8SJeff Kirsher 
474644570b8SJeff Kirsher     dev_dbg(&link->dev, "axnet_open('%s')\n", dev->name);
475644570b8SJeff Kirsher 
476644570b8SJeff Kirsher     if (!pcmcia_dev_present(link))
477644570b8SJeff Kirsher 	return -ENODEV;
478644570b8SJeff Kirsher 
479644570b8SJeff Kirsher     outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
480644570b8SJeff Kirsher     ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
481644570b8SJeff Kirsher     if (ret)
482644570b8SJeff Kirsher 	    return ret;
483644570b8SJeff Kirsher 
484644570b8SJeff Kirsher     link->open++;
485644570b8SJeff Kirsher 
486644570b8SJeff Kirsher     info->link_status = 0x00;
487c63144e4SKees Cook     timer_setup(&info->watchdog, ei_watchdog, 0);
4886753a971SVaishali Thakkar     mod_timer(&info->watchdog, jiffies + HZ);
489644570b8SJeff Kirsher 
490644570b8SJeff Kirsher     return ax_open(dev);
491644570b8SJeff Kirsher } /* axnet_open */
492644570b8SJeff Kirsher 
493644570b8SJeff Kirsher /*====================================================================*/
494644570b8SJeff Kirsher 
axnet_close(struct net_device * dev)495644570b8SJeff Kirsher static int axnet_close(struct net_device *dev)
496644570b8SJeff Kirsher {
497abac0d3fSHimangi Saraogi     struct axnet_dev *info = PRIV(dev);
498644570b8SJeff Kirsher     struct pcmcia_device *link = info->p_dev;
499644570b8SJeff Kirsher 
500644570b8SJeff Kirsher     dev_dbg(&link->dev, "axnet_close('%s')\n", dev->name);
501644570b8SJeff Kirsher 
502644570b8SJeff Kirsher     ax_close(dev);
503644570b8SJeff Kirsher     free_irq(dev->irq, dev);
504644570b8SJeff Kirsher 
505644570b8SJeff Kirsher     link->open--;
506644570b8SJeff Kirsher     netif_stop_queue(dev);
507644570b8SJeff Kirsher     del_timer_sync(&info->watchdog);
508644570b8SJeff Kirsher 
509644570b8SJeff Kirsher     return 0;
510644570b8SJeff Kirsher } /* axnet_close */
511644570b8SJeff Kirsher 
512644570b8SJeff Kirsher /*======================================================================
513644570b8SJeff Kirsher 
514644570b8SJeff Kirsher     Hard reset the card.  This used to pause for the same period that
515644570b8SJeff Kirsher     a 8390 reset command required, but that shouldn't be necessary.
516644570b8SJeff Kirsher 
517644570b8SJeff Kirsher ======================================================================*/
518644570b8SJeff Kirsher 
axnet_reset_8390(struct net_device * dev)519644570b8SJeff Kirsher static void axnet_reset_8390(struct net_device *dev)
520644570b8SJeff Kirsher {
521644570b8SJeff Kirsher     unsigned int nic_base = dev->base_addr;
522644570b8SJeff Kirsher     int i;
523644570b8SJeff Kirsher 
524644570b8SJeff Kirsher     ei_status.txing = ei_status.dmaing = 0;
525644570b8SJeff Kirsher 
526644570b8SJeff Kirsher     outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD);
527644570b8SJeff Kirsher 
528644570b8SJeff Kirsher     outb(inb(nic_base + AXNET_RESET), nic_base + AXNET_RESET);
529644570b8SJeff Kirsher 
530644570b8SJeff Kirsher     for (i = 0; i < 100; i++) {
531644570b8SJeff Kirsher 	if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0)
532644570b8SJeff Kirsher 	    break;
533644570b8SJeff Kirsher 	udelay(100);
534644570b8SJeff Kirsher     }
535644570b8SJeff Kirsher     outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
536644570b8SJeff Kirsher 
537644570b8SJeff Kirsher     if (i == 100)
538644570b8SJeff Kirsher 	netdev_err(dev, "axnet_reset_8390() did not complete\n");
539644570b8SJeff Kirsher 
540644570b8SJeff Kirsher } /* axnet_reset_8390 */
541644570b8SJeff Kirsher 
542644570b8SJeff Kirsher /*====================================================================*/
543644570b8SJeff Kirsher 
ei_irq_wrapper(int irq,void * dev_id)544644570b8SJeff Kirsher static irqreturn_t ei_irq_wrapper(int irq, void *dev_id)
545644570b8SJeff Kirsher {
546644570b8SJeff Kirsher     struct net_device *dev = dev_id;
547644570b8SJeff Kirsher     PRIV(dev)->stale = 0;
548644570b8SJeff Kirsher     return ax_interrupt(irq, dev_id);
549644570b8SJeff Kirsher }
550644570b8SJeff Kirsher 
ei_watchdog(struct timer_list * t)551c63144e4SKees Cook static void ei_watchdog(struct timer_list *t)
552644570b8SJeff Kirsher {
553c63144e4SKees Cook     struct axnet_dev *info = from_timer(info, t, watchdog);
554c63144e4SKees Cook     struct net_device *dev = info->p_dev->priv;
555644570b8SJeff Kirsher     unsigned int nic_base = dev->base_addr;
556644570b8SJeff Kirsher     unsigned int mii_addr = nic_base + AXNET_MII_EEP;
557644570b8SJeff Kirsher     u_short link;
558644570b8SJeff Kirsher 
559644570b8SJeff Kirsher     if (!netif_device_present(dev)) goto reschedule;
560644570b8SJeff Kirsher 
561644570b8SJeff Kirsher     /* Check for pending interrupt with expired latency timer: with
562644570b8SJeff Kirsher        this, we can limp along even if the interrupt is blocked */
563644570b8SJeff Kirsher     if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
564644570b8SJeff Kirsher 	if (!info->fast_poll)
565644570b8SJeff Kirsher 	    netdev_info(dev, "interrupt(s) dropped!\n");
566644570b8SJeff Kirsher 	ei_irq_wrapper(dev->irq, dev);
567644570b8SJeff Kirsher 	info->fast_poll = HZ;
568644570b8SJeff Kirsher     }
569644570b8SJeff Kirsher     if (info->fast_poll) {
570644570b8SJeff Kirsher 	info->fast_poll--;
571644570b8SJeff Kirsher 	info->watchdog.expires = jiffies + 1;
572644570b8SJeff Kirsher 	add_timer(&info->watchdog);
573644570b8SJeff Kirsher 	return;
574644570b8SJeff Kirsher     }
575644570b8SJeff Kirsher 
576644570b8SJeff Kirsher     if (info->phy_id < 0)
577644570b8SJeff Kirsher 	goto reschedule;
578644570b8SJeff Kirsher     link = mdio_read(mii_addr, info->phy_id, 1);
579644570b8SJeff Kirsher     if (!link || (link == 0xffff)) {
580644570b8SJeff Kirsher 	netdev_info(dev, "MII is missing!\n");
581644570b8SJeff Kirsher 	info->phy_id = -1;
582644570b8SJeff Kirsher 	goto reschedule;
583644570b8SJeff Kirsher     }
584644570b8SJeff Kirsher 
585644570b8SJeff Kirsher     link &= 0x0004;
586644570b8SJeff Kirsher     if (link != info->link_status) {
587644570b8SJeff Kirsher 	u_short p = mdio_read(mii_addr, info->phy_id, 5);
588644570b8SJeff Kirsher 	netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
589644570b8SJeff Kirsher 	if (link) {
590644570b8SJeff Kirsher 	    info->duplex_flag = (p & 0x0140) ? 0x80 : 0x00;
591644570b8SJeff Kirsher 	    if (p)
592644570b8SJeff Kirsher 		netdev_info(dev, "autonegotiation complete: %dbaseT-%cD selected\n",
593644570b8SJeff Kirsher 			    (p & 0x0180) ? 100 : 10, (p & 0x0140) ? 'F' : 'H');
594644570b8SJeff Kirsher 	    else
595644570b8SJeff Kirsher 		netdev_info(dev, "link partner did not autonegotiate\n");
596644570b8SJeff Kirsher 	    AX88190_init(dev, 1);
597644570b8SJeff Kirsher 	}
598644570b8SJeff Kirsher 	info->link_status = link;
599644570b8SJeff Kirsher     }
600644570b8SJeff Kirsher 
601644570b8SJeff Kirsher reschedule:
602644570b8SJeff Kirsher     info->watchdog.expires = jiffies + HZ;
603644570b8SJeff Kirsher     add_timer(&info->watchdog);
604644570b8SJeff Kirsher }
605644570b8SJeff Kirsher 
606644570b8SJeff Kirsher /*====================================================================*/
607644570b8SJeff Kirsher 
axnet_ioctl(struct net_device * dev,struct ifreq * rq,int cmd)608644570b8SJeff Kirsher static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
609644570b8SJeff Kirsher {
610abac0d3fSHimangi Saraogi     struct axnet_dev *info = PRIV(dev);
611644570b8SJeff Kirsher     struct mii_ioctl_data *data = if_mii(rq);
612644570b8SJeff Kirsher     unsigned int mii_addr = dev->base_addr + AXNET_MII_EEP;
613644570b8SJeff Kirsher     switch (cmd) {
614644570b8SJeff Kirsher     case SIOCGMIIPHY:
615644570b8SJeff Kirsher 	data->phy_id = info->phy_id;
616df561f66SGustavo A. R. Silva 	fallthrough;
617644570b8SJeff Kirsher     case SIOCGMIIREG:		/* Read MII PHY register. */
618644570b8SJeff Kirsher 	data->val_out = mdio_read(mii_addr, data->phy_id, data->reg_num & 0x1f);
619644570b8SJeff Kirsher 	return 0;
620644570b8SJeff Kirsher     case SIOCSMIIREG:		/* Write MII PHY register. */
621644570b8SJeff Kirsher 	mdio_write(mii_addr, data->phy_id, data->reg_num & 0x1f, data->val_in);
622644570b8SJeff Kirsher 	return 0;
623644570b8SJeff Kirsher     }
624644570b8SJeff Kirsher     return -EOPNOTSUPP;
625644570b8SJeff Kirsher }
626644570b8SJeff Kirsher 
627644570b8SJeff Kirsher /*====================================================================*/
628644570b8SJeff Kirsher 
get_8390_hdr(struct net_device * dev,struct e8390_pkt_hdr * hdr,int ring_page)629644570b8SJeff Kirsher static void get_8390_hdr(struct net_device *dev,
630644570b8SJeff Kirsher 			 struct e8390_pkt_hdr *hdr,
631644570b8SJeff Kirsher 			 int ring_page)
632644570b8SJeff Kirsher {
633644570b8SJeff Kirsher     unsigned int nic_base = dev->base_addr;
634644570b8SJeff Kirsher 
635644570b8SJeff Kirsher     outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
636644570b8SJeff Kirsher     outb_p(ring_page, nic_base + EN0_RSARHI);
637644570b8SJeff Kirsher     outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD);
638644570b8SJeff Kirsher 
639644570b8SJeff Kirsher     insw(nic_base + AXNET_DATAPORT, hdr,
640644570b8SJeff Kirsher 	    sizeof(struct e8390_pkt_hdr)>>1);
641644570b8SJeff Kirsher     /* Fix for big endian systems */
642644570b8SJeff Kirsher     hdr->count = le16_to_cpu(hdr->count);
643644570b8SJeff Kirsher 
644644570b8SJeff Kirsher }
645644570b8SJeff Kirsher 
646644570b8SJeff Kirsher /*====================================================================*/
647644570b8SJeff Kirsher 
block_input(struct net_device * dev,int count,struct sk_buff * skb,int ring_offset)648644570b8SJeff Kirsher static void block_input(struct net_device *dev, int count,
649644570b8SJeff Kirsher 			struct sk_buff *skb, int ring_offset)
650644570b8SJeff Kirsher {
651644570b8SJeff Kirsher     unsigned int nic_base = dev->base_addr;
652c45f812fSMatthew Whitehead     struct ei_device *ei_local = netdev_priv(dev);
653644570b8SJeff Kirsher     char *buf = skb->data;
654644570b8SJeff Kirsher 
655c45f812fSMatthew Whitehead     if ((netif_msg_rx_status(ei_local)) && (count != 4))
656c45f812fSMatthew Whitehead 	netdev_dbg(dev, "[bi=%d]\n", count+4);
657644570b8SJeff Kirsher     outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
658644570b8SJeff Kirsher     outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
659644570b8SJeff Kirsher     outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD);
660644570b8SJeff Kirsher 
661644570b8SJeff Kirsher     insw(nic_base + AXNET_DATAPORT,buf,count>>1);
662e7fee115SJoe Perches     if (count & 0x01) {
663e7fee115SJoe Perches 	buf[count-1] = inb(nic_base + AXNET_DATAPORT);
664e7fee115SJoe Perches     }
665644570b8SJeff Kirsher }
666644570b8SJeff Kirsher 
667644570b8SJeff Kirsher /*====================================================================*/
668644570b8SJeff Kirsher 
block_output(struct net_device * dev,int count,const u_char * buf,const int start_page)669644570b8SJeff Kirsher static void block_output(struct net_device *dev, int count,
670644570b8SJeff Kirsher 			 const u_char *buf, const int start_page)
671644570b8SJeff Kirsher {
672644570b8SJeff Kirsher     unsigned int nic_base = dev->base_addr;
673644570b8SJeff Kirsher 
674644570b8SJeff Kirsher     pr_debug("%s: [bo=%d]\n", dev->name, count);
675644570b8SJeff Kirsher 
676644570b8SJeff Kirsher     /* Round the count up for word writes.  Do we need to do this?
677644570b8SJeff Kirsher        What effect will an odd byte count have on the 8390?
678644570b8SJeff Kirsher        I should check someday. */
679644570b8SJeff Kirsher     if (count & 0x01)
680644570b8SJeff Kirsher 	count++;
681644570b8SJeff Kirsher 
682644570b8SJeff Kirsher     outb_p(0x00, nic_base + EN0_RSARLO);
683644570b8SJeff Kirsher     outb_p(start_page, nic_base + EN0_RSARHI);
684644570b8SJeff Kirsher     outb_p(E8390_RWRITE+E8390_START, nic_base + AXNET_CMD);
685644570b8SJeff Kirsher     outsw(nic_base + AXNET_DATAPORT, buf, count>>1);
686644570b8SJeff Kirsher }
687644570b8SJeff Kirsher 
688644570b8SJeff Kirsher static const struct pcmcia_device_id axnet_ids[] = {
689644570b8SJeff Kirsher 	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081),
690644570b8SJeff Kirsher 	PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301),
691644570b8SJeff Kirsher 	PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
692644570b8SJeff Kirsher 	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0301),
693644570b8SJeff Kirsher 	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0303),
694644570b8SJeff Kirsher 	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309),
695644570b8SJeff Kirsher 	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
696644570b8SJeff Kirsher 	PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
697644570b8SJeff Kirsher 	PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202),
698644570b8SJeff Kirsher 	PCMCIA_DEVICE_MANF_CARD(0xffff, 0x1090),
699644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc),
700644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
701644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
702644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("Billionton", "LNA-100B", 0x552ab682, 0xbc3b87e1),
703644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("CHEETAH ETHERCARD", "EN2228", 0x00fa7bc8, 0x00e990cc),
704644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("CNet", "CNF301", 0xbc477dde, 0x78c5f40b),
705644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440f, 0x436768c5),
706644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x5261440f, 0x730df72e),
707644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXM", 0x5261440f, 0x3abbd061),
708644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("Dynalink", "L100C16", 0x55632fd5, 0x66bc2a90),
709644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "ETXPCM", 0x547e66dc, 0x233adac2),
710644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8),
711644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC3-TX", 0x481e0094, 0xf91af609),
712644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA411", 0x9aa79dc3, 0x40fad875),
713644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "100BASE", 0x281f1c5d, 0x7c2add04),
714644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEtherCard", 0x281f1c5d, 0x7ef26116),
715644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FEP501", 0x281f1c5d, 0x2e272058),
716644570b8SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID14("Network Everywhere", "AX88190", 0x820a67b6,  0xab9be5ef),
717644570b8SJeff Kirsher 	PCMCIA_DEVICE_NULL,
718644570b8SJeff Kirsher };
719644570b8SJeff Kirsher MODULE_DEVICE_TABLE(pcmcia, axnet_ids);
720644570b8SJeff Kirsher 
721644570b8SJeff Kirsher static struct pcmcia_driver axnet_cs_driver = {
722644570b8SJeff Kirsher 	.owner		= THIS_MODULE,
723644570b8SJeff Kirsher 	.name		= "axnet_cs",
724644570b8SJeff Kirsher 	.probe		= axnet_probe,
725644570b8SJeff Kirsher 	.remove		= axnet_detach,
726644570b8SJeff Kirsher 	.id_table       = axnet_ids,
727644570b8SJeff Kirsher 	.suspend	= axnet_suspend,
728644570b8SJeff Kirsher 	.resume		= axnet_resume,
729644570b8SJeff Kirsher };
730fdd3f29eSH Hartley Sweeten module_pcmcia_driver(axnet_cs_driver);
731644570b8SJeff Kirsher 
732644570b8SJeff Kirsher /*====================================================================*/
733644570b8SJeff Kirsher 
734644570b8SJeff Kirsher /* 8390.c: A general NS8390 ethernet driver core for linux. */
735644570b8SJeff Kirsher /*
736644570b8SJeff Kirsher 	Written 1992-94 by Donald Becker.
737644570b8SJeff Kirsher 
738644570b8SJeff Kirsher 	Copyright 1993 United States Government as represented by the
739644570b8SJeff Kirsher 	Director, National Security Agency.
740644570b8SJeff Kirsher 
741644570b8SJeff Kirsher 	This software may be used and distributed according to the terms
742644570b8SJeff Kirsher 	of the GNU General Public License, incorporated herein by reference.
743644570b8SJeff Kirsher 
744644570b8SJeff Kirsher 	The author may be reached as becker@scyld.com, or C/O
745644570b8SJeff Kirsher 	Scyld Computing Corporation
746644570b8SJeff Kirsher 	410 Severn Ave., Suite 210
747644570b8SJeff Kirsher 	Annapolis MD 21403
748644570b8SJeff Kirsher 
749644570b8SJeff Kirsher   This is the chip-specific code for many 8390-based ethernet adaptors.
750644570b8SJeff Kirsher   This is not a complete driver, it must be combined with board-specific
751644570b8SJeff Kirsher   code such as ne.c, wd.c, 3c503.c, etc.
752644570b8SJeff Kirsher 
753644570b8SJeff Kirsher   Seeing how at least eight drivers use this code, (not counting the
754644570b8SJeff Kirsher   PCMCIA ones either) it is easy to break some card by what seems like
755644570b8SJeff Kirsher   a simple innocent change. Please contact me or Donald if you think
756644570b8SJeff Kirsher   you have found something that needs changing. -- PG
757644570b8SJeff Kirsher 
758644570b8SJeff Kirsher   Changelog:
759644570b8SJeff Kirsher 
760644570b8SJeff Kirsher   Paul Gortmaker	: remove set_bit lock, other cleanups.
761644570b8SJeff Kirsher   Paul Gortmaker	: add ei_get_8390_hdr() so we can pass skb's to
762644570b8SJeff Kirsher 			  ei_block_input() for eth_io_copy_and_sum().
763644570b8SJeff Kirsher   Paul Gortmaker	: exchange static int ei_pingpong for a #define,
764644570b8SJeff Kirsher 			  also add better Tx error handling.
765644570b8SJeff Kirsher   Paul Gortmaker	: rewrite Rx overrun handling as per NS specs.
766644570b8SJeff Kirsher   Alexey Kuznetsov	: use the 8390's six bit hash multicast filter.
767644570b8SJeff Kirsher   Paul Gortmaker	: tweak ANK's above multicast changes a bit.
768644570b8SJeff Kirsher   Paul Gortmaker	: update packet statistics for v2.1.x
769644570b8SJeff Kirsher   Alan Cox		: support arbitrary stupid port mappings on the
770644570b8SJeff Kirsher 			  68K Macintosh. Support >16bit I/O spaces
771644570b8SJeff Kirsher   Paul Gortmaker	: add kmod support for auto-loading of the 8390
772644570b8SJeff Kirsher 			  module by all drivers that require it.
773644570b8SJeff Kirsher   Alan Cox		: Spinlocking work, added 'BUG_83C690'
774644570b8SJeff Kirsher   Paul Gortmaker	: Separate out Tx timeout code from Tx path.
775644570b8SJeff Kirsher 
776644570b8SJeff Kirsher   Sources:
777644570b8SJeff Kirsher   The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
778644570b8SJeff Kirsher 
779644570b8SJeff Kirsher   */
780644570b8SJeff Kirsher 
781644570b8SJeff Kirsher #include <linux/bitops.h>
782644570b8SJeff Kirsher #include <asm/irq.h>
783644570b8SJeff Kirsher #include <linux/fcntl.h>
784644570b8SJeff Kirsher #include <linux/in.h>
785644570b8SJeff Kirsher #include <linux/interrupt.h>
786644570b8SJeff Kirsher 
787644570b8SJeff Kirsher #define BUG_83C690
788644570b8SJeff Kirsher 
789644570b8SJeff Kirsher /* These are the operational function interfaces to board-specific
790644570b8SJeff Kirsher    routines.
791644570b8SJeff Kirsher 	void reset_8390(struct net_device *dev)
792644570b8SJeff Kirsher 		Resets the board associated with DEV, including a hardware reset of
793644570b8SJeff Kirsher 		the 8390.  This is only called when there is a transmit timeout, and
794644570b8SJeff Kirsher 		it is always followed by 8390_init().
795644570b8SJeff Kirsher 	void block_output(struct net_device *dev, int count, const unsigned char *buf,
796644570b8SJeff Kirsher 					  int start_page)
797644570b8SJeff Kirsher 		Write the COUNT bytes of BUF to the packet buffer at START_PAGE.  The
798644570b8SJeff Kirsher 		"page" value uses the 8390's 256-byte pages.
799644570b8SJeff Kirsher 	void get_8390_hdr(struct net_device *dev, struct e8390_hdr *hdr, int ring_page)
800644570b8SJeff Kirsher 		Read the 4 byte, page aligned 8390 header. *If* there is a
801644570b8SJeff Kirsher 		subsequent read, it will be of the rest of the packet.
802644570b8SJeff Kirsher 	void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
803644570b8SJeff Kirsher 		Read COUNT bytes from the packet buffer into the skb data area. Start
804644570b8SJeff Kirsher 		reading from RING_OFFSET, the address as the 8390 sees it.  This will always
805644570b8SJeff Kirsher 		follow the read of the 8390 header.
806644570b8SJeff Kirsher */
807644570b8SJeff Kirsher #define ei_reset_8390 (ei_local->reset_8390)
808644570b8SJeff Kirsher #define ei_block_output (ei_local->block_output)
809644570b8SJeff Kirsher #define ei_block_input (ei_local->block_input)
810644570b8SJeff Kirsher #define ei_get_8390_hdr (ei_local->get_8390_hdr)
811644570b8SJeff Kirsher 
812644570b8SJeff Kirsher /* Index to functions. */
813644570b8SJeff Kirsher static void ei_tx_intr(struct net_device *dev);
814644570b8SJeff Kirsher static void ei_tx_err(struct net_device *dev);
815644570b8SJeff Kirsher static void ei_receive(struct net_device *dev);
816644570b8SJeff Kirsher static void ei_rx_overrun(struct net_device *dev);
817644570b8SJeff Kirsher 
818644570b8SJeff Kirsher /* Routines generic to NS8390-based boards. */
819644570b8SJeff Kirsher static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
820644570b8SJeff Kirsher 								int start_page);
821644570b8SJeff Kirsher static void do_set_multicast_list(struct net_device *dev);
822644570b8SJeff Kirsher 
823644570b8SJeff Kirsher /*
824644570b8SJeff Kirsher  *	SMP and the 8390 setup.
825644570b8SJeff Kirsher  *
826644570b8SJeff Kirsher  *	The 8390 isn't exactly designed to be multithreaded on RX/TX. There is
827644570b8SJeff Kirsher  *	a page register that controls bank and packet buffer access. We guard
828644570b8SJeff Kirsher  *	this with ei_local->page_lock. Nobody should assume or set the page other
829644570b8SJeff Kirsher  *	than zero when the lock is not held. Lock holders must restore page 0
830644570b8SJeff Kirsher  *	before unlocking. Even pure readers must take the lock to protect in
831644570b8SJeff Kirsher  *	page 0.
832644570b8SJeff Kirsher  *
833644570b8SJeff Kirsher  *	To make life difficult the chip can also be very slow. We therefore can't
834644570b8SJeff Kirsher  *	just use spinlocks. For the longer lockups we disable the irq the device
835644570b8SJeff Kirsher  *	sits on and hold the lock. We must hold the lock because there is a dual
836644570b8SJeff Kirsher  *	processor case other than interrupts (get stats/set multicast list in
837644570b8SJeff Kirsher  *	parallel with each other and transmit).
838644570b8SJeff Kirsher  *
839644570b8SJeff Kirsher  *	Note: in theory we can just disable the irq on the card _but_ there is
840644570b8SJeff Kirsher  *	a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs"
841644570b8SJeff Kirsher  *	enter lock, take the queued irq. So we waddle instead of flying.
842644570b8SJeff Kirsher  *
843644570b8SJeff Kirsher  *	Finally by special arrangement for the purpose of being generally
844644570b8SJeff Kirsher  *	annoying the transmit function is called bh atomic. That places
845644570b8SJeff Kirsher  *	restrictions on the user context callers as disable_irq won't save
846644570b8SJeff Kirsher  *	them.
847644570b8SJeff Kirsher  */
848644570b8SJeff Kirsher 
849644570b8SJeff Kirsher /**
850644570b8SJeff Kirsher  * ax_open - Open/initialize the board.
851644570b8SJeff Kirsher  * @dev: network device to initialize
852644570b8SJeff Kirsher  *
853644570b8SJeff Kirsher  * This routine goes all-out, setting everything
854644570b8SJeff Kirsher  * up anew at each open, even though many of these registers should only
855644570b8SJeff Kirsher  * need to be set once at boot.
856644570b8SJeff Kirsher  */
ax_open(struct net_device * dev)857644570b8SJeff Kirsher static int ax_open(struct net_device *dev)
858644570b8SJeff Kirsher {
859644570b8SJeff Kirsher 	unsigned long flags;
860644570b8SJeff Kirsher 	struct ei_device *ei_local = netdev_priv(dev);
861644570b8SJeff Kirsher 
862644570b8SJeff Kirsher 	/*
863644570b8SJeff Kirsher 	 *	Grab the page lock so we own the register set, then call
864644570b8SJeff Kirsher 	 *	the init function.
865644570b8SJeff Kirsher 	 */
866644570b8SJeff Kirsher 
867644570b8SJeff Kirsher       	spin_lock_irqsave(&ei_local->page_lock, flags);
868644570b8SJeff Kirsher 	AX88190_init(dev, 1);
869644570b8SJeff Kirsher 	/* Set the flag before we drop the lock, That way the IRQ arrives
870644570b8SJeff Kirsher 	   after its set and we get no silly warnings */
871644570b8SJeff Kirsher 	netif_start_queue(dev);
872644570b8SJeff Kirsher       	spin_unlock_irqrestore(&ei_local->page_lock, flags);
873644570b8SJeff Kirsher 	ei_local->irqlock = 0;
874644570b8SJeff Kirsher 	return 0;
875644570b8SJeff Kirsher }
876644570b8SJeff Kirsher 
877644570b8SJeff Kirsher #define dev_lock(dev) (((struct ei_device *)netdev_priv(dev))->page_lock)
878644570b8SJeff Kirsher 
879644570b8SJeff Kirsher /**
880644570b8SJeff Kirsher  * ax_close - shut down network device
881644570b8SJeff Kirsher  * @dev: network device to close
882644570b8SJeff Kirsher  *
883644570b8SJeff Kirsher  * Opposite of ax_open(). Only used when "ifconfig <devname> down" is done.
884644570b8SJeff Kirsher  */
ax_close(struct net_device * dev)885644570b8SJeff Kirsher static int ax_close(struct net_device *dev)
886644570b8SJeff Kirsher {
887644570b8SJeff Kirsher 	unsigned long flags;
888644570b8SJeff Kirsher 
889644570b8SJeff Kirsher 	/*
890644570b8SJeff Kirsher 	 *      Hold the page lock during close
891644570b8SJeff Kirsher 	 */
892644570b8SJeff Kirsher 
893644570b8SJeff Kirsher 	spin_lock_irqsave(&dev_lock(dev), flags);
894644570b8SJeff Kirsher 	AX88190_init(dev, 0);
895644570b8SJeff Kirsher 	spin_unlock_irqrestore(&dev_lock(dev), flags);
896644570b8SJeff Kirsher 	netif_stop_queue(dev);
897644570b8SJeff Kirsher 	return 0;
898644570b8SJeff Kirsher }
899644570b8SJeff Kirsher 
900644570b8SJeff Kirsher /**
901644570b8SJeff Kirsher  * axnet_tx_timeout - handle transmit time out condition
902644570b8SJeff Kirsher  * @dev: network device which has apparently fallen asleep
903fd29aeeeSLee Jones  * @txqueue: unused
904644570b8SJeff Kirsher  *
905644570b8SJeff Kirsher  * Called by kernel when device never acknowledges a transmit has
906644570b8SJeff Kirsher  * completed (or failed) - i.e. never posted a Tx related interrupt.
907644570b8SJeff Kirsher  */
908644570b8SJeff Kirsher 
axnet_tx_timeout(struct net_device * dev,unsigned int txqueue)9090290bd29SMichael S. Tsirkin static void axnet_tx_timeout(struct net_device *dev, unsigned int txqueue)
910644570b8SJeff Kirsher {
911644570b8SJeff Kirsher 	long e8390_base = dev->base_addr;
912644570b8SJeff Kirsher 	struct ei_device *ei_local = netdev_priv(dev);
913644570b8SJeff Kirsher 	int txsr, isr, tickssofar = jiffies - dev_trans_start(dev);
914644570b8SJeff Kirsher 	unsigned long flags;
915644570b8SJeff Kirsher 
916644570b8SJeff Kirsher 	dev->stats.tx_errors++;
917644570b8SJeff Kirsher 
918644570b8SJeff Kirsher 	spin_lock_irqsave(&ei_local->page_lock, flags);
919644570b8SJeff Kirsher 	txsr = inb(e8390_base+EN0_TSR);
920644570b8SJeff Kirsher 	isr = inb(e8390_base+EN0_ISR);
921644570b8SJeff Kirsher 	spin_unlock_irqrestore(&ei_local->page_lock, flags);
922644570b8SJeff Kirsher 
923c45f812fSMatthew Whitehead 	netdev_dbg(dev, "Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
924644570b8SJeff Kirsher 		   (txsr & ENTSR_ABT) ? "excess collisions." :
925644570b8SJeff Kirsher 		   (isr) ? "lost interrupt?" : "cable problem?",
926644570b8SJeff Kirsher 		   txsr, isr, tickssofar);
927644570b8SJeff Kirsher 
928644570b8SJeff Kirsher 	if (!isr && !dev->stats.tx_packets)
929644570b8SJeff Kirsher 	{
930644570b8SJeff Kirsher 		/* The 8390 probably hasn't gotten on the cable yet. */
931644570b8SJeff Kirsher 		ei_local->interface_num ^= 1;   /* Try a different xcvr.  */
932644570b8SJeff Kirsher 	}
933644570b8SJeff Kirsher 
934644570b8SJeff Kirsher 	/* Ugly but a reset can be slow, yet must be protected */
935644570b8SJeff Kirsher 
936644570b8SJeff Kirsher 	spin_lock_irqsave(&ei_local->page_lock, flags);
937644570b8SJeff Kirsher 
938644570b8SJeff Kirsher 	/* Try to restart the card.  Perhaps the user has fixed something. */
939644570b8SJeff Kirsher 	ei_reset_8390(dev);
940644570b8SJeff Kirsher 	AX88190_init(dev, 1);
941644570b8SJeff Kirsher 
942644570b8SJeff Kirsher 	spin_unlock_irqrestore(&ei_local->page_lock, flags);
943644570b8SJeff Kirsher 	netif_wake_queue(dev);
944644570b8SJeff Kirsher }
945644570b8SJeff Kirsher 
946644570b8SJeff Kirsher /**
947644570b8SJeff Kirsher  * axnet_start_xmit - begin packet transmission
948644570b8SJeff Kirsher  * @skb: packet to be sent
949644570b8SJeff Kirsher  * @dev: network device to which packet is sent
950644570b8SJeff Kirsher  *
951644570b8SJeff Kirsher  * Sends a packet to an 8390 network device.
952644570b8SJeff Kirsher  */
953644570b8SJeff Kirsher 
axnet_start_xmit(struct sk_buff * skb,struct net_device * dev)954644570b8SJeff Kirsher static netdev_tx_t axnet_start_xmit(struct sk_buff *skb,
955644570b8SJeff Kirsher 					  struct net_device *dev)
956644570b8SJeff Kirsher {
957644570b8SJeff Kirsher 	long e8390_base = dev->base_addr;
958644570b8SJeff Kirsher 	struct ei_device *ei_local = netdev_priv(dev);
959644570b8SJeff Kirsher 	int length, send_length, output_page;
960644570b8SJeff Kirsher 	unsigned long flags;
961644570b8SJeff Kirsher 	u8 packet[ETH_ZLEN];
962644570b8SJeff Kirsher 
963644570b8SJeff Kirsher 	netif_stop_queue(dev);
964644570b8SJeff Kirsher 
965644570b8SJeff Kirsher 	length = skb->len;
966644570b8SJeff Kirsher 
967644570b8SJeff Kirsher 	/* Mask interrupts from the ethercard.
968644570b8SJeff Kirsher 	   SMP: We have to grab the lock here otherwise the IRQ handler
969644570b8SJeff Kirsher 	   on another CPU can flip window and race the IRQ mask set. We end
970644570b8SJeff Kirsher 	   up trashing the mcast filter not disabling irqs if we don't lock */
971644570b8SJeff Kirsher 
972644570b8SJeff Kirsher 	spin_lock_irqsave(&ei_local->page_lock, flags);
973644570b8SJeff Kirsher 	outb_p(0x00, e8390_base + EN0_IMR);
974644570b8SJeff Kirsher 
975644570b8SJeff Kirsher 	/*
976644570b8SJeff Kirsher 	 *	Slow phase with lock held.
977644570b8SJeff Kirsher 	 */
978644570b8SJeff Kirsher 
979644570b8SJeff Kirsher 	ei_local->irqlock = 1;
980644570b8SJeff Kirsher 
981644570b8SJeff Kirsher 	send_length = max(length, ETH_ZLEN);
982644570b8SJeff Kirsher 
983644570b8SJeff Kirsher 	/*
984644570b8SJeff Kirsher 	 * We have two Tx slots available for use. Find the first free
985644570b8SJeff Kirsher 	 * slot, and then perform some sanity checks. With two Tx bufs,
986644570b8SJeff Kirsher 	 * you get very close to transmitting back-to-back packets. With
987644570b8SJeff Kirsher 	 * only one Tx buf, the transmitter sits idle while you reload the
988644570b8SJeff Kirsher 	 * card, leaving a substantial gap between each transmitted packet.
989644570b8SJeff Kirsher 	 */
990644570b8SJeff Kirsher 
991644570b8SJeff Kirsher 	if (ei_local->tx1 == 0)
992644570b8SJeff Kirsher 	{
993644570b8SJeff Kirsher 		output_page = ei_local->tx_start_page;
994644570b8SJeff Kirsher 		ei_local->tx1 = send_length;
995c45f812fSMatthew Whitehead 		if ((netif_msg_tx_queued(ei_local)) &&
996c45f812fSMatthew Whitehead 		    ei_local->tx2 > 0)
997c45f812fSMatthew Whitehead 			netdev_dbg(dev,
998644570b8SJeff Kirsher 				   "idle transmitter tx2=%d, lasttx=%d, txing=%d\n",
999644570b8SJeff Kirsher 				   ei_local->tx2, ei_local->lasttx,
1000644570b8SJeff Kirsher 				   ei_local->txing);
1001644570b8SJeff Kirsher 	}
1002644570b8SJeff Kirsher 	else if (ei_local->tx2 == 0)
1003644570b8SJeff Kirsher 	{
1004644570b8SJeff Kirsher 		output_page = ei_local->tx_start_page + TX_PAGES/2;
1005644570b8SJeff Kirsher 		ei_local->tx2 = send_length;
1006c45f812fSMatthew Whitehead 		if ((netif_msg_tx_queued(ei_local)) &&
1007c45f812fSMatthew Whitehead 		    ei_local->tx1 > 0)
1008c45f812fSMatthew Whitehead 			netdev_dbg(dev,
1009644570b8SJeff Kirsher 				   "idle transmitter, tx1=%d, lasttx=%d, txing=%d\n",
1010644570b8SJeff Kirsher 				   ei_local->tx1, ei_local->lasttx,
1011644570b8SJeff Kirsher 				   ei_local->txing);
1012644570b8SJeff Kirsher 	}
1013644570b8SJeff Kirsher 	else
1014644570b8SJeff Kirsher 	{	/* We should never get here. */
1015c45f812fSMatthew Whitehead 		netif_dbg(ei_local, tx_err, dev,
1016644570b8SJeff Kirsher 			  "No Tx buffers free! tx1=%d tx2=%d last=%d\n",
1017644570b8SJeff Kirsher 			  ei_local->tx1, ei_local->tx2,
1018644570b8SJeff Kirsher 			  ei_local->lasttx);
1019644570b8SJeff Kirsher 		ei_local->irqlock = 0;
1020644570b8SJeff Kirsher 		netif_stop_queue(dev);
1021644570b8SJeff Kirsher 		outb_p(ENISR_ALL, e8390_base + EN0_IMR);
1022644570b8SJeff Kirsher 		spin_unlock_irqrestore(&ei_local->page_lock, flags);
1023644570b8SJeff Kirsher 		dev->stats.tx_errors++;
1024644570b8SJeff Kirsher 		return NETDEV_TX_BUSY;
1025644570b8SJeff Kirsher 	}
1026644570b8SJeff Kirsher 
1027644570b8SJeff Kirsher 	/*
1028644570b8SJeff Kirsher 	 * Okay, now upload the packet and trigger a send if the transmitter
1029644570b8SJeff Kirsher 	 * isn't already sending. If it is busy, the interrupt handler will
1030644570b8SJeff Kirsher 	 * trigger the send later, upon receiving a Tx done interrupt.
1031644570b8SJeff Kirsher 	 */
1032644570b8SJeff Kirsher 
1033644570b8SJeff Kirsher 	if (length == skb->len)
1034644570b8SJeff Kirsher 		ei_block_output(dev, length, skb->data, output_page);
1035644570b8SJeff Kirsher 	else {
1036644570b8SJeff Kirsher 		memset(packet, 0, ETH_ZLEN);
1037644570b8SJeff Kirsher 		skb_copy_from_linear_data(skb, packet, skb->len);
1038644570b8SJeff Kirsher 		ei_block_output(dev, length, packet, output_page);
1039644570b8SJeff Kirsher 	}
1040644570b8SJeff Kirsher 
1041644570b8SJeff Kirsher 	if (! ei_local->txing)
1042644570b8SJeff Kirsher 	{
1043644570b8SJeff Kirsher 		ei_local->txing = 1;
1044644570b8SJeff Kirsher 		NS8390_trigger_send(dev, send_length, output_page);
1045860e9538SFlorian Westphal 		netif_trans_update(dev);
1046644570b8SJeff Kirsher 		if (output_page == ei_local->tx_start_page)
1047644570b8SJeff Kirsher 		{
1048644570b8SJeff Kirsher 			ei_local->tx1 = -1;
1049644570b8SJeff Kirsher 			ei_local->lasttx = -1;
1050644570b8SJeff Kirsher 		}
1051644570b8SJeff Kirsher 		else
1052644570b8SJeff Kirsher 		{
1053644570b8SJeff Kirsher 			ei_local->tx2 = -1;
1054644570b8SJeff Kirsher 			ei_local->lasttx = -2;
1055644570b8SJeff Kirsher 		}
1056644570b8SJeff Kirsher 	}
1057644570b8SJeff Kirsher 	else ei_local->txqueue++;
1058644570b8SJeff Kirsher 
1059644570b8SJeff Kirsher 	if (ei_local->tx1  &&  ei_local->tx2)
1060644570b8SJeff Kirsher 		netif_stop_queue(dev);
1061644570b8SJeff Kirsher 	else
1062644570b8SJeff Kirsher 		netif_start_queue(dev);
1063644570b8SJeff Kirsher 
1064644570b8SJeff Kirsher 	/* Turn 8390 interrupts back on. */
1065644570b8SJeff Kirsher 	ei_local->irqlock = 0;
1066644570b8SJeff Kirsher 	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
1067644570b8SJeff Kirsher 
1068644570b8SJeff Kirsher 	spin_unlock_irqrestore(&ei_local->page_lock, flags);
1069644570b8SJeff Kirsher 
1070644570b8SJeff Kirsher 	dev_kfree_skb (skb);
1071644570b8SJeff Kirsher 	dev->stats.tx_bytes += send_length;
1072644570b8SJeff Kirsher 
1073644570b8SJeff Kirsher 	return NETDEV_TX_OK;
1074644570b8SJeff Kirsher }
1075644570b8SJeff Kirsher 
1076644570b8SJeff Kirsher /**
1077644570b8SJeff Kirsher  * ax_interrupt - handle the interrupts from an 8390
1078644570b8SJeff Kirsher  * @irq: interrupt number
1079644570b8SJeff Kirsher  * @dev_id: a pointer to the net_device
1080644570b8SJeff Kirsher  *
1081644570b8SJeff Kirsher  * Handle the ether interface interrupts. We pull packets from
1082644570b8SJeff Kirsher  * the 8390 via the card specific functions and fire them at the networking
1083644570b8SJeff Kirsher  * stack. We also handle transmit completions and wake the transmit path if
1084644570b8SJeff Kirsher  * necessary. We also update the counters and do other housekeeping as
1085644570b8SJeff Kirsher  * needed.
1086644570b8SJeff Kirsher  */
1087644570b8SJeff Kirsher 
ax_interrupt(int irq,void * dev_id)1088644570b8SJeff Kirsher static irqreturn_t ax_interrupt(int irq, void *dev_id)
1089644570b8SJeff Kirsher {
1090644570b8SJeff Kirsher 	struct net_device *dev = dev_id;
1091644570b8SJeff Kirsher 	long e8390_base;
1092644570b8SJeff Kirsher 	int interrupts, nr_serviced = 0, i;
1093644570b8SJeff Kirsher 	struct ei_device *ei_local;
1094644570b8SJeff Kirsher 	int handled = 0;
1095644570b8SJeff Kirsher 	unsigned long flags;
1096644570b8SJeff Kirsher 
1097644570b8SJeff Kirsher 	e8390_base = dev->base_addr;
1098644570b8SJeff Kirsher 	ei_local = netdev_priv(dev);
1099644570b8SJeff Kirsher 
1100644570b8SJeff Kirsher 	/*
1101644570b8SJeff Kirsher 	 *	Protect the irq test too.
1102644570b8SJeff Kirsher 	 */
1103644570b8SJeff Kirsher 
1104644570b8SJeff Kirsher 	spin_lock_irqsave(&ei_local->page_lock, flags);
1105644570b8SJeff Kirsher 
1106644570b8SJeff Kirsher 	if (ei_local->irqlock) {
1107644570b8SJeff Kirsher #if 1 /* This might just be an interrupt for a PCI device sharing this line */
1108644570b8SJeff Kirsher 		const char *msg;
1109644570b8SJeff Kirsher 		/* The "irqlock" check is only for testing. */
1110644570b8SJeff Kirsher 		if (ei_local->irqlock)
1111644570b8SJeff Kirsher 			msg = "Interrupted while interrupts are masked!";
1112644570b8SJeff Kirsher 		else
1113644570b8SJeff Kirsher 			msg = "Reentering the interrupt handler!";
1114644570b8SJeff Kirsher 		netdev_info(dev, "%s, isr=%#2x imr=%#2x\n",
1115644570b8SJeff Kirsher 			    msg,
1116644570b8SJeff Kirsher 			    inb_p(e8390_base + EN0_ISR),
1117644570b8SJeff Kirsher 			    inb_p(e8390_base + EN0_IMR));
1118644570b8SJeff Kirsher #endif
1119644570b8SJeff Kirsher 		spin_unlock_irqrestore(&ei_local->page_lock, flags);
1120644570b8SJeff Kirsher 		return IRQ_NONE;
1121644570b8SJeff Kirsher 	}
1122644570b8SJeff Kirsher 
1123c45f812fSMatthew Whitehead 	netif_dbg(ei_local, intr, dev, "interrupt(isr=%#2.2x)\n",
1124644570b8SJeff Kirsher 		  inb_p(e8390_base + EN0_ISR));
1125644570b8SJeff Kirsher 
1126644570b8SJeff Kirsher 	outb_p(0x00, e8390_base + EN0_ISR);
1127644570b8SJeff Kirsher 	ei_local->irqlock = 1;
1128644570b8SJeff Kirsher 
1129644570b8SJeff Kirsher 	/* !!Assumption!! -- we stay in page 0.	 Don't break this. */
1130644570b8SJeff Kirsher 	while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0 &&
1131644570b8SJeff Kirsher 	       ++nr_serviced < MAX_SERVICE)
1132644570b8SJeff Kirsher 	{
1133644570b8SJeff Kirsher 		if (!netif_running(dev) || (interrupts == 0xff)) {
1134c45f812fSMatthew Whitehead 			netif_warn(ei_local, intr, dev,
1135644570b8SJeff Kirsher 				   "interrupt from stopped card\n");
1136644570b8SJeff Kirsher 			outb_p(interrupts, e8390_base + EN0_ISR);
1137644570b8SJeff Kirsher 			interrupts = 0;
1138644570b8SJeff Kirsher 			break;
1139644570b8SJeff Kirsher 		}
1140644570b8SJeff Kirsher 		handled = 1;
1141644570b8SJeff Kirsher 
1142644570b8SJeff Kirsher 		/* AX88190 bug fix. */
1143644570b8SJeff Kirsher 		outb_p(interrupts, e8390_base + EN0_ISR);
1144644570b8SJeff Kirsher 		for (i = 0; i < 10; i++) {
1145644570b8SJeff Kirsher 			if (!(inb(e8390_base + EN0_ISR) & interrupts))
1146644570b8SJeff Kirsher 				break;
1147644570b8SJeff Kirsher 			outb_p(0, e8390_base + EN0_ISR);
1148644570b8SJeff Kirsher 			outb_p(interrupts, e8390_base + EN0_ISR);
1149644570b8SJeff Kirsher 		}
1150644570b8SJeff Kirsher 		if (interrupts & ENISR_OVER)
1151644570b8SJeff Kirsher 			ei_rx_overrun(dev);
1152644570b8SJeff Kirsher 		else if (interrupts & (ENISR_RX+ENISR_RX_ERR))
1153644570b8SJeff Kirsher 		{
1154644570b8SJeff Kirsher 			/* Got a good (?) packet. */
1155644570b8SJeff Kirsher 			ei_receive(dev);
1156644570b8SJeff Kirsher 		}
1157644570b8SJeff Kirsher 		/* Push the next to-transmit packet through. */
1158644570b8SJeff Kirsher 		if (interrupts & ENISR_TX)
1159644570b8SJeff Kirsher 			ei_tx_intr(dev);
1160644570b8SJeff Kirsher 		else if (interrupts & ENISR_TX_ERR)
1161644570b8SJeff Kirsher 			ei_tx_err(dev);
1162644570b8SJeff Kirsher 
1163644570b8SJeff Kirsher 		if (interrupts & ENISR_COUNTERS)
1164644570b8SJeff Kirsher 		{
1165644570b8SJeff Kirsher 			dev->stats.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
1166644570b8SJeff Kirsher 			dev->stats.rx_crc_errors   += inb_p(e8390_base + EN0_COUNTER1);
1167644570b8SJeff Kirsher 			dev->stats.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
1168644570b8SJeff Kirsher 		}
1169644570b8SJeff Kirsher 	}
1170644570b8SJeff Kirsher 
1171c45f812fSMatthew Whitehead 	if (interrupts && (netif_msg_intr(ei_local)))
1172644570b8SJeff Kirsher 	{
1173644570b8SJeff Kirsher 		handled = 1;
1174644570b8SJeff Kirsher 		if (nr_serviced >= MAX_SERVICE)
1175644570b8SJeff Kirsher 		{
1176644570b8SJeff Kirsher 			/* 0xFF is valid for a card removal */
1177644570b8SJeff Kirsher 			if (interrupts != 0xFF)
1178c45f812fSMatthew Whitehead 				netdev_warn(dev,
1179c45f812fSMatthew Whitehead 					    "Too much work at interrupt, status %#2.2x\n",
1180644570b8SJeff Kirsher 					    interrupts);
1181644570b8SJeff Kirsher 			outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
1182644570b8SJeff Kirsher 		} else {
1183644570b8SJeff Kirsher 			netdev_warn(dev, "unknown interrupt %#2x\n",
1184644570b8SJeff Kirsher 				    interrupts);
1185644570b8SJeff Kirsher 			outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
1186644570b8SJeff Kirsher 		}
1187644570b8SJeff Kirsher 	}
1188644570b8SJeff Kirsher 
1189644570b8SJeff Kirsher 	/* Turn 8390 interrupts back on. */
1190644570b8SJeff Kirsher 	ei_local->irqlock = 0;
1191644570b8SJeff Kirsher 	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
1192644570b8SJeff Kirsher 
1193644570b8SJeff Kirsher 	spin_unlock_irqrestore(&ei_local->page_lock, flags);
1194644570b8SJeff Kirsher 	return IRQ_RETVAL(handled);
1195644570b8SJeff Kirsher }
1196644570b8SJeff Kirsher 
1197644570b8SJeff Kirsher /**
1198644570b8SJeff Kirsher  * ei_tx_err - handle transmitter error
1199644570b8SJeff Kirsher  * @dev: network device which threw the exception
1200644570b8SJeff Kirsher  *
1201644570b8SJeff Kirsher  * A transmitter error has happened. Most likely excess collisions (which
1202644570b8SJeff Kirsher  * is a fairly normal condition). If the error is one where the Tx will
1203644570b8SJeff Kirsher  * have been aborted, we try and send another one right away, instead of
1204644570b8SJeff Kirsher  * letting the failed packet sit and collect dust in the Tx buffer. This
1205644570b8SJeff Kirsher  * is a much better solution as it avoids kernel based Tx timeouts, and
1206644570b8SJeff Kirsher  * an unnecessary card reset.
1207644570b8SJeff Kirsher  *
1208644570b8SJeff Kirsher  * Called with lock held.
1209644570b8SJeff Kirsher  */
1210644570b8SJeff Kirsher 
ei_tx_err(struct net_device * dev)1211644570b8SJeff Kirsher static void ei_tx_err(struct net_device *dev)
1212644570b8SJeff Kirsher {
1213644570b8SJeff Kirsher 	long e8390_base = dev->base_addr;
1214644570b8SJeff Kirsher 	unsigned char txsr = inb_p(e8390_base+EN0_TSR);
1215644570b8SJeff Kirsher 	unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
1216644570b8SJeff Kirsher 
1217644570b8SJeff Kirsher #ifdef VERBOSE_ERROR_DUMP
1218c45f812fSMatthew Whitehead 	netdev_dbg(dev, "transmitter error (%#2x):", txsr);
1219644570b8SJeff Kirsher 	if (txsr & ENTSR_ABT)
1220644570b8SJeff Kirsher 		pr_cont(" excess-collisions");
1221644570b8SJeff Kirsher 	if (txsr & ENTSR_ND)
1222644570b8SJeff Kirsher 		pr_cont(" non-deferral");
1223644570b8SJeff Kirsher 	if (txsr & ENTSR_CRS)
1224644570b8SJeff Kirsher 		pr_cont(" lost-carrier");
1225644570b8SJeff Kirsher 	if (txsr & ENTSR_FU)
1226644570b8SJeff Kirsher 		pr_cont(" FIFO-underrun");
1227644570b8SJeff Kirsher 	if (txsr & ENTSR_CDH)
1228644570b8SJeff Kirsher 		pr_cont(" lost-heartbeat");
1229644570b8SJeff Kirsher 	pr_cont("\n");
1230644570b8SJeff Kirsher #endif
1231644570b8SJeff Kirsher 
1232644570b8SJeff Kirsher 	if (tx_was_aborted)
1233644570b8SJeff Kirsher 		ei_tx_intr(dev);
1234644570b8SJeff Kirsher 	else
1235644570b8SJeff Kirsher 	{
1236644570b8SJeff Kirsher 		dev->stats.tx_errors++;
1237644570b8SJeff Kirsher 		if (txsr & ENTSR_CRS) dev->stats.tx_carrier_errors++;
1238644570b8SJeff Kirsher 		if (txsr & ENTSR_CDH) dev->stats.tx_heartbeat_errors++;
1239644570b8SJeff Kirsher 		if (txsr & ENTSR_OWC) dev->stats.tx_window_errors++;
1240644570b8SJeff Kirsher 	}
1241644570b8SJeff Kirsher }
1242644570b8SJeff Kirsher 
1243644570b8SJeff Kirsher /**
1244644570b8SJeff Kirsher  * ei_tx_intr - transmit interrupt handler
1245644570b8SJeff Kirsher  * @dev: network device for which tx intr is handled
1246644570b8SJeff Kirsher  *
1247644570b8SJeff Kirsher  * We have finished a transmit: check for errors and then trigger the next
1248644570b8SJeff Kirsher  * packet to be sent. Called with lock held.
1249644570b8SJeff Kirsher  */
1250644570b8SJeff Kirsher 
ei_tx_intr(struct net_device * dev)1251644570b8SJeff Kirsher static void ei_tx_intr(struct net_device *dev)
1252644570b8SJeff Kirsher {
1253644570b8SJeff Kirsher 	long e8390_base = dev->base_addr;
1254644570b8SJeff Kirsher 	struct ei_device *ei_local = netdev_priv(dev);
1255644570b8SJeff Kirsher 	int status = inb(e8390_base + EN0_TSR);
1256644570b8SJeff Kirsher 
1257644570b8SJeff Kirsher 	/*
1258644570b8SJeff Kirsher 	 * There are two Tx buffers, see which one finished, and trigger
1259644570b8SJeff Kirsher 	 * the send of another one if it exists.
1260644570b8SJeff Kirsher 	 */
1261644570b8SJeff Kirsher 	ei_local->txqueue--;
1262644570b8SJeff Kirsher 
1263644570b8SJeff Kirsher 	if (ei_local->tx1 < 0)
1264644570b8SJeff Kirsher 	{
1265644570b8SJeff Kirsher 		if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
1266644570b8SJeff Kirsher 			netdev_err(dev, "%s: bogus last_tx_buffer %d, tx1=%d\n",
1267644570b8SJeff Kirsher 				   ei_local->name, ei_local->lasttx,
1268644570b8SJeff Kirsher 				   ei_local->tx1);
1269644570b8SJeff Kirsher 		ei_local->tx1 = 0;
1270644570b8SJeff Kirsher 		if (ei_local->tx2 > 0)
1271644570b8SJeff Kirsher 		{
1272644570b8SJeff Kirsher 			ei_local->txing = 1;
1273644570b8SJeff Kirsher 			NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
1274860e9538SFlorian Westphal 			netif_trans_update(dev);
1275e7fee115SJoe Perches 			ei_local->tx2 = -1;
1276644570b8SJeff Kirsher 			ei_local->lasttx = 2;
1277e7fee115SJoe Perches 		} else {
1278e7fee115SJoe Perches 			ei_local->lasttx = 20;
1279e7fee115SJoe Perches 			ei_local->txing = 0;
1280644570b8SJeff Kirsher 		}
1281644570b8SJeff Kirsher 	}
1282644570b8SJeff Kirsher 	else if (ei_local->tx2 < 0)
1283644570b8SJeff Kirsher 	{
1284644570b8SJeff Kirsher 		if (ei_local->lasttx != 2  &&  ei_local->lasttx != -2)
1285c45f812fSMatthew Whitehead 			netdev_err(dev, "%s: bogus last_tx_buffer %d, tx2=%d\n",
1286644570b8SJeff Kirsher 				   ei_local->name, ei_local->lasttx,
1287644570b8SJeff Kirsher 				   ei_local->tx2);
1288644570b8SJeff Kirsher 		ei_local->tx2 = 0;
1289644570b8SJeff Kirsher 		if (ei_local->tx1 > 0)
1290644570b8SJeff Kirsher 		{
1291644570b8SJeff Kirsher 			ei_local->txing = 1;
1292644570b8SJeff Kirsher 			NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
1293860e9538SFlorian Westphal 			netif_trans_update(dev);
1294644570b8SJeff Kirsher 			ei_local->tx1 = -1;
1295644570b8SJeff Kirsher 			ei_local->lasttx = 1;
1296e7fee115SJoe Perches 		} else {
1297e7fee115SJoe Perches 			ei_local->lasttx = 10;
1298e7fee115SJoe Perches 			ei_local->txing = 0;
1299644570b8SJeff Kirsher 		}
1300644570b8SJeff Kirsher 	}
1301644570b8SJeff Kirsher //	else
1302644570b8SJeff Kirsher //		netdev_warn(dev, "unexpected TX-done interrupt, lasttx=%d\n",
1303644570b8SJeff Kirsher //			    ei_local->lasttx);
1304644570b8SJeff Kirsher 
1305644570b8SJeff Kirsher 	/* Minimize Tx latency: update the statistics after we restart TXing. */
1306644570b8SJeff Kirsher 	if (status & ENTSR_COL)
1307644570b8SJeff Kirsher 		dev->stats.collisions++;
1308644570b8SJeff Kirsher 	if (status & ENTSR_PTX)
1309644570b8SJeff Kirsher 		dev->stats.tx_packets++;
1310644570b8SJeff Kirsher 	else
1311644570b8SJeff Kirsher 	{
1312644570b8SJeff Kirsher 		dev->stats.tx_errors++;
1313644570b8SJeff Kirsher 		if (status & ENTSR_ABT)
1314644570b8SJeff Kirsher 		{
1315644570b8SJeff Kirsher 			dev->stats.tx_aborted_errors++;
1316644570b8SJeff Kirsher 			dev->stats.collisions += 16;
1317644570b8SJeff Kirsher 		}
1318644570b8SJeff Kirsher 		if (status & ENTSR_CRS)
1319644570b8SJeff Kirsher 			dev->stats.tx_carrier_errors++;
1320644570b8SJeff Kirsher 		if (status & ENTSR_FU)
1321644570b8SJeff Kirsher 			dev->stats.tx_fifo_errors++;
1322644570b8SJeff Kirsher 		if (status & ENTSR_CDH)
1323644570b8SJeff Kirsher 			dev->stats.tx_heartbeat_errors++;
1324644570b8SJeff Kirsher 		if (status & ENTSR_OWC)
1325644570b8SJeff Kirsher 			dev->stats.tx_window_errors++;
1326644570b8SJeff Kirsher 	}
1327644570b8SJeff Kirsher 	netif_wake_queue(dev);
1328644570b8SJeff Kirsher }
1329644570b8SJeff Kirsher 
1330644570b8SJeff Kirsher /**
1331644570b8SJeff Kirsher  * ei_receive - receive some packets
1332644570b8SJeff Kirsher  * @dev: network device with which receive will be run
1333644570b8SJeff Kirsher  *
1334644570b8SJeff Kirsher  * We have a good packet(s), get it/them out of the buffers.
1335644570b8SJeff Kirsher  * Called with lock held.
1336644570b8SJeff Kirsher  */
1337644570b8SJeff Kirsher 
ei_receive(struct net_device * dev)1338644570b8SJeff Kirsher static void ei_receive(struct net_device *dev)
1339644570b8SJeff Kirsher {
1340644570b8SJeff Kirsher 	long e8390_base = dev->base_addr;
1341644570b8SJeff Kirsher 	struct ei_device *ei_local = netdev_priv(dev);
1342644570b8SJeff Kirsher 	unsigned char rxing_page, this_frame, next_frame;
1343644570b8SJeff Kirsher 	unsigned short current_offset;
1344644570b8SJeff Kirsher 	int rx_pkt_count = 0;
1345644570b8SJeff Kirsher 	struct e8390_pkt_hdr rx_frame;
1346644570b8SJeff Kirsher 
1347644570b8SJeff Kirsher 	while (++rx_pkt_count < 10)
1348644570b8SJeff Kirsher 	{
1349644570b8SJeff Kirsher 		int pkt_len, pkt_stat;
1350644570b8SJeff Kirsher 
1351644570b8SJeff Kirsher 		/* Get the rx page (incoming packet pointer). */
1352644570b8SJeff Kirsher 		rxing_page = inb_p(e8390_base + EN1_CURPAG -1);
1353644570b8SJeff Kirsher 
1354644570b8SJeff Kirsher 		/* Remove one frame from the ring.  Boundary is always a page behind. */
1355644570b8SJeff Kirsher 		this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;
1356644570b8SJeff Kirsher 		if (this_frame >= ei_local->stop_page)
1357644570b8SJeff Kirsher 			this_frame = ei_local->rx_start_page;
1358644570b8SJeff Kirsher 
1359644570b8SJeff Kirsher 		/* Someday we'll omit the previous, iff we never get this message.
1360644570b8SJeff Kirsher 		   (There is at least one clone claimed to have a problem.)
1361644570b8SJeff Kirsher 
1362644570b8SJeff Kirsher 		   Keep quiet if it looks like a card removal. One problem here
1363644570b8SJeff Kirsher 		   is that some clones crash in roughly the same way.
1364644570b8SJeff Kirsher 		 */
1365c45f812fSMatthew Whitehead 		if ((netif_msg_rx_err(ei_local)) &&
1366c45f812fSMatthew Whitehead 		    this_frame != ei_local->current_page &&
1367c45f812fSMatthew Whitehead 		    (this_frame != 0x0 || rxing_page != 0xFF))
1368644570b8SJeff Kirsher 			netdev_err(dev, "mismatched read page pointers %2x vs %2x\n",
1369644570b8SJeff Kirsher 				   this_frame, ei_local->current_page);
1370644570b8SJeff Kirsher 
1371644570b8SJeff Kirsher 		if (this_frame == rxing_page)	/* Read all the frames? */
1372644570b8SJeff Kirsher 			break;				/* Done for now */
1373644570b8SJeff Kirsher 
1374644570b8SJeff Kirsher 		current_offset = this_frame << 8;
1375644570b8SJeff Kirsher 		ei_get_8390_hdr(dev, &rx_frame, this_frame);
1376644570b8SJeff Kirsher 
1377644570b8SJeff Kirsher 		pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);
1378644570b8SJeff Kirsher 		pkt_stat = rx_frame.status;
1379644570b8SJeff Kirsher 
1380644570b8SJeff Kirsher 		next_frame = this_frame + 1 + ((pkt_len+4)>>8);
1381644570b8SJeff Kirsher 
1382644570b8SJeff Kirsher 		if (pkt_len < 60  ||  pkt_len > 1518)
1383644570b8SJeff Kirsher 		{
1384c45f812fSMatthew Whitehead 			netif_err(ei_local, rx_err, dev,
1385644570b8SJeff Kirsher 				  "bogus packet size: %d, status=%#2x nxpg=%#2x\n",
1386644570b8SJeff Kirsher 				  rx_frame.count, rx_frame.status,
1387644570b8SJeff Kirsher 				  rx_frame.next);
1388644570b8SJeff Kirsher 			dev->stats.rx_errors++;
1389644570b8SJeff Kirsher 			dev->stats.rx_length_errors++;
1390644570b8SJeff Kirsher 		}
1391644570b8SJeff Kirsher 		 else if ((pkt_stat & 0x0F) == ENRSR_RXOK)
1392644570b8SJeff Kirsher 		{
1393644570b8SJeff Kirsher 			struct sk_buff *skb;
1394644570b8SJeff Kirsher 
13951d266430SPradeep A Dalvi 			skb = netdev_alloc_skb(dev, pkt_len + 2);
1396644570b8SJeff Kirsher 			if (skb == NULL)
1397644570b8SJeff Kirsher 			{
1398c45f812fSMatthew Whitehead 				netif_err(ei_local, rx_err, dev,
1399644570b8SJeff Kirsher 					  "Couldn't allocate a sk_buff of size %d\n",
1400644570b8SJeff Kirsher 					  pkt_len);
1401644570b8SJeff Kirsher 				dev->stats.rx_dropped++;
1402644570b8SJeff Kirsher 				break;
1403644570b8SJeff Kirsher 			}
1404644570b8SJeff Kirsher 			else
1405644570b8SJeff Kirsher 			{
1406644570b8SJeff Kirsher 				skb_reserve(skb,2);	/* IP headers on 16 byte boundaries */
1407644570b8SJeff Kirsher 				skb_put(skb, pkt_len);	/* Make room */
1408644570b8SJeff Kirsher 				ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
1409644570b8SJeff Kirsher 				skb->protocol=eth_type_trans(skb,dev);
1410644570b8SJeff Kirsher 				netif_rx(skb);
1411644570b8SJeff Kirsher 				dev->stats.rx_packets++;
1412644570b8SJeff Kirsher 				dev->stats.rx_bytes += pkt_len;
1413644570b8SJeff Kirsher 				if (pkt_stat & ENRSR_PHY)
1414644570b8SJeff Kirsher 					dev->stats.multicast++;
1415644570b8SJeff Kirsher 			}
1416644570b8SJeff Kirsher 		}
1417644570b8SJeff Kirsher 		else
1418644570b8SJeff Kirsher 		{
1419c45f812fSMatthew Whitehead 			netif_err(ei_local, rx_err, dev,
1420644570b8SJeff Kirsher 				  "bogus packet: status=%#2x nxpg=%#2x size=%d\n",
1421644570b8SJeff Kirsher 				  rx_frame.status, rx_frame.next,
1422644570b8SJeff Kirsher 				  rx_frame.count);
1423644570b8SJeff Kirsher 			dev->stats.rx_errors++;
1424644570b8SJeff Kirsher 			/* NB: The NIC counts CRC, frame and missed errors. */
1425644570b8SJeff Kirsher 			if (pkt_stat & ENRSR_FO)
1426644570b8SJeff Kirsher 				dev->stats.rx_fifo_errors++;
1427644570b8SJeff Kirsher 		}
1428644570b8SJeff Kirsher 		next_frame = rx_frame.next;
1429644570b8SJeff Kirsher 
1430644570b8SJeff Kirsher 		/* This _should_ never happen: it's here for avoiding bad clones. */
1431644570b8SJeff Kirsher 		if (next_frame >= ei_local->stop_page) {
1432644570b8SJeff Kirsher 			netdev_info(dev, "next frame inconsistency, %#2x\n",
1433644570b8SJeff Kirsher 				    next_frame);
1434644570b8SJeff Kirsher 			next_frame = ei_local->rx_start_page;
1435644570b8SJeff Kirsher 		}
1436644570b8SJeff Kirsher 		ei_local->current_page = next_frame;
1437644570b8SJeff Kirsher 		outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
1438644570b8SJeff Kirsher 	}
1439644570b8SJeff Kirsher }
1440644570b8SJeff Kirsher 
1441644570b8SJeff Kirsher /**
1442644570b8SJeff Kirsher  * ei_rx_overrun - handle receiver overrun
1443644570b8SJeff Kirsher  * @dev: network device which threw exception
1444644570b8SJeff Kirsher  *
1445644570b8SJeff Kirsher  * We have a receiver overrun: we have to kick the 8390 to get it started
1446644570b8SJeff Kirsher  * again. Problem is that you have to kick it exactly as NS prescribes in
1447644570b8SJeff Kirsher  * the updated datasheets, or "the NIC may act in an unpredictable manner."
1448644570b8SJeff Kirsher  * This includes causing "the NIC to defer indefinitely when it is stopped
1449644570b8SJeff Kirsher  * on a busy network."  Ugh.
1450644570b8SJeff Kirsher  * Called with lock held. Don't call this with the interrupts off or your
1451644570b8SJeff Kirsher  * computer will hate you - it takes 10ms or so.
1452644570b8SJeff Kirsher  */
1453644570b8SJeff Kirsher 
ei_rx_overrun(struct net_device * dev)1454644570b8SJeff Kirsher static void ei_rx_overrun(struct net_device *dev)
1455644570b8SJeff Kirsher {
1456abac0d3fSHimangi Saraogi 	struct axnet_dev *info = PRIV(dev);
1457644570b8SJeff Kirsher 	long e8390_base = dev->base_addr;
1458644570b8SJeff Kirsher 	unsigned char was_txing, must_resend = 0;
1459c45f812fSMatthew Whitehead 	struct ei_device *ei_local = netdev_priv(dev);
1460644570b8SJeff Kirsher 
1461644570b8SJeff Kirsher 	/*
1462644570b8SJeff Kirsher 	 * Record whether a Tx was in progress and then issue the
1463644570b8SJeff Kirsher 	 * stop command.
1464644570b8SJeff Kirsher 	 */
1465644570b8SJeff Kirsher 	was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
1466644570b8SJeff Kirsher 	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
1467644570b8SJeff Kirsher 
1468c45f812fSMatthew Whitehead 	netif_dbg(ei_local, rx_err, dev, "Receiver overrun\n");
1469644570b8SJeff Kirsher 	dev->stats.rx_over_errors++;
1470644570b8SJeff Kirsher 
1471644570b8SJeff Kirsher 	/*
1472644570b8SJeff Kirsher 	 * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
1473644570b8SJeff Kirsher 	 * We wait at least 2ms.
1474644570b8SJeff Kirsher 	 */
1475644570b8SJeff Kirsher 
1476644570b8SJeff Kirsher 	mdelay(2);
1477644570b8SJeff Kirsher 
1478644570b8SJeff Kirsher 	/*
1479644570b8SJeff Kirsher 	 * Reset RBCR[01] back to zero as per magic incantation.
1480644570b8SJeff Kirsher 	 */
1481644570b8SJeff Kirsher 	outb_p(0x00, e8390_base+EN0_RCNTLO);
1482644570b8SJeff Kirsher 	outb_p(0x00, e8390_base+EN0_RCNTHI);
1483644570b8SJeff Kirsher 
1484644570b8SJeff Kirsher 	/*
1485644570b8SJeff Kirsher 	 * See if any Tx was interrupted or not. According to NS, this
1486644570b8SJeff Kirsher 	 * step is vital, and skipping it will cause no end of havoc.
1487644570b8SJeff Kirsher 	 */
1488644570b8SJeff Kirsher 
1489644570b8SJeff Kirsher 	if (was_txing)
1490644570b8SJeff Kirsher 	{
1491644570b8SJeff Kirsher 		unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
1492644570b8SJeff Kirsher 		if (!tx_completed)
1493644570b8SJeff Kirsher 			must_resend = 1;
1494644570b8SJeff Kirsher 	}
1495644570b8SJeff Kirsher 
1496644570b8SJeff Kirsher 	/*
1497644570b8SJeff Kirsher 	 * Have to enter loopback mode and then restart the NIC before
1498644570b8SJeff Kirsher 	 * you are allowed to slurp packets up off the ring.
1499644570b8SJeff Kirsher 	 */
1500644570b8SJeff Kirsher 	outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
1501644570b8SJeff Kirsher 	outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
1502644570b8SJeff Kirsher 
1503644570b8SJeff Kirsher 	/*
1504644570b8SJeff Kirsher 	 * Clear the Rx ring of all the debris, and ack the interrupt.
1505644570b8SJeff Kirsher 	 */
1506644570b8SJeff Kirsher 	ei_receive(dev);
1507644570b8SJeff Kirsher 
1508644570b8SJeff Kirsher 	/*
1509644570b8SJeff Kirsher 	 * Leave loopback mode, and resend any packet that got stopped.
1510644570b8SJeff Kirsher 	 */
1511644570b8SJeff Kirsher 	outb_p(E8390_TXCONFIG | info->duplex_flag, e8390_base + EN0_TXCR);
1512644570b8SJeff Kirsher 	if (must_resend)
1513644570b8SJeff Kirsher     		outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
1514644570b8SJeff Kirsher }
1515644570b8SJeff Kirsher 
1516644570b8SJeff Kirsher /*
1517644570b8SJeff Kirsher  *	Collect the stats. This is called unlocked and from several contexts.
1518644570b8SJeff Kirsher  */
1519644570b8SJeff Kirsher 
get_stats(struct net_device * dev)1520644570b8SJeff Kirsher static struct net_device_stats *get_stats(struct net_device *dev)
1521644570b8SJeff Kirsher {
1522644570b8SJeff Kirsher 	long ioaddr = dev->base_addr;
1523644570b8SJeff Kirsher 	struct ei_device *ei_local = netdev_priv(dev);
1524644570b8SJeff Kirsher 	unsigned long flags;
1525644570b8SJeff Kirsher 
1526644570b8SJeff Kirsher 	/* If the card is stopped, just return the present stats. */
1527644570b8SJeff Kirsher 	if (!netif_running(dev))
1528644570b8SJeff Kirsher 		return &dev->stats;
1529644570b8SJeff Kirsher 
1530644570b8SJeff Kirsher 	spin_lock_irqsave(&ei_local->page_lock,flags);
1531644570b8SJeff Kirsher 	/* Read the counter registers, assuming we are in page 0. */
1532644570b8SJeff Kirsher 	dev->stats.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
1533644570b8SJeff Kirsher 	dev->stats.rx_crc_errors   += inb_p(ioaddr + EN0_COUNTER1);
1534644570b8SJeff Kirsher 	dev->stats.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
1535644570b8SJeff Kirsher 	spin_unlock_irqrestore(&ei_local->page_lock, flags);
1536644570b8SJeff Kirsher 
1537644570b8SJeff Kirsher 	return &dev->stats;
1538644570b8SJeff Kirsher }
1539644570b8SJeff Kirsher 
1540644570b8SJeff Kirsher /*
1541644570b8SJeff Kirsher  * Form the 64 bit 8390 multicast table from the linked list of addresses
1542644570b8SJeff Kirsher  * associated with this dev structure.
1543644570b8SJeff Kirsher  */
1544644570b8SJeff Kirsher 
make_mc_bits(u8 * bits,struct net_device * dev)1545644570b8SJeff Kirsher static inline void make_mc_bits(u8 *bits, struct net_device *dev)
1546644570b8SJeff Kirsher {
1547644570b8SJeff Kirsher 	struct netdev_hw_addr *ha;
1548644570b8SJeff Kirsher 	u32 crc;
1549644570b8SJeff Kirsher 
1550644570b8SJeff Kirsher 	netdev_for_each_mc_addr(ha, dev) {
1551644570b8SJeff Kirsher 		crc = ether_crc(ETH_ALEN, ha->addr);
1552644570b8SJeff Kirsher 		/*
1553644570b8SJeff Kirsher 		 * The 8390 uses the 6 most significant bits of the
1554644570b8SJeff Kirsher 		 * CRC to index the multicast table.
1555644570b8SJeff Kirsher 		 */
1556644570b8SJeff Kirsher 		bits[crc>>29] |= (1<<((crc>>26)&7));
1557644570b8SJeff Kirsher 	}
1558644570b8SJeff Kirsher }
1559644570b8SJeff Kirsher 
1560644570b8SJeff Kirsher /**
1561644570b8SJeff Kirsher  * do_set_multicast_list - set/clear multicast filter
1562644570b8SJeff Kirsher  * @dev: net device for which multicast filter is adjusted
1563644570b8SJeff Kirsher  *
1564644570b8SJeff Kirsher  *	Set or clear the multicast filter for this adaptor.
1565644570b8SJeff Kirsher  *	Must be called with lock held.
1566644570b8SJeff Kirsher  */
1567644570b8SJeff Kirsher 
do_set_multicast_list(struct net_device * dev)1568644570b8SJeff Kirsher static void do_set_multicast_list(struct net_device *dev)
1569644570b8SJeff Kirsher {
1570644570b8SJeff Kirsher 	long e8390_base = dev->base_addr;
1571644570b8SJeff Kirsher 	int i;
1572644570b8SJeff Kirsher 	struct ei_device *ei_local = netdev_priv(dev);
1573644570b8SJeff Kirsher 
1574644570b8SJeff Kirsher 	if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
1575644570b8SJeff Kirsher 		memset(ei_local->mcfilter, 0, 8);
1576644570b8SJeff Kirsher 		if (!netdev_mc_empty(dev))
1577644570b8SJeff Kirsher 			make_mc_bits(ei_local->mcfilter, dev);
1578644570b8SJeff Kirsher 	} else {
1579644570b8SJeff Kirsher 		/* set to accept-all */
1580644570b8SJeff Kirsher 		memset(ei_local->mcfilter, 0xFF, 8);
1581644570b8SJeff Kirsher 	}
1582644570b8SJeff Kirsher 
1583644570b8SJeff Kirsher 	outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
1584644570b8SJeff Kirsher 	for(i = 0; i < 8; i++)
1585644570b8SJeff Kirsher 	{
1586644570b8SJeff Kirsher 		outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
1587644570b8SJeff Kirsher 	}
1588644570b8SJeff Kirsher 	outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
1589644570b8SJeff Kirsher 
1590644570b8SJeff Kirsher 	if(dev->flags&IFF_PROMISC)
1591644570b8SJeff Kirsher 		outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
1592644570b8SJeff Kirsher 	else if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev))
1593644570b8SJeff Kirsher 		outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
1594644570b8SJeff Kirsher 	else
1595644570b8SJeff Kirsher 		outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
1596644570b8SJeff Kirsher 
1597644570b8SJeff Kirsher 	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
1598644570b8SJeff Kirsher }
1599644570b8SJeff Kirsher 
1600644570b8SJeff Kirsher /*
1601644570b8SJeff Kirsher  *	Called without lock held. This is invoked from user context and may
1602644570b8SJeff Kirsher  *	be parallel to just about everything else. Its also fairly quick and
1603644570b8SJeff Kirsher  *	not called too often. Must protect against both bh and irq users
1604644570b8SJeff Kirsher  */
1605644570b8SJeff Kirsher 
set_multicast_list(struct net_device * dev)1606644570b8SJeff Kirsher static void set_multicast_list(struct net_device *dev)
1607644570b8SJeff Kirsher {
1608644570b8SJeff Kirsher 	unsigned long flags;
1609644570b8SJeff Kirsher 
1610644570b8SJeff Kirsher 	spin_lock_irqsave(&dev_lock(dev), flags);
1611644570b8SJeff Kirsher 	do_set_multicast_list(dev);
1612644570b8SJeff Kirsher 	spin_unlock_irqrestore(&dev_lock(dev), flags);
1613644570b8SJeff Kirsher }
1614644570b8SJeff Kirsher 
1615644570b8SJeff Kirsher /* This page of functions should be 8390 generic */
1616644570b8SJeff Kirsher /* Follow National Semi's recommendations for initializing the "NIC". */
1617644570b8SJeff Kirsher 
1618644570b8SJeff Kirsher /**
1619644570b8SJeff Kirsher  * AX88190_init - initialize 8390 hardware
1620644570b8SJeff Kirsher  * @dev: network device to initialize
1621644570b8SJeff Kirsher  * @startp: boolean.  non-zero value to initiate chip processing
1622644570b8SJeff Kirsher  *
1623644570b8SJeff Kirsher  *	Must be called with lock held.
1624644570b8SJeff Kirsher  */
1625644570b8SJeff Kirsher 
AX88190_init(struct net_device * dev,int startp)1626644570b8SJeff Kirsher static void AX88190_init(struct net_device *dev, int startp)
1627644570b8SJeff Kirsher {
1628abac0d3fSHimangi Saraogi 	struct axnet_dev *info = PRIV(dev);
1629644570b8SJeff Kirsher 	long e8390_base = dev->base_addr;
1630644570b8SJeff Kirsher 	struct ei_device *ei_local = netdev_priv(dev);
1631644570b8SJeff Kirsher 	int i;
1632644570b8SJeff Kirsher 	int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
1633644570b8SJeff Kirsher 
1634644570b8SJeff Kirsher 	if(sizeof(struct e8390_pkt_hdr)!=4)
1635644570b8SJeff Kirsher     		panic("8390.c: header struct mispacked\n");
1636644570b8SJeff Kirsher 	/* Follow National Semi's recommendations for initing the DP83902. */
1637644570b8SJeff Kirsher 	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */
1638644570b8SJeff Kirsher 	outb_p(endcfg, e8390_base + EN0_DCFG);	/* 0x48 or 0x49 */
1639644570b8SJeff Kirsher 	/* Clear the remote byte count registers. */
1640644570b8SJeff Kirsher 	outb_p(0x00,  e8390_base + EN0_RCNTLO);
1641644570b8SJeff Kirsher 	outb_p(0x00,  e8390_base + EN0_RCNTHI);
1642644570b8SJeff Kirsher 	/* Set to monitor and loopback mode -- this is vital!. */
1643644570b8SJeff Kirsher 	outb_p(E8390_RXOFF|0x40, e8390_base + EN0_RXCR); /* 0x60 */
1644644570b8SJeff Kirsher 	outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
1645644570b8SJeff Kirsher 	/* Set the transmit page and receive ring. */
1646644570b8SJeff Kirsher 	outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
1647644570b8SJeff Kirsher 	ei_local->tx1 = ei_local->tx2 = 0;
1648644570b8SJeff Kirsher 	outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
1649644570b8SJeff Kirsher 	outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY);	/* 3c503 says 0x3f,NS0x26*/
1650644570b8SJeff Kirsher 	ei_local->current_page = ei_local->rx_start_page;		/* assert boundary+1 */
1651644570b8SJeff Kirsher 	outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
1652644570b8SJeff Kirsher 	/* Clear the pending interrupts and mask. */
1653644570b8SJeff Kirsher 	outb_p(0xFF, e8390_base + EN0_ISR);
1654644570b8SJeff Kirsher 	outb_p(0x00,  e8390_base + EN0_IMR);
1655644570b8SJeff Kirsher 
1656644570b8SJeff Kirsher 	/* Copy the station address into the DS8390 registers. */
1657644570b8SJeff Kirsher 
1658644570b8SJeff Kirsher 	outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
1659644570b8SJeff Kirsher 	for(i = 0; i < 6; i++)
1660644570b8SJeff Kirsher 	{
1661644570b8SJeff Kirsher 		outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
1662644570b8SJeff Kirsher 		if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
1663644570b8SJeff Kirsher 			netdev_err(dev, "Hw. address read/write mismap %d\n", i);
1664644570b8SJeff Kirsher 	}
1665644570b8SJeff Kirsher 
1666644570b8SJeff Kirsher 	outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
1667644570b8SJeff Kirsher 	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
1668644570b8SJeff Kirsher 
1669644570b8SJeff Kirsher 	netif_start_queue(dev);
1670644570b8SJeff Kirsher 	ei_local->tx1 = ei_local->tx2 = 0;
1671644570b8SJeff Kirsher 	ei_local->txing = 0;
1672644570b8SJeff Kirsher 
1673644570b8SJeff Kirsher 	if (info->flags & IS_AX88790)	/* select Internal PHY */
1674644570b8SJeff Kirsher 		outb(0x10, e8390_base + AXNET_GPIO);
1675644570b8SJeff Kirsher 
1676644570b8SJeff Kirsher 	if (startp)
1677644570b8SJeff Kirsher 	{
1678644570b8SJeff Kirsher 		outb_p(0xff,  e8390_base + EN0_ISR);
1679644570b8SJeff Kirsher 		outb_p(ENISR_ALL,  e8390_base + EN0_IMR);
1680644570b8SJeff Kirsher 		outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
1681644570b8SJeff Kirsher 		outb_p(E8390_TXCONFIG | info->duplex_flag,
1682644570b8SJeff Kirsher 		       e8390_base + EN0_TXCR); /* xmit on. */
1683644570b8SJeff Kirsher 		/* 3c503 TechMan says rxconfig only after the NIC is started. */
1684644570b8SJeff Kirsher 		outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); /* rx on, */
1685644570b8SJeff Kirsher 		do_set_multicast_list(dev);	/* (re)load the mcast table */
1686644570b8SJeff Kirsher 	}
1687644570b8SJeff Kirsher }
1688644570b8SJeff Kirsher 
1689644570b8SJeff Kirsher /* Trigger a transmit start, assuming the length is valid.
1690644570b8SJeff Kirsher    Always called with the page lock held */
1691644570b8SJeff Kirsher 
NS8390_trigger_send(struct net_device * dev,unsigned int length,int start_page)1692644570b8SJeff Kirsher static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
1693644570b8SJeff Kirsher 								int start_page)
1694644570b8SJeff Kirsher {
1695644570b8SJeff Kirsher 	long e8390_base = dev->base_addr;
1696644570b8SJeff Kirsher  	struct ei_device *ei_local __attribute((unused)) = netdev_priv(dev);
1697644570b8SJeff Kirsher 
1698644570b8SJeff Kirsher 	if (inb_p(e8390_base) & E8390_TRANS)
1699644570b8SJeff Kirsher 	{
1700644570b8SJeff Kirsher 		netdev_warn(dev, "trigger_send() called with the transmitter busy\n");
1701644570b8SJeff Kirsher 		return;
1702644570b8SJeff Kirsher 	}
1703644570b8SJeff Kirsher 	outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
1704644570b8SJeff Kirsher 	outb_p(length >> 8, e8390_base + EN0_TCNTHI);
1705644570b8SJeff Kirsher 	outb_p(start_page, e8390_base + EN0_TPSR);
1706644570b8SJeff Kirsher 	outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD);
1707644570b8SJeff Kirsher }
1708