xref: /openbmc/linux/drivers/net/ethernet/8390/apne.c (revision 9f07af05)
1*9f07af05SBagas Sanjaya // SPDX-License-Identifier: GPL-2.0-only
2644570b8SJeff Kirsher /*
3644570b8SJeff Kirsher  * Amiga Linux/68k 8390 based PCMCIA Ethernet Driver for the Amiga 1200
4644570b8SJeff Kirsher  *
5644570b8SJeff Kirsher  * (C) Copyright 1997 Alain Malek
6644570b8SJeff Kirsher  *                    (Alain.Malek@cryogen.com)
7644570b8SJeff Kirsher  *
8644570b8SJeff Kirsher  * ----------------------------------------------------------------------------
9644570b8SJeff Kirsher  *
10644570b8SJeff Kirsher  * This program is based on
11644570b8SJeff Kirsher  *
12644570b8SJeff Kirsher  * ne.c:       A general non-shared-memory NS8390 ethernet driver for linux
13644570b8SJeff Kirsher  *             Written 1992-94 by Donald Becker.
14644570b8SJeff Kirsher  *
15644570b8SJeff Kirsher  * 8390.c:     A general NS8390 ethernet driver core for linux.
16644570b8SJeff Kirsher  *             Written 1992-94 by Donald Becker.
17644570b8SJeff Kirsher  *
18644570b8SJeff Kirsher  * cnetdevice: A Sana-II ethernet driver for AmigaOS
19644570b8SJeff Kirsher  *             Written by Bruce Abbott (bhabbott@inhb.co.nz)
20644570b8SJeff Kirsher  *
21644570b8SJeff Kirsher  * ----------------------------------------------------------------------------
22644570b8SJeff Kirsher  *
23644570b8SJeff Kirsher  */
24644570b8SJeff Kirsher 
25644570b8SJeff Kirsher 
26644570b8SJeff Kirsher #include <linux/module.h>
27644570b8SJeff Kirsher #include <linux/kernel.h>
28644570b8SJeff Kirsher #include <linux/errno.h>
29644570b8SJeff Kirsher #include <linux/pci.h>
30644570b8SJeff Kirsher #include <linux/init.h>
31644570b8SJeff Kirsher #include <linux/delay.h>
32644570b8SJeff Kirsher #include <linux/netdevice.h>
33644570b8SJeff Kirsher #include <linux/etherdevice.h>
34644570b8SJeff Kirsher #include <linux/interrupt.h>
35644570b8SJeff Kirsher #include <linux/jiffies.h>
36644570b8SJeff Kirsher 
37644570b8SJeff Kirsher #include <asm/io.h>
38644570b8SJeff Kirsher #include <asm/setup.h>
39644570b8SJeff Kirsher #include <asm/amigaints.h>
40644570b8SJeff Kirsher #include <asm/amigahw.h>
41644570b8SJeff Kirsher #include <asm/amigayle.h>
42644570b8SJeff Kirsher #include <asm/amipcmcia.h>
43644570b8SJeff Kirsher 
44644570b8SJeff Kirsher #include "8390.h"
45644570b8SJeff Kirsher 
46644570b8SJeff Kirsher /* ---- No user-serviceable parts below ---- */
47644570b8SJeff Kirsher 
48644570b8SJeff Kirsher #define DRV_NAME "apne"
49644570b8SJeff Kirsher 
50644570b8SJeff Kirsher #define NE_BASE	 (dev->base_addr)
51644570b8SJeff Kirsher #define NE_CMD	 		0x00
52644570b8SJeff Kirsher #define NE_DATAPORT		0x10            /* NatSemi-defined port window offset. */
53644570b8SJeff Kirsher #define NE_RESET		0x1f            /* Issue a read to reset, a write to clear. */
54644570b8SJeff Kirsher #define NE_IO_EXTENT	        0x20
55644570b8SJeff Kirsher 
56644570b8SJeff Kirsher #define NE_EN0_ISR		0x07
57644570b8SJeff Kirsher #define NE_EN0_DCFG		0x0e
58644570b8SJeff Kirsher 
59644570b8SJeff Kirsher #define NE_EN0_RSARLO	        0x08
60644570b8SJeff Kirsher #define NE_EN0_RSARHI	        0x09
61644570b8SJeff Kirsher #define NE_EN0_RCNTLO	        0x0a
62644570b8SJeff Kirsher #define NE_EN0_RXCR		0x0c
63644570b8SJeff Kirsher #define NE_EN0_TXCR		0x0d
64644570b8SJeff Kirsher #define NE_EN0_RCNTHI	        0x0b
65644570b8SJeff Kirsher #define NE_EN0_IMR		0x0f
66644570b8SJeff Kirsher 
67644570b8SJeff Kirsher #define NE1SM_START_PG	0x20	/* First page of TX buffer */
68644570b8SJeff Kirsher #define NE1SM_STOP_PG 	0x40	/* Last page +1 of RX ring */
69644570b8SJeff Kirsher #define NESM_START_PG	0x40	/* First page of TX buffer */
70644570b8SJeff Kirsher #define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
71644570b8SJeff Kirsher 
72644570b8SJeff Kirsher 
73644570b8SJeff Kirsher static int apne_probe1(struct net_device *dev, int ioaddr);
74644570b8SJeff Kirsher 
75644570b8SJeff Kirsher static void apne_reset_8390(struct net_device *dev);
76644570b8SJeff Kirsher static void apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
77644570b8SJeff Kirsher 			  int ring_page);
78644570b8SJeff Kirsher static void apne_block_input(struct net_device *dev, int count,
79644570b8SJeff Kirsher 								struct sk_buff *skb, int ring_offset);
80644570b8SJeff Kirsher static void apne_block_output(struct net_device *dev, const int count,
81644570b8SJeff Kirsher 							const unsigned char *buf, const int start_page);
82644570b8SJeff Kirsher static irqreturn_t apne_interrupt(int irq, void *dev_id);
83644570b8SJeff Kirsher 
84644570b8SJeff Kirsher static int init_pcmcia(void);
85644570b8SJeff Kirsher 
86644570b8SJeff Kirsher /* IO base address used for nic */
87644570b8SJeff Kirsher 
88644570b8SJeff Kirsher #define IOBASE 0x300
89644570b8SJeff Kirsher 
90644570b8SJeff Kirsher /*
91644570b8SJeff Kirsher    use MANUAL_CONFIG and MANUAL_OFFSET for enabling IO by hand
92644570b8SJeff Kirsher    you can find the values to use by looking at the cnet.device
93644570b8SJeff Kirsher    config file example (the default values are for the CNET40BC card)
94644570b8SJeff Kirsher */
95644570b8SJeff Kirsher 
96644570b8SJeff Kirsher /*
97644570b8SJeff Kirsher #define MANUAL_CONFIG 0x20
98644570b8SJeff Kirsher #define MANUAL_OFFSET 0x3f8
99644570b8SJeff Kirsher 
100644570b8SJeff Kirsher #define MANUAL_HWADDR0 0x00
101644570b8SJeff Kirsher #define MANUAL_HWADDR1 0x12
102644570b8SJeff Kirsher #define MANUAL_HWADDR2 0x34
103644570b8SJeff Kirsher #define MANUAL_HWADDR3 0x56
104644570b8SJeff Kirsher #define MANUAL_HWADDR4 0x78
105644570b8SJeff Kirsher #define MANUAL_HWADDR5 0x9a
106644570b8SJeff Kirsher */
107644570b8SJeff Kirsher 
108644570b8SJeff Kirsher static const char version[] =
109644570b8SJeff Kirsher     "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n";
110644570b8SJeff Kirsher 
111644570b8SJeff Kirsher static int apne_owned;	/* signal if card already owned */
112644570b8SJeff Kirsher 
113c45f812fSMatthew Whitehead static u32 apne_msg_enable;
114d3757ba4SJoe Perches module_param_named(msg_enable, apne_msg_enable, uint, 0444);
115c45f812fSMatthew Whitehead MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)");
116c45f812fSMatthew Whitehead 
apne_probe(void)117e179d78eSArnd Bergmann static struct net_device * __init apne_probe(void)
118644570b8SJeff Kirsher {
119644570b8SJeff Kirsher 	struct net_device *dev;
120c45f812fSMatthew Whitehead 	struct ei_device *ei_local;
121c45f812fSMatthew Whitehead 
122644570b8SJeff Kirsher #ifndef MANUAL_CONFIG
123644570b8SJeff Kirsher 	char tuple[8];
124644570b8SJeff Kirsher #endif
125644570b8SJeff Kirsher 	int err;
126644570b8SJeff Kirsher 
127644570b8SJeff Kirsher 	if (!MACH_IS_AMIGA)
128644570b8SJeff Kirsher 		return ERR_PTR(-ENODEV);
129644570b8SJeff Kirsher 
130644570b8SJeff Kirsher 	if (apne_owned)
131644570b8SJeff Kirsher 		return ERR_PTR(-ENODEV);
132644570b8SJeff Kirsher 
133644570b8SJeff Kirsher 	if ( !(AMIGAHW_PRESENT(PCMCIA)) )
134644570b8SJeff Kirsher 		return ERR_PTR(-ENODEV);
135644570b8SJeff Kirsher 
136c45f812fSMatthew Whitehead 	pr_info("Looking for PCMCIA ethernet card : ");
137644570b8SJeff Kirsher 
138644570b8SJeff Kirsher 	/* check if a card is inserted */
139644570b8SJeff Kirsher 	if (!(PCMCIA_INSERTED)) {
140c45f812fSMatthew Whitehead 		pr_cont("NO PCMCIA card inserted\n");
141644570b8SJeff Kirsher 		return ERR_PTR(-ENODEV);
142644570b8SJeff Kirsher 	}
143644570b8SJeff Kirsher 
144644570b8SJeff Kirsher 	dev = alloc_ei_netdev();
145644570b8SJeff Kirsher 	if (!dev)
146644570b8SJeff Kirsher 		return ERR_PTR(-ENOMEM);
147c45f812fSMatthew Whitehead 	ei_local = netdev_priv(dev);
148c45f812fSMatthew Whitehead 	ei_local->msg_enable = apne_msg_enable;
149644570b8SJeff Kirsher 
150644570b8SJeff Kirsher 	/* disable pcmcia irq for readtuple */
151644570b8SJeff Kirsher 	pcmcia_disable_irq();
152644570b8SJeff Kirsher 
153644570b8SJeff Kirsher #ifndef MANUAL_CONFIG
154644570b8SJeff Kirsher 	if ((pcmcia_copy_tuple(CISTPL_FUNCID, tuple, 8) < 3) ||
155644570b8SJeff Kirsher 		(tuple[2] != CISTPL_FUNCID_NETWORK)) {
156c45f812fSMatthew Whitehead 		pr_cont("not an ethernet card\n");
157644570b8SJeff Kirsher 		/* XXX: shouldn't we re-enable irq here? */
158644570b8SJeff Kirsher 		free_netdev(dev);
159644570b8SJeff Kirsher 		return ERR_PTR(-ENODEV);
160644570b8SJeff Kirsher 	}
161644570b8SJeff Kirsher #endif
162644570b8SJeff Kirsher 
163c45f812fSMatthew Whitehead 	pr_cont("ethernet PCMCIA card inserted\n");
164644570b8SJeff Kirsher 
165644570b8SJeff Kirsher 	if (!init_pcmcia()) {
166644570b8SJeff Kirsher 		/* XXX: shouldn't we re-enable irq here? */
167644570b8SJeff Kirsher 		free_netdev(dev);
168644570b8SJeff Kirsher 		return ERR_PTR(-ENODEV);
169644570b8SJeff Kirsher 	}
170644570b8SJeff Kirsher 
171644570b8SJeff Kirsher 	if (!request_region(IOBASE, 0x20, DRV_NAME)) {
172644570b8SJeff Kirsher 		free_netdev(dev);
173644570b8SJeff Kirsher 		return ERR_PTR(-EBUSY);
174644570b8SJeff Kirsher 	}
175644570b8SJeff Kirsher 
176644570b8SJeff Kirsher 	err = apne_probe1(dev, IOBASE);
177644570b8SJeff Kirsher 	if (err) {
178644570b8SJeff Kirsher 		release_region(IOBASE, 0x20);
179644570b8SJeff Kirsher 		free_netdev(dev);
180644570b8SJeff Kirsher 		return ERR_PTR(err);
181644570b8SJeff Kirsher 	}
182644570b8SJeff Kirsher 	err = register_netdev(dev);
183644570b8SJeff Kirsher 	if (!err)
184644570b8SJeff Kirsher 		return dev;
185644570b8SJeff Kirsher 
186644570b8SJeff Kirsher 	pcmcia_disable_irq();
187644570b8SJeff Kirsher 	free_irq(IRQ_AMIGA_PORTS, dev);
188644570b8SJeff Kirsher 	pcmcia_reset();
189644570b8SJeff Kirsher 	release_region(IOBASE, 0x20);
190644570b8SJeff Kirsher 	free_netdev(dev);
191644570b8SJeff Kirsher 	return ERR_PTR(err);
192644570b8SJeff Kirsher }
193644570b8SJeff Kirsher 
apne_probe1(struct net_device * dev,int ioaddr)194644570b8SJeff Kirsher static int __init apne_probe1(struct net_device *dev, int ioaddr)
195644570b8SJeff Kirsher {
196644570b8SJeff Kirsher     int i;
197644570b8SJeff Kirsher     unsigned char SA_prom[32];
198644570b8SJeff Kirsher     int wordlength = 2;
199644570b8SJeff Kirsher     const char *name = NULL;
200644570b8SJeff Kirsher     int start_page, stop_page;
201644570b8SJeff Kirsher #ifndef MANUAL_HWADDR0
202644570b8SJeff Kirsher     int neX000, ctron;
203644570b8SJeff Kirsher #endif
204644570b8SJeff Kirsher     static unsigned version_printed;
205644570b8SJeff Kirsher 
206c45f812fSMatthew Whitehead     if ((apne_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0))
207c45f812fSMatthew Whitehead 		netdev_info(dev, version);
208644570b8SJeff Kirsher 
209c45f812fSMatthew Whitehead     netdev_info(dev, "PCMCIA NE*000 ethercard probe");
210644570b8SJeff Kirsher 
211644570b8SJeff Kirsher     /* Reset card. Who knows what dain-bramaged state it was left in. */
212644570b8SJeff Kirsher     {	unsigned long reset_start_time = jiffies;
213644570b8SJeff Kirsher 
214644570b8SJeff Kirsher 	outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
215644570b8SJeff Kirsher 
216644570b8SJeff Kirsher 	while ((inb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
217644570b8SJeff Kirsher 		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
218c45f812fSMatthew Whitehead 			pr_cont(" not found (no reset ack).\n");
219644570b8SJeff Kirsher 			return -ENODEV;
220644570b8SJeff Kirsher 		}
221644570b8SJeff Kirsher 
222644570b8SJeff Kirsher 	outb(0xff, ioaddr + NE_EN0_ISR);		/* Ack all intr. */
223644570b8SJeff Kirsher     }
224644570b8SJeff Kirsher 
225644570b8SJeff Kirsher #ifndef MANUAL_HWADDR0
226644570b8SJeff Kirsher 
227644570b8SJeff Kirsher     /* Read the 16 bytes of station address PROM.
228644570b8SJeff Kirsher        We must first initialize registers, similar to NS8390_init(eifdev, 0).
229644570b8SJeff Kirsher        We can't reliably read the SAPROM address without this.
230644570b8SJeff Kirsher        (I learned the hard way!). */
231644570b8SJeff Kirsher     {
232644570b8SJeff Kirsher 	struct {unsigned long value, offset; } program_seq[] = {
233644570b8SJeff Kirsher 	    {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/
234644570b8SJeff Kirsher 	    {0x48,	NE_EN0_DCFG},	/* Set byte-wide (0x48) access. */
235644570b8SJeff Kirsher 	    {0x00,	NE_EN0_RCNTLO},	/* Clear the count regs. */
236644570b8SJeff Kirsher 	    {0x00,	NE_EN0_RCNTHI},
237644570b8SJeff Kirsher 	    {0x00,	NE_EN0_IMR},	/* Mask completion irq. */
238644570b8SJeff Kirsher 	    {0xFF,	NE_EN0_ISR},
239644570b8SJeff Kirsher 	    {E8390_RXOFF, NE_EN0_RXCR},	/* 0x20  Set to monitor */
240644570b8SJeff Kirsher 	    {E8390_TXOFF, NE_EN0_TXCR},	/* 0x02  and loopback mode. */
241644570b8SJeff Kirsher 	    {32,	NE_EN0_RCNTLO},
242644570b8SJeff Kirsher 	    {0x00,	NE_EN0_RCNTHI},
243644570b8SJeff Kirsher 	    {0x00,	NE_EN0_RSARLO},	/* DMA starting at 0x0000. */
244644570b8SJeff Kirsher 	    {0x00,	NE_EN0_RSARHI},
245644570b8SJeff Kirsher 	    {E8390_RREAD+E8390_START, NE_CMD},
246644570b8SJeff Kirsher 	};
247644570b8SJeff Kirsher 	for (i = 0; i < ARRAY_SIZE(program_seq); i++) {
248644570b8SJeff Kirsher 	    outb(program_seq[i].value, ioaddr + program_seq[i].offset);
249644570b8SJeff Kirsher 	}
250644570b8SJeff Kirsher 
251644570b8SJeff Kirsher     }
252644570b8SJeff Kirsher     for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
253644570b8SJeff Kirsher 	SA_prom[i] = inb(ioaddr + NE_DATAPORT);
254644570b8SJeff Kirsher 	SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
255644570b8SJeff Kirsher 	if (SA_prom[i] != SA_prom[i+1])
256644570b8SJeff Kirsher 	    wordlength = 1;
257644570b8SJeff Kirsher     }
258644570b8SJeff Kirsher 
259644570b8SJeff Kirsher     /*	At this point, wordlength *only* tells us if the SA_prom is doubled
260644570b8SJeff Kirsher 	up or not because some broken PCI cards don't respect the byte-wide
261644570b8SJeff Kirsher 	request in program_seq above, and hence don't have doubled up values.
262644570b8SJeff Kirsher 	These broken cards would otherwise be detected as an ne1000.  */
263644570b8SJeff Kirsher 
264644570b8SJeff Kirsher     if (wordlength == 2)
265644570b8SJeff Kirsher 	for (i = 0; i < 16; i++)
266644570b8SJeff Kirsher 		SA_prom[i] = SA_prom[i+i];
267644570b8SJeff Kirsher 
268644570b8SJeff Kirsher     if (wordlength == 2) {
269644570b8SJeff Kirsher 	/* We must set the 8390 for word mode. */
270644570b8SJeff Kirsher 	outb(0x49, ioaddr + NE_EN0_DCFG);
271644570b8SJeff Kirsher 	start_page = NESM_START_PG;
272644570b8SJeff Kirsher 	stop_page = NESM_STOP_PG;
273644570b8SJeff Kirsher     } else {
274644570b8SJeff Kirsher 	start_page = NE1SM_START_PG;
275644570b8SJeff Kirsher 	stop_page = NE1SM_STOP_PG;
276644570b8SJeff Kirsher     }
277644570b8SJeff Kirsher 
278644570b8SJeff Kirsher     neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
279644570b8SJeff Kirsher     ctron =  (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
280644570b8SJeff Kirsher 
281644570b8SJeff Kirsher     /* Set up the rest of the parameters. */
282644570b8SJeff Kirsher     if (neX000) {
283644570b8SJeff Kirsher 	name = (wordlength == 2) ? "NE2000" : "NE1000";
284644570b8SJeff Kirsher     } else if (ctron) {
285644570b8SJeff Kirsher 	name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
286644570b8SJeff Kirsher 	start_page = 0x01;
287644570b8SJeff Kirsher 	stop_page = (wordlength == 2) ? 0x40 : 0x20;
288644570b8SJeff Kirsher     } else {
289c45f812fSMatthew Whitehead 	pr_cont(" not found.\n");
290644570b8SJeff Kirsher 	return -ENXIO;
291644570b8SJeff Kirsher 
292644570b8SJeff Kirsher     }
293644570b8SJeff Kirsher 
294644570b8SJeff Kirsher #else
295644570b8SJeff Kirsher     wordlength = 2;
296644570b8SJeff Kirsher     /* We must set the 8390 for word mode. */
297644570b8SJeff Kirsher     outb(0x49, ioaddr + NE_EN0_DCFG);
298644570b8SJeff Kirsher     start_page = NESM_START_PG;
299644570b8SJeff Kirsher     stop_page = NESM_STOP_PG;
300644570b8SJeff Kirsher 
301644570b8SJeff Kirsher     SA_prom[0] = MANUAL_HWADDR0;
302644570b8SJeff Kirsher     SA_prom[1] = MANUAL_HWADDR1;
303644570b8SJeff Kirsher     SA_prom[2] = MANUAL_HWADDR2;
304644570b8SJeff Kirsher     SA_prom[3] = MANUAL_HWADDR3;
305644570b8SJeff Kirsher     SA_prom[4] = MANUAL_HWADDR4;
306644570b8SJeff Kirsher     SA_prom[5] = MANUAL_HWADDR5;
307644570b8SJeff Kirsher     name = "NE2000";
308644570b8SJeff Kirsher #endif
309644570b8SJeff Kirsher 
310644570b8SJeff Kirsher     dev->base_addr = ioaddr;
311644570b8SJeff Kirsher     dev->irq = IRQ_AMIGA_PORTS;
312644570b8SJeff Kirsher     dev->netdev_ops = &ei_netdev_ops;
313644570b8SJeff Kirsher 
314644570b8SJeff Kirsher     /* Install the Interrupt handler */
315644570b8SJeff Kirsher     i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);
316644570b8SJeff Kirsher     if (i) return i;
317644570b8SJeff Kirsher 
3188ce218b6SJakub Kicinski     eth_hw_addr_set(dev, SA_prom);
319644570b8SJeff Kirsher 
320c45f812fSMatthew Whitehead     pr_cont(" %pM\n", dev->dev_addr);
321644570b8SJeff Kirsher 
322c45f812fSMatthew Whitehead     netdev_info(dev, "%s found.\n", name);
323644570b8SJeff Kirsher 
324644570b8SJeff Kirsher     ei_status.name = name;
325644570b8SJeff Kirsher     ei_status.tx_start_page = start_page;
326644570b8SJeff Kirsher     ei_status.stop_page = stop_page;
327644570b8SJeff Kirsher     ei_status.word16 = (wordlength == 2);
328644570b8SJeff Kirsher 
329644570b8SJeff Kirsher     ei_status.rx_start_page = start_page + TX_PAGES;
330644570b8SJeff Kirsher 
331644570b8SJeff Kirsher     ei_status.reset_8390 = &apne_reset_8390;
332644570b8SJeff Kirsher     ei_status.block_input = &apne_block_input;
333644570b8SJeff Kirsher     ei_status.block_output = &apne_block_output;
334644570b8SJeff Kirsher     ei_status.get_8390_hdr = &apne_get_8390_hdr;
335644570b8SJeff Kirsher 
336644570b8SJeff Kirsher     NS8390_init(dev, 0);
337644570b8SJeff Kirsher 
338644570b8SJeff Kirsher     pcmcia_ack_int(pcmcia_get_intreq());		/* ack PCMCIA int req */
339644570b8SJeff Kirsher     pcmcia_enable_irq();
340644570b8SJeff Kirsher 
341644570b8SJeff Kirsher     apne_owned = 1;
342644570b8SJeff Kirsher 
343644570b8SJeff Kirsher     return 0;
344644570b8SJeff Kirsher }
345644570b8SJeff Kirsher 
346644570b8SJeff Kirsher /* Hard reset the card.  This used to pause for the same period that a
347644570b8SJeff Kirsher    8390 reset command required, but that shouldn't be necessary. */
348644570b8SJeff Kirsher static void
apne_reset_8390(struct net_device * dev)349644570b8SJeff Kirsher apne_reset_8390(struct net_device *dev)
350644570b8SJeff Kirsher {
351644570b8SJeff Kirsher     unsigned long reset_start_time = jiffies;
352c45f812fSMatthew Whitehead     struct ei_device *ei_local = netdev_priv(dev);
353644570b8SJeff Kirsher 
354644570b8SJeff Kirsher     init_pcmcia();
355644570b8SJeff Kirsher 
356c45f812fSMatthew Whitehead     netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies);
357644570b8SJeff Kirsher 
358644570b8SJeff Kirsher     outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
359644570b8SJeff Kirsher 
360644570b8SJeff Kirsher     ei_status.txing = 0;
361644570b8SJeff Kirsher     ei_status.dmaing = 0;
362644570b8SJeff Kirsher 
363644570b8SJeff Kirsher     /* This check _should_not_ be necessary, omit eventually. */
364644570b8SJeff Kirsher     while ((inb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
365644570b8SJeff Kirsher 	if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
366c45f812fSMatthew Whitehead 		netdev_err(dev, "ne_reset_8390() did not complete.\n");
367644570b8SJeff Kirsher 		break;
368644570b8SJeff Kirsher 	}
369644570b8SJeff Kirsher     outb(ENISR_RESET, NE_BASE + NE_EN0_ISR);	/* Ack intr. */
370644570b8SJeff Kirsher }
371644570b8SJeff Kirsher 
372644570b8SJeff Kirsher /* Grab the 8390 specific header. Similar to the block_input routine, but
373644570b8SJeff Kirsher    we don't need to be concerned with ring wrap as the header will be at
374644570b8SJeff Kirsher    the start of a page, so we optimize accordingly. */
375644570b8SJeff Kirsher 
376644570b8SJeff Kirsher static void
apne_get_8390_hdr(struct net_device * dev,struct e8390_pkt_hdr * hdr,int ring_page)377644570b8SJeff Kirsher apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
378644570b8SJeff Kirsher {
379644570b8SJeff Kirsher 
380644570b8SJeff Kirsher     int nic_base = dev->base_addr;
381644570b8SJeff Kirsher     int cnt;
382644570b8SJeff Kirsher     char *ptrc;
383644570b8SJeff Kirsher     short *ptrs;
384644570b8SJeff Kirsher 
385644570b8SJeff Kirsher     /* This *shouldn't* happen. If it does, it's the last thing you'll see */
386644570b8SJeff Kirsher     if (ei_status.dmaing) {
387c45f812fSMatthew Whitehead 	netdev_err(dev, "DMAing conflict in ne_get_8390_hdr "
388644570b8SJeff Kirsher 		   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
389c45f812fSMatthew Whitehead 		   ei_status.dmaing, ei_status.irqlock, dev->irq);
390644570b8SJeff Kirsher 	return;
391644570b8SJeff Kirsher     }
392644570b8SJeff Kirsher 
393644570b8SJeff Kirsher     ei_status.dmaing |= 0x01;
394644570b8SJeff Kirsher     outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
395644570b8SJeff Kirsher     outb(ENISR_RDC, nic_base + NE_EN0_ISR);
396644570b8SJeff Kirsher     outb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO);
397644570b8SJeff Kirsher     outb(0, nic_base + NE_EN0_RCNTHI);
398644570b8SJeff Kirsher     outb(0, nic_base + NE_EN0_RSARLO);		/* On page boundary */
399644570b8SJeff Kirsher     outb(ring_page, nic_base + NE_EN0_RSARHI);
400644570b8SJeff Kirsher     outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
401644570b8SJeff Kirsher 
402644570b8SJeff Kirsher     if (ei_status.word16) {
403644570b8SJeff Kirsher         ptrs = (short*)hdr;
404644570b8SJeff Kirsher         for(cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++)
405644570b8SJeff Kirsher             *ptrs++ = inw(NE_BASE + NE_DATAPORT);
406644570b8SJeff Kirsher     } else {
407644570b8SJeff Kirsher         ptrc = (char*)hdr;
408644570b8SJeff Kirsher         for(cnt = 0; cnt < sizeof(struct e8390_pkt_hdr); cnt++)
409644570b8SJeff Kirsher             *ptrc++ = inb(NE_BASE + NE_DATAPORT);
410644570b8SJeff Kirsher     }
411644570b8SJeff Kirsher 
412644570b8SJeff Kirsher     outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
413644570b8SJeff Kirsher     ei_status.dmaing &= ~0x01;
414644570b8SJeff Kirsher 
415644570b8SJeff Kirsher     le16_to_cpus(&hdr->count);
416644570b8SJeff Kirsher }
417644570b8SJeff Kirsher 
418644570b8SJeff Kirsher /* Block input and output, similar to the Crynwr packet driver.  If you
419644570b8SJeff Kirsher    are porting to a new ethercard, look at the packet driver source for hints.
420644570b8SJeff Kirsher    The NEx000 doesn't share the on-board packet memory -- you have to put
421644570b8SJeff Kirsher    the packet out through the "remote DMA" dataport using outb. */
422644570b8SJeff Kirsher 
423644570b8SJeff Kirsher static void
apne_block_input(struct net_device * dev,int count,struct sk_buff * skb,int ring_offset)424644570b8SJeff Kirsher apne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
425644570b8SJeff Kirsher {
426644570b8SJeff Kirsher     int nic_base = dev->base_addr;
427644570b8SJeff Kirsher     char *buf = skb->data;
428644570b8SJeff Kirsher     char *ptrc;
429644570b8SJeff Kirsher     short *ptrs;
430644570b8SJeff Kirsher     int cnt;
431644570b8SJeff Kirsher 
432644570b8SJeff Kirsher     /* This *shouldn't* happen. If it does, it's the last thing you'll see */
433644570b8SJeff Kirsher     if (ei_status.dmaing) {
434c45f812fSMatthew Whitehead 		netdev_err(dev, "DMAing conflict in ne_block_input "
435644570b8SJeff Kirsher 			   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
436c45f812fSMatthew Whitehead 			   ei_status.dmaing, ei_status.irqlock, dev->irq);
437644570b8SJeff Kirsher 	return;
438644570b8SJeff Kirsher     }
439644570b8SJeff Kirsher     ei_status.dmaing |= 0x01;
440644570b8SJeff Kirsher     outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
441644570b8SJeff Kirsher     outb(ENISR_RDC, nic_base + NE_EN0_ISR);
442644570b8SJeff Kirsher     outb(count & 0xff, nic_base + NE_EN0_RCNTLO);
443644570b8SJeff Kirsher     outb(count >> 8, nic_base + NE_EN0_RCNTHI);
444644570b8SJeff Kirsher     outb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);
445644570b8SJeff Kirsher     outb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);
446644570b8SJeff Kirsher     outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
447644570b8SJeff Kirsher     if (ei_status.word16) {
448644570b8SJeff Kirsher       ptrs = (short*)buf;
449644570b8SJeff Kirsher       for (cnt = 0; cnt < (count>>1); cnt++)
450644570b8SJeff Kirsher         *ptrs++ = inw(NE_BASE + NE_DATAPORT);
451644570b8SJeff Kirsher       if (count & 0x01) {
452644570b8SJeff Kirsher 	buf[count-1] = inb(NE_BASE + NE_DATAPORT);
453644570b8SJeff Kirsher       }
454644570b8SJeff Kirsher     } else {
45564699336SJoe Perches       ptrc = buf;
456644570b8SJeff Kirsher       for (cnt = 0; cnt < count; cnt++)
457644570b8SJeff Kirsher         *ptrc++ = inb(NE_BASE + NE_DATAPORT);
458644570b8SJeff Kirsher     }
459644570b8SJeff Kirsher 
460644570b8SJeff Kirsher     outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
461644570b8SJeff Kirsher     ei_status.dmaing &= ~0x01;
462644570b8SJeff Kirsher }
463644570b8SJeff Kirsher 
464644570b8SJeff Kirsher static void
apne_block_output(struct net_device * dev,int count,const unsigned char * buf,const int start_page)465644570b8SJeff Kirsher apne_block_output(struct net_device *dev, int count,
466644570b8SJeff Kirsher 		const unsigned char *buf, const int start_page)
467644570b8SJeff Kirsher {
468644570b8SJeff Kirsher     int nic_base = NE_BASE;
469644570b8SJeff Kirsher     unsigned long dma_start;
470644570b8SJeff Kirsher     char *ptrc;
471644570b8SJeff Kirsher     short *ptrs;
472644570b8SJeff Kirsher     int cnt;
473644570b8SJeff Kirsher 
474644570b8SJeff Kirsher     /* Round the count up for word writes.  Do we need to do this?
475644570b8SJeff Kirsher        What effect will an odd byte count have on the 8390?
476644570b8SJeff Kirsher        I should check someday. */
477644570b8SJeff Kirsher     if (ei_status.word16 && (count & 0x01))
478644570b8SJeff Kirsher       count++;
479644570b8SJeff Kirsher 
480644570b8SJeff Kirsher     /* This *shouldn't* happen. If it does, it's the last thing you'll see */
481644570b8SJeff Kirsher     if (ei_status.dmaing) {
482c45f812fSMatthew Whitehead 		netdev_err(dev, "DMAing conflict in ne_block_output."
483644570b8SJeff Kirsher 			   "[DMAstat:%d][irqlock:%d][intr:%d]\n",
484c45f812fSMatthew Whitehead 			   ei_status.dmaing, ei_status.irqlock, dev->irq);
485644570b8SJeff Kirsher 	return;
486644570b8SJeff Kirsher     }
487644570b8SJeff Kirsher     ei_status.dmaing |= 0x01;
488644570b8SJeff Kirsher     /* We should already be in page 0, but to be safe... */
489644570b8SJeff Kirsher     outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
490644570b8SJeff Kirsher 
491644570b8SJeff Kirsher     outb(ENISR_RDC, nic_base + NE_EN0_ISR);
492644570b8SJeff Kirsher 
493644570b8SJeff Kirsher    /* Now the normal output. */
494644570b8SJeff Kirsher     outb(count & 0xff, nic_base + NE_EN0_RCNTLO);
495644570b8SJeff Kirsher     outb(count >> 8,   nic_base + NE_EN0_RCNTHI);
496644570b8SJeff Kirsher     outb(0x00, nic_base + NE_EN0_RSARLO);
497644570b8SJeff Kirsher     outb(start_page, nic_base + NE_EN0_RSARHI);
498644570b8SJeff Kirsher 
499644570b8SJeff Kirsher     outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
500644570b8SJeff Kirsher     if (ei_status.word16) {
501644570b8SJeff Kirsher         ptrs = (short*)buf;
502644570b8SJeff Kirsher         for (cnt = 0; cnt < count>>1; cnt++)
503644570b8SJeff Kirsher             outw(*ptrs++, NE_BASE+NE_DATAPORT);
504644570b8SJeff Kirsher     } else {
505644570b8SJeff Kirsher         ptrc = (char*)buf;
506644570b8SJeff Kirsher         for (cnt = 0; cnt < count; cnt++)
507644570b8SJeff Kirsher 	    outb(*ptrc++, NE_BASE + NE_DATAPORT);
508644570b8SJeff Kirsher     }
509644570b8SJeff Kirsher 
510644570b8SJeff Kirsher     dma_start = jiffies;
511644570b8SJeff Kirsher 
512644570b8SJeff Kirsher     while ((inb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
513644570b8SJeff Kirsher 	if (time_after(jiffies, dma_start + 2*HZ/100)) {	/* 20ms */
514c45f812fSMatthew Whitehead 		netdev_warn(dev, "timeout waiting for Tx RDC.\n");
515644570b8SJeff Kirsher 		apne_reset_8390(dev);
516644570b8SJeff Kirsher 		NS8390_init(dev,1);
517644570b8SJeff Kirsher 		break;
518644570b8SJeff Kirsher 	}
519644570b8SJeff Kirsher 
520644570b8SJeff Kirsher     outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
521644570b8SJeff Kirsher     ei_status.dmaing &= ~0x01;
522644570b8SJeff Kirsher }
523644570b8SJeff Kirsher 
apne_interrupt(int irq,void * dev_id)524644570b8SJeff Kirsher static irqreturn_t apne_interrupt(int irq, void *dev_id)
525644570b8SJeff Kirsher {
526644570b8SJeff Kirsher     unsigned char pcmcia_intreq;
527644570b8SJeff Kirsher 
528644570b8SJeff Kirsher     if (!(gayle.inten & GAYLE_IRQ_IRQ))
529644570b8SJeff Kirsher         return IRQ_NONE;
530644570b8SJeff Kirsher 
531644570b8SJeff Kirsher     pcmcia_intreq = pcmcia_get_intreq();
532644570b8SJeff Kirsher 
533644570b8SJeff Kirsher     if (!(pcmcia_intreq & GAYLE_IRQ_IRQ)) {
534644570b8SJeff Kirsher         pcmcia_ack_int(pcmcia_intreq);
535644570b8SJeff Kirsher         return IRQ_NONE;
536644570b8SJeff Kirsher     }
537c45f812fSMatthew Whitehead     if (apne_msg_enable & NETIF_MSG_INTR)
538c45f812fSMatthew Whitehead 	pr_debug("pcmcia intreq = %x\n", pcmcia_intreq);
539644570b8SJeff Kirsher     pcmcia_disable_irq();			/* to get rid of the sti() within ei_interrupt */
540644570b8SJeff Kirsher     ei_interrupt(irq, dev_id);
541644570b8SJeff Kirsher     pcmcia_ack_int(pcmcia_get_intreq());
542644570b8SJeff Kirsher     pcmcia_enable_irq();
543644570b8SJeff Kirsher     return IRQ_HANDLED;
544644570b8SJeff Kirsher }
545644570b8SJeff Kirsher 
546644570b8SJeff Kirsher static struct net_device *apne_dev;
547644570b8SJeff Kirsher 
apne_module_init(void)548644570b8SJeff Kirsher static int __init apne_module_init(void)
549644570b8SJeff Kirsher {
550e179d78eSArnd Bergmann 	apne_dev = apne_probe();
5510af764e3SDuan Jiong 	return PTR_ERR_OR_ZERO(apne_dev);
552644570b8SJeff Kirsher }
553644570b8SJeff Kirsher 
apne_module_exit(void)554644570b8SJeff Kirsher static void __exit apne_module_exit(void)
555644570b8SJeff Kirsher {
556644570b8SJeff Kirsher 	unregister_netdev(apne_dev);
557644570b8SJeff Kirsher 
558644570b8SJeff Kirsher 	pcmcia_disable_irq();
559644570b8SJeff Kirsher 
560644570b8SJeff Kirsher 	free_irq(IRQ_AMIGA_PORTS, apne_dev);
561644570b8SJeff Kirsher 
562644570b8SJeff Kirsher 	pcmcia_reset();
563644570b8SJeff Kirsher 
564644570b8SJeff Kirsher 	release_region(IOBASE, 0x20);
565644570b8SJeff Kirsher 
566644570b8SJeff Kirsher 	free_netdev(apne_dev);
567644570b8SJeff Kirsher }
568644570b8SJeff Kirsher module_init(apne_module_init);
569644570b8SJeff Kirsher module_exit(apne_module_exit);
570644570b8SJeff Kirsher 
init_pcmcia(void)571644570b8SJeff Kirsher static int init_pcmcia(void)
572644570b8SJeff Kirsher {
573644570b8SJeff Kirsher 	u_char config;
574644570b8SJeff Kirsher #ifndef MANUAL_CONFIG
575644570b8SJeff Kirsher 	u_char tuple[32];
576644570b8SJeff Kirsher 	int offset_len;
577644570b8SJeff Kirsher #endif
578644570b8SJeff Kirsher 	u_long offset;
579644570b8SJeff Kirsher 
580644570b8SJeff Kirsher 	pcmcia_reset();
581644570b8SJeff Kirsher 	pcmcia_program_voltage(PCMCIA_0V);
582644570b8SJeff Kirsher 	pcmcia_access_speed(PCMCIA_SPEED_250NS);
583644570b8SJeff Kirsher 	pcmcia_write_enable();
584644570b8SJeff Kirsher 
585644570b8SJeff Kirsher #ifdef MANUAL_CONFIG
586644570b8SJeff Kirsher 	config = MANUAL_CONFIG;
587644570b8SJeff Kirsher #else
588644570b8SJeff Kirsher 	/* get and write config byte to enable IO port */
589644570b8SJeff Kirsher 
590644570b8SJeff Kirsher 	if (pcmcia_copy_tuple(CISTPL_CFTABLE_ENTRY, tuple, 32) < 3)
591644570b8SJeff Kirsher 		return 0;
592644570b8SJeff Kirsher 
593644570b8SJeff Kirsher 	config = tuple[2] & 0x3f;
594644570b8SJeff Kirsher #endif
595644570b8SJeff Kirsher #ifdef MANUAL_OFFSET
596644570b8SJeff Kirsher 	offset = MANUAL_OFFSET;
597644570b8SJeff Kirsher #else
598644570b8SJeff Kirsher 	if (pcmcia_copy_tuple(CISTPL_CONFIG, tuple, 32) < 6)
599644570b8SJeff Kirsher 		return 0;
600644570b8SJeff Kirsher 
601644570b8SJeff Kirsher 	offset_len = (tuple[2] & 0x3) + 1;
602644570b8SJeff Kirsher 	offset = 0;
603644570b8SJeff Kirsher 	while(offset_len--) {
604644570b8SJeff Kirsher 		offset = (offset << 8) | tuple[4+offset_len];
605644570b8SJeff Kirsher 	}
606644570b8SJeff Kirsher #endif
607644570b8SJeff Kirsher 
608644570b8SJeff Kirsher 	out_8(GAYLE_ATTRIBUTE+offset, config);
609644570b8SJeff Kirsher 
610644570b8SJeff Kirsher 	return 1;
611644570b8SJeff Kirsher }
612644570b8SJeff Kirsher 
613644570b8SJeff Kirsher MODULE_LICENSE("GPL");
614