1 /* smc-mca.c: A SMC Ultra ethernet driver for linux. */
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
7 This is a driver for the SMC Ultra and SMC EtherEZ ethercards.
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
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.
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.)
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
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
40 #include <linux/module.h>
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>
48 #include <asm/system.h>
50 #include <linux/netdevice.h>
51 #include <linux/etherdevice.h>
54 #include <linux/mca.h>
56 int ultramca_probe(struct net_device
*dev
);
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
,
63 static void ultramca_block_input(struct net_device
*dev
, int count
,
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
);
71 #define START_PG 0x00 /* First page of TX buffer */
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. */
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
89 struct smc_mca_adapters_t
{
94 const struct smc_mca_adapters_t smc_mca_adapters
[] = {
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" },
106 int __init
ultramca_probe(struct net_device
*dev
)
108 unsigned short ioaddr
;
109 unsigned char reg4
, num_pages
;
111 unsigned char pos2
= 0xff, pos3
= 0xff, pos4
= 0xff, pos5
= 0xff;
113 int adapter_found
= 0;
117 int base_addr
= dev
? dev
->base_addr
: 0;
118 int irq
= dev
? dev
->irq
: 0;
124 if (base_addr
|| irq
) {
125 printk(KERN_INFO
"Probing for SMC MCA adapter");
127 printk(KERN_INFO
" at I/O address 0x%04x%c",
128 base_addr
, irq
? ' ' : '\n');
131 printk(KERN_INFO
"using irq %d\n", irq
);
135 /* proper multicard detection by ZP Gu (zpg@castle.net) */
137 for (j
= 0; (smc_mca_adapters
[j
].name
!= NULL
) && !adapter_found
; j
++) {
138 slot
= mca_find_unused_adapter(smc_mca_adapters
[j
].id
, 0);
140 while((slot
!= MCA_NOTFOUND
) && !adapter_found
) {
144 /* If we're trying to match a specificied irq or
145 * io address, we'll reject the adapter
146 * found unless it's the one we're looking for
149 pos2
= mca_read_stored_pos(slot
, 2); /* io_addr */
150 pos3
= mca_read_stored_pos(slot
, 3); /* shared mem */
151 pos4
= mca_read_stored_pos(slot
, 4); /* ROM bios addr
153 pos5
= mca_read_stored_pos(slot
, 5); /* irq, media
156 /* Test the following conditions:
157 * - If an irq parameter is supplied, compare it
158 * with the irq of the adapter we found
159 * - If a base_addr paramater is given, compare it
160 * with the base_addr of the adapter we found
161 * - Check that the irq and the base_addr of the
162 * adapter we found is not already in use by
166 switch (j
) { /* j = card-idx (card array above) [hs] */
167 case _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A
:
168 case _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A
:
169 case _efd4_IBM_PS2_Adapter_A_for_Ethernet_UTP_AUI_WD8013WP_A
:
170 case _efd5_IBM_PS2_Adapter_A_for_Ethernet_BNC_AUI_WD8013WP_A
:
172 tbase
= addr_table
[(pos2
& 0xf0) >> 4].base_addr
;
173 tirq
= irq_table
[(pos5
& 0xc) >> 2].new_irq
;
176 case _6fc0_WD_Ethercard_PLUS_A_WD8003E_A_OR_WD8003ET_A
:
177 case _6fc1_WD_Starcard_PLUS_A_WD8003ST_A
:
178 case _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A
:
179 case _efe5_IBM_PS2_Adapter_A_for_Ethernet
:
181 tbase
= ((pos2
& 0x0fe) * 0x10);
182 tirq
= irq_table
[(pos5
& 3)].old_irq
;
187 if(!tirq
|| !tbase
|| (irq
&& irq
!= tirq
) || (base_addr
&& tbase
!= base_addr
)) {
188 slot
= mca_find_unused_adapter(smc_mca_adapters
[j
].id
, slot
+ 1);
197 return ((base_addr
|| irq
) ? ENXIO
: ENODEV
);
202 printk(KERN_INFO
"%s: %s found in slot %d\n",
203 dev
->name
, smc_mca_adapters
[adapter
].name
, slot
+ 1);
205 mca_set_adapter_name(slot
, smc_mca_adapters
[adapter
].name
);
206 mca_mark_as_used(slot
);
209 dev
->base_addr
= ioaddr
= tbase
;
214 switch (j
) { /* 'j' = card-# in const array above [hs] */
215 case _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A
:
216 case _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A
:
218 for (i
= 0; i
< 16; i
++) { /* taking 16 counts
220 if (mem_table
[i
].mem_index
== (pos3
& ~MEM_MASK
)) {
221 dev
->mem_start
= mem_table
[i
].mem_start
;
222 num_pages
= mem_table
[i
].num_pages
;
227 case _6fc0_WD_Ethercard_PLUS_A_WD8003E_A_OR_WD8003ET_A
:
228 case _6fc1_WD_Starcard_PLUS_A_WD8003ST_A
:
229 case _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A
:
230 case _efe5_IBM_PS2_Adapter_A_for_Ethernet
:
232 dev
->mem_start
= ((pos3
& 0xfc) * 0x1000);
236 case _efd4_IBM_PS2_Adapter_A_for_Ethernet_UTP_AUI_WD8013WP_A
:
237 case _efd5_IBM_PS2_Adapter_A_for_Ethernet_BNC_AUI_WD8013WP_A
:
239 /* courtesy of gamera@quartz.ocn.ne.jp, pos3 indicates
240 * the index of the 0x2000 step.
241 * beware different number of pages [hs]
243 dev
->mem_start
= 0xc0000 + (0x2000 * (pos3
& 0xf));
244 num_pages
= 0x20 + (2 * (pos3
& 0x10));
249 if (dev
->mem_start
== 0) /* sanity check, shouldn't happen */
252 reg4
= inb(ioaddr
+ 4) & 0x7f;
253 outb(reg4
, ioaddr
+ 4);
255 if (load_8390_module("wd.c"))
258 printk(KERN_INFO
"%s: Parameters: %#3x,", dev
->name
, ioaddr
);
260 for (i
= 0; i
< 6; i
++)
261 printk(KERN_INFO
" %2.2X", dev
->dev_addr
[i
] = inb(ioaddr
+ 8 + i
));
263 /* Switch from the station address to the alternate register set
264 * and read the useful registers there.
267 outb(0x80 | reg4
, ioaddr
+ 4);
269 /* Enable FINE16 mode to avoid BIOS ROM width mismatches @ reboot.
272 outb(0x80 | inb(ioaddr
+ 0x0c), ioaddr
+ 0x0c);
274 /* Switch back to the station address register set so that
275 * the MS-DOS driver can find the card after a warm boot.
278 outb(reg4
, ioaddr
+ 4);
280 /* Allocate dev->priv and fill in 8390 specific dev fields.
283 if (ethdev_init(dev
)) {
284 printk (KERN_INFO
", no memory for dev->priv.\n");
288 /* OK, we are certain this is going to work. Setup the device.
291 request_region(ioaddr
, ULTRA_IO_EXTENT
, "smc-mca");
293 /* The 8390 isn't at the base address, so fake the offset
296 dev
->base_addr
= ioaddr
+ ULTRA_NIC_OFFSET
;
298 ei_status
.name
= "SMC Ultra MCA";
299 ei_status
.word16
= 1;
300 ei_status
.tx_start_page
= START_PG
;
301 ei_status
.rx_start_page
= START_PG
+ TX_PAGES
;
302 ei_status
.stop_page
= num_pages
;
304 dev
->rmem_start
= dev
->mem_start
+ TX_PAGES
* 256;
305 dev
->mem_end
= dev
->rmem_end
=
306 dev
->mem_start
+ (ei_status
.stop_page
- START_PG
) * 256;
308 printk(KERN_INFO
", IRQ %d memory %#lx-%#lx.\n",
309 dev
->irq
, dev
->mem_start
, dev
->mem_end
- 1);
311 ei_status
.reset_8390
= &ultramca_reset_8390
;
312 ei_status
.block_input
= &ultramca_block_input
;
313 ei_status
.block_output
= &ultramca_block_output
;
314 ei_status
.get_8390_hdr
= &ultramca_get_8390_hdr
;
316 ei_status
.priv
= slot
;
318 dev
->open
= &ultramca_open
;
319 dev
->stop
= &ultramca_close_card
;
325 static int ultramca_open(struct net_device
*dev
)
327 int ioaddr
= dev
->base_addr
- ULTRA_NIC_OFFSET
; /* ASIC addr */
329 if (request_irq(dev
->irq
, ei_interrupt
, 0, ei_status
.name
, dev
))
332 outb(ULTRA_MEMENB
, ioaddr
); /* Enable memory */
333 outb(0x80, ioaddr
+ 5); /* ??? */
334 outb(0x01, ioaddr
+ 6); /* Enable interrupts and memory. */
335 outb(0x04, ioaddr
+ 5); /* ??? */
337 /* Set the early receive warning level in window 0 high enough not
338 * to receive ERW interrupts.
341 /* outb_p(E8390_NODMA + E8390_PAGE0, dev->base_addr);
342 * outb(0xff, dev->base_addr + EN0_ERWCNT);
350 static void ultramca_reset_8390(struct net_device
*dev
)
352 int ioaddr
= dev
->base_addr
- ULTRA_NIC_OFFSET
; /* ASIC addr */
354 outb(ULTRA_RESET
, ioaddr
);
356 printk("resetting Ultra, t=%ld...", jiffies
);
359 outb(0x80, ioaddr
+ 5); /* ??? */
360 outb(0x01, ioaddr
+ 6); /* Enable interrupts and memory. */
363 printk("reset done\n");
367 /* Grab the 8390 specific header. Similar to the block_input routine, but
368 * we don't need to be concerned with ring wrap as the header will be at
369 * the start of a page, so we optimize accordingly.
372 static void ultramca_get_8390_hdr(struct net_device
*dev
, struct e8390_pkt_hdr
*hdr
, int ring_page
)
374 unsigned long hdr_start
= dev
->mem_start
+ ((ring_page
- START_PG
) << 8);
377 /* Officially this is what we are doing, but the readl() is faster */
378 memcpy_fromio(hdr
, hdr_start
, sizeof(struct e8390_pkt_hdr
));
380 ((unsigned int*)hdr
)[0] = readl(hdr_start
);
384 /* Block input and output are easy on shared memory ethercards, the only
385 * complication is when the ring buffer wraps.
388 static void ultramca_block_input(struct net_device
*dev
, int count
, struct sk_buff
*skb
, int ring_offset
)
390 unsigned long xfer_start
= dev
->mem_start
+ ring_offset
- (START_PG
<< 8);
392 if (xfer_start
+ count
> dev
->rmem_end
) {
393 /* We must wrap the input move. */
394 int semi_count
= dev
->rmem_end
- xfer_start
;
395 memcpy_fromio(skb
->data
, xfer_start
, semi_count
);
397 memcpy_fromio(skb
->data
+ semi_count
, dev
->rmem_start
, count
);
399 /* Packet is in one chunk -- we can copy + cksum. */
400 eth_io_copy_and_sum(skb
, xfer_start
, count
, 0);
405 static void ultramca_block_output(struct net_device
*dev
, int count
, const unsigned char *buf
,
408 unsigned long shmem
= dev
->mem_start
+ ((start_page
- START_PG
) << 8);
410 memcpy_toio(shmem
, buf
, count
);
413 static int ultramca_close_card(struct net_device
*dev
)
415 int ioaddr
= dev
->base_addr
- ULTRA_NIC_OFFSET
; /* ASIC addr */
421 printk("%s: Shutting down ethercard.\n", dev
->name
);
423 outb(0x00, ioaddr
+ 6); /* Disable interrupts. */
424 free_irq(dev
->irq
, dev
);
427 /* We should someday disable shared memory and change to 8-bit mode
438 #undef MODULE /* don't want to bother now! */
440 #define MAX_ULTRAMCA_CARDS 4 /* Max number of Ultra cards per module */
441 #define NAMELEN 8 /* # of chars for storing dev->name */
443 static char namelist
[NAMELEN
* MAX_ULTRAMCA_CARDS
] = { 0, };
445 static struct net_device dev_ultra
[MAX_ULTRAMCA_CARDS
] =
448 NULL
, /* assign a chunk of namelist[] below */
455 static int io
[MAX_ULTRAMCA_CARDS
] = { 0, };
456 static int irq
[MAX_ULTRAMCA_CARDS
] = { 0, };
458 MODULE_PARM(io
, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS
) "i");
459 MODULE_PARM(irq
, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS
) "i");
461 int init_module(void)
463 int this_dev
, found
= 0;
465 for (this_dev
= 0; this_dev
< MAX_ULTRAMCA_CARDS
; this_dev
++) {
466 struct net_device
*dev
= &dev_ultra
[this_dev
];
467 dev
->name
= namelist
+ (NAMELEN
* this_dev
);
468 dev
->irq
= irq
[this_dev
];
469 dev
->base_addr
= io
[this_dev
];
470 dev
->init
= ultramca_probe
;
472 if (register_netdev(dev
) != 0) {
473 if (found
!= 0) { /* Got at least one. */
477 printk(KERN_NOTICE
"smc-mca.c: No SMC Ultra card found (i/o = 0x%x).\n", io
[this_dev
]);
486 void cleanup_module(void)
490 for (this_dev
= 0; this_dev
< MAX_ULTRAMCA_CARDS
; this_dev
++) {
491 struct net_device
*dev
= &dev_ultra
[this_dev
];
492 if (dev
->priv
!= NULL
) {
493 void *priv
= dev
->priv
;
494 /* NB: ultra_close_card() does free_irq */
495 int ioaddr
= dev
->base_addr
- ULTRA_NIC_OFFSET
;
496 mca_mark_as_unused(ei_status
.priv
);
497 release_region(ioaddr
, ULTRA_IO_EXTENT
);
498 unregister_netdev(dev
);
502 unlock_8390_module();
508 * compile-command: "gcc -D__KERNEL__ -Wall -O6 -I/usr/src/linux/net/inet -c smc-mca.c"
510 * kept-new-versions: 5