File: /usr/src/linux/drivers/net/smc-mca.c

1     /* smc-mca.c: A SMC Ultra ethernet driver for linux. */
2     /*
3         Most of this driver, except for ultramca_probe is nearly
4         verbatim from smc-ultra.c by Donald Becker. The rest is
5         written and copyright 1996 by David Weis, weisd3458@uni.edu
6     
7         This is a driver for the SMC Ultra and SMC EtherEZ ethercards.
8     
9         This driver uses the cards in the 8390-compatible, shared memory mode.
10         Most of the run-time complexity is handled by the generic code in
11         8390.c.
12     
13         This driver enables the shared memory only when doing the actual data
14         transfers to avoid a bug in early version of the card that corrupted
15         data transferred by a AHA1542.
16     
17         This driver does not support the programmed-I/O data transfer mode of
18         the EtherEZ.  That support (if available) is smc-ez.c.  Nor does it
19         use the non-8390-compatible "Altego" mode. (No support currently planned.)
20     
21         Changelog:
22     
23         Paul Gortmaker	 : multiple card support for module users.
24         David Weis		 : Micro Channel-ized it.
25         Tom Sightler	 : Added support for IBM PS/2 Ethernet Adapter/A
26         Christopher Turcksin : Changed MCA-probe so that multiple adapters are
27     			   found correctly (Jul 16, 1997)
28         Chris Beauregard	 : Tried to merge the two changes above (Dec 15, 1997)
29         Tom Sightler	 : Fixed minor detection bug caused by above merge
30         Tom Sightler	 : Added support for three more Western Digital
31     			   MCA-adapters
32         Tom Sightler	 : Added support for 2.2.x mca_find_unused_adapter
33         Hartmut Schmidt	 : - Modified parameter detection to handle each
34     			     card differently depending on a switch-list
35     			   - 'card_ver' removed from the adapter list
36     			   - Some minor bug fixes
37     */
38     
39     
40     #include <linux/module.h>
41     
42     #include <linux/kernel.h>
43     #include <linux/sched.h>
44     #include <linux/errno.h>
45     #include <linux/string.h>
46     #include <linux/init.h>
47     #include <asm/io.h>
48     #include <asm/system.h>
49     
50     #include <linux/netdevice.h>
51     #include <linux/etherdevice.h>
52     #include "8390.h"
53     #include "smc-mca.h"
54     #include <linux/mca.h>
55     
56     int ultramca_probe(struct net_device *dev);
57     
58     static int ultramca_open(struct net_device *dev);
59     static void ultramca_reset_8390(struct net_device *dev);
60     static void ultramca_get_8390_hdr(struct net_device *dev,
61                                       struct e8390_pkt_hdr *hdr,
62                                       int ring_page);
63     static void ultramca_block_input(struct net_device *dev, int count,
64                                      struct sk_buff *skb,
65                                      int ring_offset);
66     static void ultramca_block_output(struct net_device *dev, int count,
67                                       const unsigned char *buf,
68                                       const int start_page);
69     static int ultramca_close_card(struct net_device *dev);
70     
71     #define START_PG        0x00    /* First page of TX buffer */
72     
73     #define ULTRA_CMDREG 0      /* Offset to ASIC command register. */
74     #define ULTRA_RESET  0x80   /* Board reset, in ULTRA_CMDREG. */
75     #define ULTRA_MEMENB 0x40   /* Enable the shared memory. */
76     #define ULTRA_NIC_OFFSET 16 /* NIC register offset from the base_addr. */
77     #define ULTRA_IO_EXTENT 32
78     #define EN0_ERWCNT      0x08  /* Early receive warning count. */
79     
80     #define _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A            0
81     #define _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A            1
82     #define _6fc0_WD_Ethercard_PLUS_A_WD8003E_A_OR_WD8003ET_A              2
83     #define _6fc1_WD_Starcard_PLUS_A_WD8003ST_A                            3
84     #define _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A                        4
85     #define _efd4_IBM_PS2_Adapter_A_for_Ethernet_UTP_AUI_WD8013WP_A        5
86     #define _efd5_IBM_PS2_Adapter_A_for_Ethernet_BNC_AUI_WD8013WP_A        6
87     #define _efe5_IBM_PS2_Adapter_A_for_Ethernet                           7
88     
89     struct smc_mca_adapters_t {
90     	unsigned int id;
91     	char *name;
92     };
93     
94     static struct smc_mca_adapters_t smc_mca_adapters[] __initdata = {
95         { 0x61c8, "SMC Ethercard PLUS Elite/A BNC/AUI (WD8013EP/A)" },
96         { 0x61c9, "SMC Ethercard PLUS Elite/A UTP/AUI (WD8013WP/A)" },
97         { 0x6fc0, "WD Ethercard PLUS/A (WD8003E/A or WD8003ET/A)" },
98         { 0x6fc1, "WD Starcard PLUS/A (WD8003ST/A)" },
99         { 0x6fc2, "WD Ethercard PLUS 10T/A (WD8003W/A)" },
100         { 0xefd4, "IBM PS/2 Adapter/A for Ethernet UTP/AUI (WD8013WP/A)" },
101         { 0xefd5, "IBM PS/2 Adapter/A for Ethernet BNC/AUI (WD8013EP/A)" },
102         { 0xefe5, "IBM PS/2 Adapter/A for Ethernet" },
103         { 0x0000, NULL }
104     };
105     
106     int __init ultramca_probe(struct net_device *dev)
107     {
108     	unsigned short ioaddr;
109     	unsigned char reg4, num_pages;
110     	char slot = -1;
111     	unsigned char pos2 = 0xff, pos3 = 0xff, pos4 = 0xff, pos5 = 0xff;
112     	int i, j;
113     	int adapter_found = 0;
114     	int adapter = 0;
115     	int tbase = 0;
116     	int tirq = 0;
117     	int base_addr = dev->base_addr;
118     	int irq = dev->irq;
119     
120     	if (!MCA_bus) {
121     		return -ENODEV;
122     	}
123     
124     	SET_MODULE_OWNER(dev);
125     
126     	if (base_addr || irq) {
127     		printk(KERN_INFO "Probing for SMC MCA adapter");
128     		if (base_addr) {
129     			printk(KERN_INFO " at I/O address 0x%04x%c",
130     			       base_addr, irq ? ' ' : '\n');
131     		}
132     		if (irq) {
133     			printk(KERN_INFO "using irq %d\n", irq);
134     		}
135     	}
136     
137             /* proper multicard detection by ZP Gu (zpg@castle.net) */
138     
139     	for (j = 0; (smc_mca_adapters[j].name != NULL) && !adapter_found; j++) {
140     		slot = mca_find_unused_adapter(smc_mca_adapters[j].id, 0);
141     
142     		while((slot != MCA_NOTFOUND) && !adapter_found) {
143     			tirq = 0;
144     			tbase = 0;
145     
146                             /* If we're trying to match a specificied irq or
147     			 * io address, we'll reject the adapter
148     			 * found unless it's the one we're looking for
149     			 */
150     
151     			pos2 = mca_read_stored_pos(slot, 2); /* io_addr */
152     			pos3 = mca_read_stored_pos(slot, 3); /* shared mem */
153     			pos4 = mca_read_stored_pos(slot, 4); /* ROM bios addr
154     							      * range */
155     			pos5 = mca_read_stored_pos(slot, 5); /* irq, media
156     							      * and RIPL */
157     
158     			/* Test the following conditions:
159     			 * - If an irq parameter is supplied, compare it
160     			 *   with the irq of the adapter we found
161     			 * - If a base_addr paramater is given, compare it
162     			 *   with the base_addr of the adapter we found
163     			 * - Check that the irq and the base_addr of the
164     			 *   adapter we found is not already in use by
165     			 *   this driver
166     			 */
167     
168     			switch (j) { /* j = card-idx (card array above) [hs] */
169     				case _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A:
170     		                case _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A:
171     				case _efd4_IBM_PS2_Adapter_A_for_Ethernet_UTP_AUI_WD8013WP_A:
172     				case _efd5_IBM_PS2_Adapter_A_for_Ethernet_BNC_AUI_WD8013WP_A:
173     				{
174     					tbase = addr_table[(pos2 & 0xf0) >> 4].base_addr;
175     					tirq  = irq_table[(pos5 & 0xc) >> 2].new_irq;
176     					break;
177     				}
178     				case _6fc0_WD_Ethercard_PLUS_A_WD8003E_A_OR_WD8003ET_A:
179     				case _6fc1_WD_Starcard_PLUS_A_WD8003ST_A:
180     				case _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A:
181     				case _efe5_IBM_PS2_Adapter_A_for_Ethernet:
182     				{
183     					tbase = ((pos2 & 0x0fe) * 0x10);
184     					tirq  = irq_table[(pos5 & 3)].old_irq;
185     					break;
186     				}
187     			}
188     
189     			if(!tirq || !tbase || (irq && irq != tirq) || (base_addr && tbase != base_addr)) {
190     				slot = mca_find_unused_adapter(smc_mca_adapters[j].id, slot + 1);
191     			} else {
192     				adapter_found = 1;
193     				adapter = j;
194     			}
195     		}
196     	}
197     
198     	if(!adapter_found) {
199     		return ((base_addr || irq) ? -ENXIO : -ENODEV);
200     	}
201     
202             /* Adapter found. */
203     
204     	printk(KERN_INFO "%s: %s found in slot %d\n",
205     	       dev->name, smc_mca_adapters[adapter].name, slot + 1);
206     
207     	mca_set_adapter_name(slot, smc_mca_adapters[adapter].name);
208     	mca_mark_as_used(slot);
209     
210     
211     	dev->base_addr = ioaddr = tbase;
212     	dev->irq       = tirq;
213     	dev->mem_start = 0;
214     	num_pages      = 40;
215     
216     	switch (adapter) {	/* card-# in const array above [hs] */
217     		case _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A:
218     		case _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A:
219     		{
220     			for (i = 0; i < 16; i++) { /* taking 16 counts
221     						    * up to 15 [hs] */
222     				if (mem_table[i].mem_index == (pos3 & ~MEM_MASK)) {
223     					dev->mem_start = mem_table[i].mem_start;
224     					num_pages = mem_table[i].num_pages;
225     				}
226     			}
227     			break;
228     		}
229     		case _6fc0_WD_Ethercard_PLUS_A_WD8003E_A_OR_WD8003ET_A:
230     		case _6fc1_WD_Starcard_PLUS_A_WD8003ST_A:
231     		case _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A:
232     		case _efe5_IBM_PS2_Adapter_A_for_Ethernet:
233     		{
234     			dev->mem_start = ((pos3 & 0xfc) * 0x1000);
235     			num_pages = 0x40;
236     			break;
237     		}
238     		case _efd4_IBM_PS2_Adapter_A_for_Ethernet_UTP_AUI_WD8013WP_A:
239     		case _efd5_IBM_PS2_Adapter_A_for_Ethernet_BNC_AUI_WD8013WP_A:
240     		{
241     			/* courtesy of gamera@quartz.ocn.ne.jp, pos3 indicates
242     			 * the index of the 0x2000 step.
243     			 * beware different number of pages [hs]
244     			 */
245     			dev->mem_start = 0xc0000 + (0x2000 * (pos3 & 0xf));
246     			num_pages = 0x20 + (2 * (pos3 & 0x10));
247     			break;
248     		}
249     	}
250     
251     	if (dev->mem_start == 0) /* sanity check, shouldn't happen */
252     		return -ENODEV;
253     
254     	if (!request_region(ioaddr, ULTRA_IO_EXTENT, dev->name))
255     		return -EBUSY;
256     
257     	reg4 = inb(ioaddr + 4) & 0x7f;
258     	outb(reg4, ioaddr + 4);
259     
260     	printk(KERN_INFO "%s: Parameters: %#3x,", dev->name, ioaddr);
261     
262     	for (i = 0; i < 6; i++)
263     		printk(KERN_INFO " %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
264     
265     	/* Switch from the station address to the alternate register set
266     	 * and read the useful registers there.
267     	 */
268     
269     	outb(0x80 | reg4, ioaddr + 4);
270     
271     	/* Enable FINE16 mode to avoid BIOS ROM width mismatches @ reboot.
272     	 */
273     
274     	outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c);
275     
276     	/* Switch back to the station address register set so that
277     	 * the MS-DOS driver can find the card after a warm boot.
278     	 */
279     
280     	outb(reg4, ioaddr + 4);
281     
282     	/* Allocate dev->priv and fill in 8390 specific dev fields.
283     	 */
284     
285     	if (ethdev_init(dev)) {
286     		printk (KERN_INFO ", no memory for dev->priv.\n");
287     		release_region(ioaddr, ULTRA_IO_EXTENT);
288     		return -ENOMEM;
289     	}
290     
291     	/* The 8390 isn't at the base address, so fake the offset
292     	 */
293     
294     	dev->base_addr = ioaddr + ULTRA_NIC_OFFSET;
295     
296     	ei_status.name = "SMC Ultra MCA";
297     	ei_status.word16 = 1;
298     	ei_status.tx_start_page = START_PG;
299     	ei_status.rx_start_page = START_PG + TX_PAGES;
300     	ei_status.stop_page = num_pages;
301     
302     	dev->rmem_start = dev->mem_start + TX_PAGES * 256;
303     	dev->mem_end = dev->rmem_end =
304     	dev->mem_start + (ei_status.stop_page - START_PG) * 256;
305     
306     	printk(KERN_INFO ", IRQ %d memory %#lx-%#lx.\n",
307     	dev->irq, dev->mem_start, dev->mem_end - 1);
308     
309     	ei_status.reset_8390 = &ultramca_reset_8390;
310     	ei_status.block_input = &ultramca_block_input;
311     	ei_status.block_output = &ultramca_block_output;
312     	ei_status.get_8390_hdr = &ultramca_get_8390_hdr;
313     
314     	ei_status.priv = slot;
315     
316     	dev->open = &ultramca_open;
317     	dev->stop = &ultramca_close_card;
318     	NS8390_init(dev, 0);
319     
320     	return 0;
321     }
322     
323     static int ultramca_open(struct net_device *dev)
324     {
325     	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
326     	int retval;
327     
328     	if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev)))
329     		return retval;
330     
331     	outb(ULTRA_MEMENB, ioaddr); /* Enable memory */
332     	outb(0x80, ioaddr + 5);     /* ??? */
333     	outb(0x01, ioaddr + 6);     /* Enable interrupts and memory. */
334     	outb(0x04, ioaddr + 5);     /* ??? */
335     
336     	/* Set the early receive warning level in window 0 high enough not
337     	 * to receive ERW interrupts.
338     	 */
339     
340     	/* outb_p(E8390_NODMA + E8390_PAGE0, dev->base_addr);
341     	 * outb(0xff, dev->base_addr + EN0_ERWCNT);
342     	 */
343     
344     	ei_open(dev);
345     	return 0;
346     }
347     
348     static void ultramca_reset_8390(struct net_device *dev)
349     {
350     	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
351     
352     	outb(ULTRA_RESET, ioaddr);
353     	if (ei_debug > 1)
354     		printk("resetting Ultra, t=%ld...", jiffies);
355     	ei_status.txing = 0;
356     
357     	outb(0x80, ioaddr + 5);     /* ??? */
358     	outb(0x01, ioaddr + 6);     /* Enable interrupts and memory. */
359     
360     	if (ei_debug > 1)
361     		printk("reset done\n");
362     	return;
363     }
364     
365     /* Grab the 8390 specific header. Similar to the block_input routine, but
366      * we don't need to be concerned with ring wrap as the header will be at
367      * the start of a page, so we optimize accordingly.
368      */
369     
370     static void ultramca_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
371     {
372     	unsigned long hdr_start = dev->mem_start + ((ring_page - START_PG) << 8);
373     
374     #ifdef notdef
375     	/* Officially this is what we are doing, but the readl() is faster */
376     	isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
377     #else
378     	((unsigned int*)hdr)[0] = isa_readl(hdr_start);
379     #endif
380     }
381     
382     /* Block input and output are easy on shared memory ethercards, the only
383      * complication is when the ring buffer wraps.
384      */
385     
386     static void ultramca_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
387     {
388     	unsigned long xfer_start = dev->mem_start + ring_offset - (START_PG << 8);
389     
390     	if (xfer_start + count > dev->rmem_end) {
391     		/* We must wrap the input move. */
392     		int semi_count = dev->rmem_end - xfer_start;
393     		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
394     		count -= semi_count;
395     		isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
396     	} else {
397     		/* Packet is in one chunk -- we can copy + cksum. */
398     		isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
399     	}
400     
401     }
402     
403     static void ultramca_block_output(struct net_device *dev, int count, const unsigned char *buf,
404                     int start_page)
405     {
406     	unsigned long shmem = dev->mem_start + ((start_page - START_PG) << 8);
407     
408     	isa_memcpy_toio(shmem, buf, count);
409     }
410     
411     static int ultramca_close_card(struct net_device *dev)
412     {
413     	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
414     
415     	netif_stop_queue(dev);
416     	
417     	if (ei_debug > 1)
418     		printk("%s: Shutting down ethercard.\n", dev->name);
419     
420     	outb(0x00, ioaddr + 6);     /* Disable interrupts. */
421     	free_irq(dev->irq, dev);
422     
423     	NS8390_init(dev, 0);
424     	/* We should someday disable shared memory and change to 8-bit mode
425              * "just in case"...
426     	 */
427     
428     	return 0;
429     }
430     
431     
432     #ifdef MODULE
433     #undef MODULE        /* don't want to bother now! */
434     
435     #define MAX_ULTRAMCA_CARDS 4	/* Max number of Ultra cards per module */
436     
437     static struct net_device dev_ultra[MAX_ULTRAMCA_CARDS];
438     static int io[MAX_ULTRAMCA_CARDS];
439     static int irq[MAX_ULTRAMCA_CARDS];
440     
441     MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
442     MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
443     MODULE_PARM_DESC(io, "SMC Ultra/EtherEZ MCA I/O base address(es)");
444     MODULE_PARM_DESC(irq, "SMC Ultra/EtherEZ MCA IRQ number(s)");
445     
446     int init_module(void)
447     {
448     	int this_dev, found = 0;
449     
450     	for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++) {
451     		struct net_device *dev = &dev_ultra[this_dev];
452     		dev->irq = irq[this_dev];
453     		dev->base_addr = io[this_dev];
454     		dev->init = ultramca_probe;
455     
456     		if (register_netdev(dev) != 0) {
457     			if (found != 0) {	/* Got at least one. */
458     				return 0;
459     			}
460     			printk(KERN_NOTICE "smc-mca.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]);
461     			return -ENXIO;
462     		}
463     		found++;
464     	}
465     	return 0;
466     }
467     
468     void cleanup_module(void)
469     {
470     	int this_dev;
471     
472     	for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++) {
473     		struct net_device *dev = &dev_ultra[this_dev];
474     		if (dev->priv != NULL) {
475     			void *priv = dev->priv;
476     			/* NB: ultra_close_card() does free_irq */
477     			int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET;
478     			mca_mark_as_unused(ei_status.priv);
479     			release_region(ioaddr, ULTRA_IO_EXTENT);
480     			unregister_netdev(dev);
481     			kfree(priv);
482     		}
483     	}
484     }
485     #endif /* MODULE */
486     
487     /*
488      * Local variables:
489      *  compile-command: "gcc -D__KERNEL__ -Wall -O6 -I/usr/src/linux/net/inet -c smc-mca.c"
490      *  version-control: t
491      *  kept-new-versions: 5
492      *  c-indent-level: 8
493      *  tab-width: 8
494      * End:
495      */
496