1/* hp-plus.c: A HP PCLAN/plus ethernet driver for linux. */
2/*
3	Written 1994 by Donald Becker.
4
5	This driver is for the Hewlett Packard PC LAN (27***) plus ethercards.
6	These cards are sold under several model numbers, usually 2724*.
7
8	This software may be used and distributed according to the terms
9	of the GNU General Public License, incorporated herein by reference.
10
11	The author may be reached as becker@scyld.com, or C/O
12	Scyld Computing Corporation
13	410 Severn Ave., Suite 210
14	Annapolis MD 21403
15
16	As is often the case, a great deal of credit is owed to Russ Nelson.
17	The Crynwr packet driver was my primary source of HP-specific
18	programming information.
19*/
20
21static const char version[] =
22"hp-plus.c:v1.10 9/24/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
23
24#include <linux/module.h>
25
26#include <linux/string.h>		/* Important -- this inlines word moves. */
27#include <linux/kernel.h>
28#include <linux/errno.h>
29#include <linux/ioport.h>
30#include <linux/netdevice.h>
31#include <linux/etherdevice.h>
32#include <linux/init.h>
33#include <linux/delay.h>
34
35#include <asm/system.h>
36#include <asm/io.h>
37
38#include "8390.h"
39
40#define DRV_NAME "hp-plus"
41
42/* A zero-terminated list of I/O addresses to be probed. */
43static unsigned int hpplus_portlist[] __initdata =
44{0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0};
45
46/*
47   The HP EtherTwist chip implementation is a fairly routine DP8390
48   implementation.  It allows both shared memory and programmed-I/O buffer
49   access, using a custom interface for both.  The programmed-I/O mode is
50   entirely implemented in the HP EtherTwist chip, bypassing the problem
51   ridden built-in 8390 facilities used on NE2000 designs.  The shared
52   memory mode is likewise special, with an offset register used to make
53   packets appear at the shared memory base.  Both modes use a base and bounds
54   page register to hide the Rx ring buffer wrap -- a packet that spans the
55   end of physical buffer memory appears continuous to the driver. (c.f. the
56   3c503 and Cabletron E2100)
57
58   A special note: the internal buffer of the board is only 8 bits wide.
59   This lays several nasty traps for the unaware:
60   - the 8390 must be programmed for byte-wide operations
61   - all I/O and memory operations must work on whole words (the access
62     latches are serially preloaded and have no byte-swapping ability).
63
64   This board is laid out in I/O space much like the earlier HP boards:
65   the first 16 locations are for the board registers, and the second 16 are
66   for the 8390.  The board is easy to identify, with both a dedicated 16 bit
67   ID register and a constant 0x530* value in the upper bits of the paging
68   register.
69*/
70
71#define HP_ID			0x00	/* ID register, always 0x4850. */
72#define HP_PAGING		0x02	/* Registers visible @ 8-f, see PageName. */
73#define HPP_OPTION		0x04	/* Bitmapped options, see HP_Option.	*/
74#define HPP_OUT_ADDR	0x08	/* I/O output location in Perf_Page.	*/
75#define HPP_IN_ADDR		0x0A	/* I/O input location in Perf_Page.		*/
76#define HP_DATAPORT		0x0c	/* I/O data transfer in Perf_Page.		*/
77#define NIC_OFFSET		0x10	/* Offset to the 8390 registers.		*/
78#define HP_IO_EXTENT	32
79
80#define HP_START_PG		0x00	/* First page of TX buffer */
81#define HP_STOP_PG		0x80	/* Last page +1 of RX ring */
82
83/* The register set selected in HP_PAGING. */
84enum PageName {
85	Perf_Page = 0,				/* Normal operation. */
86	MAC_Page = 1,				/* The ethernet address (+checksum). */
87	HW_Page = 2,				/* EEPROM-loaded hardware parameters. */
88	LAN_Page = 4,				/* Transceiver selection, testing, etc. */
89	ID_Page = 6 };
90
91/* The bit definitions for the HPP_OPTION register. */
92enum HP_Option {
93	NICReset = 1, ChipReset = 2, 	/* Active low, really UNreset. */
94	EnableIRQ = 4, FakeIntr = 8, BootROMEnb = 0x10, IOEnb = 0x20,
95	MemEnable = 0x40, ZeroWait = 0x80, MemDisable = 0x1000, };
96
97static int hpp_probe1(struct net_device *dev, int ioaddr);
98
99static void hpp_reset_8390(struct net_device *dev);
100static int hpp_open(struct net_device *dev);
101static int hpp_close(struct net_device *dev);
102static void hpp_mem_block_input(struct net_device *dev, int count,
103						  struct sk_buff *skb, int ring_offset);
104static void hpp_mem_block_output(struct net_device *dev, int count,
105							const unsigned char *buf, int start_page);
106static void hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
107						  int ring_page);
108static void hpp_io_block_input(struct net_device *dev, int count,
109						  struct sk_buff *skb, int ring_offset);
110static void hpp_io_block_output(struct net_device *dev, int count,
111							const unsigned char *buf, int start_page);
112static void hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
113						  int ring_page);
114
115
116/*	Probe a list of addresses for an HP LAN+ adaptor.
117	This routine is almost boilerplate. */
118
119static int __init do_hpp_probe(struct net_device *dev)
120{
121	int i;
122	int base_addr = dev->base_addr;
123	int irq = dev->irq;
124
125	SET_MODULE_OWNER(dev);
126
127	if (base_addr > 0x1ff)		/* Check a single specified location. */
128		return hpp_probe1(dev, base_addr);
129	else if (base_addr != 0)	/* Don't probe at all. */
130		return -ENXIO;
131
132	for (i = 0; hpplus_portlist[i]; i++) {
133		if (hpp_probe1(dev, hpplus_portlist[i]) == 0)
134			return 0;
135		dev->irq = irq;
136	}
137
138	return -ENODEV;
139}
140
141#ifndef MODULE
142struct net_device * __init hp_plus_probe(int unit)
143{
144	struct net_device *dev = alloc_ei_netdev();
145	int err;
146
147	if (!dev)
148		return ERR_PTR(-ENOMEM);
149
150	sprintf(dev->name, "eth%d", unit);
151	netdev_boot_setup_check(dev);
152
153	err = do_hpp_probe(dev);
154	if (err)
155		goto out;
156	return dev;
157out:
158	free_netdev(dev);
159	return ERR_PTR(err);
160}
161#endif
162
163/* Do the interesting part of the probe at a single address. */
164static int __init hpp_probe1(struct net_device *dev, int ioaddr)
165{
166	int i, retval;
167	unsigned char checksum = 0;
168	const char name[] = "HP-PC-LAN+";
169	int mem_start;
170	static unsigned version_printed;
171
172	if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
173		return -EBUSY;
174
175	/* Check for the HP+ signature, 50 48 0x 53. */
176	if (inw(ioaddr + HP_ID) != 0x4850
177		|| (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300) {
178		retval = -ENODEV;
179		goto out;
180	}
181
182	if (ei_debug  &&  version_printed++ == 0)
183		printk(version);
184
185	printk("%s: %s at %#3x,", dev->name, name, ioaddr);
186
187	/* Retrieve and checksum the station address. */
188	outw(MAC_Page, ioaddr + HP_PAGING);
189
190	for(i = 0; i < ETHER_ADDR_LEN; i++) {
191		unsigned char inval = inb(ioaddr + 8 + i);
192		dev->dev_addr[i] = inval;
193		checksum += inval;
194		printk(" %2.2x", inval);
195	}
196	checksum += inb(ioaddr + 14);
197
198	if (checksum != 0xff) {
199		printk(" bad checksum %2.2x.\n", checksum);
200		retval = -ENODEV;
201		goto out;
202	} else {
203		/* Point at the Software Configuration Flags. */
204		outw(ID_Page, ioaddr + HP_PAGING);
205		printk(" ID %4.4x", inw(ioaddr + 12));
206	}
207
208	/* Read the IRQ line. */
209	outw(HW_Page, ioaddr + HP_PAGING);
210	{
211		int irq = inb(ioaddr + 13) & 0x0f;
212		int option = inw(ioaddr + HPP_OPTION);
213
214		dev->irq = irq;
215		if (option & MemEnable) {
216			mem_start = inw(ioaddr + 9) << 8;
217			printk(", IRQ %d, memory address %#x.\n", irq, mem_start);
218		} else {
219			mem_start = 0;
220			printk(", IRQ %d, programmed-I/O mode.\n", irq);
221		}
222	}
223
224	/* Set the wrap registers for string I/O reads.   */
225	outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
226
227	/* Set the base address to point to the NIC, not the "real" base! */
228	dev->base_addr = ioaddr + NIC_OFFSET;
229
230	dev->open = &hpp_open;
231	dev->stop = &hpp_close;
232#ifdef CONFIG_NET_POLL_CONTROLLER
233	dev->poll_controller = ei_poll;
234#endif
235
236	ei_status.name = name;
237	ei_status.word16 = 0;		/* Agggghhhhh! Debug time: 2 days! */
238	ei_status.tx_start_page = HP_START_PG;
239	ei_status.rx_start_page = HP_START_PG + TX_PAGES/2;
240	ei_status.stop_page = HP_STOP_PG;
241
242	ei_status.reset_8390 = &hpp_reset_8390;
243	ei_status.block_input = &hpp_io_block_input;
244	ei_status.block_output = &hpp_io_block_output;
245	ei_status.get_8390_hdr = &hpp_io_get_8390_hdr;
246
247	/* Check if the memory_enable flag is set in the option register. */
248	if (mem_start) {
249		ei_status.block_input = &hpp_mem_block_input;
250		ei_status.block_output = &hpp_mem_block_output;
251		ei_status.get_8390_hdr = &hpp_mem_get_8390_hdr;
252		dev->mem_start = mem_start;
253		ei_status.mem = ioremap(mem_start,
254					(HP_STOP_PG - HP_START_PG)*256);
255		if (!ei_status.mem) {
256			retval = -ENOMEM;
257			goto out;
258		}
259		ei_status.rmem_start = dev->mem_start + TX_PAGES/2*256;
260		dev->mem_end = ei_status.rmem_end
261			= dev->mem_start + (HP_STOP_PG - HP_START_PG)*256;
262	}
263
264	outw(Perf_Page, ioaddr + HP_PAGING);
265	NS8390_init(dev, 0);
266	/* Leave the 8390 and HP chip reset. */
267	outw(inw(ioaddr + HPP_OPTION) & ~EnableIRQ, ioaddr + HPP_OPTION);
268
269	retval = register_netdev(dev);
270	if (retval)
271		goto out1;
272	return 0;
273out1:
274	iounmap(ei_status.mem);
275out:
276	release_region(ioaddr, HP_IO_EXTENT);
277	return retval;
278}
279
280static int
281hpp_open(struct net_device *dev)
282{
283	int ioaddr = dev->base_addr - NIC_OFFSET;
284	int option_reg;
285	int retval;
286
287	if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) {
288	    return retval;
289	}
290
291	/* Reset the 8390 and HP chip. */
292	option_reg = inw(ioaddr + HPP_OPTION);
293	outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
294	udelay(5);
295	/* Unreset the board and enable interrupts. */
296	outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
297
298	/* Set the wrap registers for programmed-I/O operation.   */
299	outw(HW_Page, ioaddr + HP_PAGING);
300	outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
301
302	/* Select the operational page. */
303	outw(Perf_Page, ioaddr + HP_PAGING);
304
305	ei_open(dev);
306	return 0;
307}
308
309static int
310hpp_close(struct net_device *dev)
311{
312	int ioaddr = dev->base_addr - NIC_OFFSET;
313	int option_reg = inw(ioaddr + HPP_OPTION);
314
315	free_irq(dev->irq, dev);
316	ei_close(dev);
317	outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
318		 ioaddr + HPP_OPTION);
319
320	return 0;
321}
322
323static void
324hpp_reset_8390(struct net_device *dev)
325{
326	int ioaddr = dev->base_addr - NIC_OFFSET;
327	int option_reg = inw(ioaddr + HPP_OPTION);
328
329	if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
330
331	outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
332	/* Pause a few cycles for the hardware reset to take place. */
333	udelay(5);
334	ei_status.txing = 0;
335	outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
336
337	udelay(5);
338
339
340	if ((inb_p(ioaddr+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
341		printk("%s: hp_reset_8390() did not complete.\n", dev->name);
342
343	if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
344	return;
345}
346
347/* The programmed-I/O version of reading the 4 byte 8390 specific header.
348   Note that transfer with the EtherTwist+ must be on word boundaries. */
349
350static void
351hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
352{
353	int ioaddr = dev->base_addr - NIC_OFFSET;
354
355	outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
356	insw(ioaddr + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
357}
358
359/* Block input and output, similar to the Crynwr packet driver. */
360
361static void
362hpp_io_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
363{
364	int ioaddr = dev->base_addr - NIC_OFFSET;
365	char *buf = skb->data;
366
367	outw(ring_offset, ioaddr + HPP_IN_ADDR);
368	insw(ioaddr + HP_DATAPORT, buf, count>>1);
369	if (count & 0x01)
370        buf[count-1] = inw(ioaddr + HP_DATAPORT);
371}
372
373/* The corresponding shared memory versions of the above 2 functions. */
374
375static void
376hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
377{
378	int ioaddr = dev->base_addr - NIC_OFFSET;
379	int option_reg = inw(ioaddr + HPP_OPTION);
380
381	outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
382	outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
383	memcpy_fromio(hdr, ei_status.mem, sizeof(struct e8390_pkt_hdr));
384	outw(option_reg, ioaddr + HPP_OPTION);
385	hdr->count = (le16_to_cpu(hdr->count) + 3) & ~3;	/* Round up allocation. */
386}
387
388static void
389hpp_mem_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
390{
391	int ioaddr = dev->base_addr - NIC_OFFSET;
392	int option_reg = inw(ioaddr + HPP_OPTION);
393
394	outw(ring_offset, ioaddr + HPP_IN_ADDR);
395
396	outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
397
398	/* Caution: this relies on get_8390_hdr() rounding up count!
399	   Also note that we *can't* use eth_io_copy_and_sum() because
400	   it will not always copy "count" bytes (e.g. padded IP).  */
401
402	memcpy_fromio(skb->data, ei_status.mem, count);
403	outw(option_reg, ioaddr + HPP_OPTION);
404}
405
406/* A special note: we *must* always transfer >=16 bit words.
407   It's always safe to round up, so we do. */
408static void
409hpp_io_block_output(struct net_device *dev, int count,
410					const unsigned char *buf, int start_page)
411{
412	int ioaddr = dev->base_addr - NIC_OFFSET;
413	outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
414	outsl(ioaddr + HP_DATAPORT, buf, (count+3)>>2);
415	return;
416}
417
418static void
419hpp_mem_block_output(struct net_device *dev, int count,
420				const unsigned char *buf, int start_page)
421{
422	int ioaddr = dev->base_addr - NIC_OFFSET;
423	int option_reg = inw(ioaddr + HPP_OPTION);
424
425	outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
426	outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
427	memcpy_toio(ei_status.mem, buf, (count + 3) & ~3);
428	outw(option_reg, ioaddr + HPP_OPTION);
429
430	return;
431}
432
433
434#ifdef MODULE
435#define MAX_HPP_CARDS	4	/* Max number of HPP cards per module */
436static struct net_device *dev_hpp[MAX_HPP_CARDS];
437static int io[MAX_HPP_CARDS];
438static int irq[MAX_HPP_CARDS];
439
440module_param_array(io, int, NULL, 0);
441module_param_array(irq, int, NULL, 0);
442MODULE_PARM_DESC(io, "I/O port address(es)");
443MODULE_PARM_DESC(irq, "IRQ number(s); ignored if properly detected");
444MODULE_DESCRIPTION("HP PC-LAN+ ISA ethernet driver");
445MODULE_LICENSE("GPL");
446
447/* This is set up so that only a single autoprobe takes place per call.
448ISA device autoprobes on a running machine are not recommended. */
449int __init
450init_module(void)
451{
452	struct net_device *dev;
453	int this_dev, found = 0;
454
455	for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
456		if (io[this_dev] == 0)  {
457			if (this_dev != 0) break; /* only autoprobe 1st one */
458			printk(KERN_NOTICE "hp-plus.c: Presently autoprobing (not recommended) for a single card.\n");
459		}
460		dev = alloc_ei_netdev();
461		if (!dev)
462			break;
463		dev->irq = irq[this_dev];
464		dev->base_addr = io[this_dev];
465		if (do_hpp_probe(dev) == 0) {
466			dev_hpp[found++] = dev;
467			continue;
468		}
469		free_netdev(dev);
470		printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]);
471		break;
472	}
473	if (found)
474		return 0;
475	return -ENXIO;
476}
477
478static void cleanup_card(struct net_device *dev)
479{
480	/* NB: hpp_close() handles free_irq */
481	iounmap(ei_status.mem);
482	release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
483}
484
485void __exit
486cleanup_module(void)
487{
488	int this_dev;
489
490	for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
491		struct net_device *dev = dev_hpp[this_dev];
492		if (dev) {
493			unregister_netdev(dev);
494			cleanup_card(dev);
495			free_netdev(dev);
496		}
497	}
498}
499#endif /* MODULE */
500