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