1 /* mac_ns8390.c: A Macintosh 8390 based ethernet driver for linux. */
5 Written 1993-94 by Donald Becker.
7 Copyright 1993 United States Government as represented by the
8 Director, National Security Agency.
10 This software may be used and distributed according to the terms
11 of the GNU Public License, incorporated herein by reference.
15 The block output routines may be wrong for non Dayna
21 static const char *version
=
22 "mac_ns8390.c:v0.01 7/5/97 Alan Cox (Alan.Cox@linux.org)\n";
24 #include <linux/module.h>
26 #include <linux/kernel.h>
27 #include <linux/sched.h>
28 #include <linux/errno.h>
29 #include <linux/string.h>
30 #include <linux/nubus.h>
32 #include <asm/system.h>
33 #include <asm/hwtest.h>
34 #include <linux/delay.h>
36 #include <linux/netdevice.h>
37 #include <linux/etherdevice.h>
40 int ns8390_probe1(struct device
*dev
, int word16
, char *name
, int id
, int prom
);
42 static int ns8390_open(struct device
*dev
);
43 static void ns8390_no_reset(struct device
*dev
);
44 static int ns8390_close_card(struct device
*dev
);
46 static void interlan_reset(struct device
*dev
);
48 static void dayna_get_8390_hdr(struct device
*dev
, struct e8390_pkt_hdr
*hdr
,
50 static void dayna_block_input(struct device
*dev
, int count
,
51 struct sk_buff
*skb
, int ring_offset
);
52 static void dayna_block_output(struct device
*dev
, int count
,
53 const unsigned char *buf
, const int start_page
);
55 static void sane_get_8390_hdr(struct device
*dev
, struct e8390_pkt_hdr
*hdr
,
57 static void sane_block_input(struct device
*dev
, int count
,
58 struct sk_buff
*skb
, int ring_offset
);
59 static void sane_block_output(struct device
*dev
, int count
,
60 const unsigned char *buf
, const int start_page
);
62 static void slow_sane_get_8390_hdr(struct device
*dev
, struct e8390_pkt_hdr
*hdr
,
64 static void slow_sane_block_input(struct device
*dev
, int count
,
65 struct sk_buff
*skb
, int ring_offset
);
66 static void slow_sane_block_output(struct device
*dev
, int count
,
67 const unsigned char *buf
, const int start_page
);
70 #define WD_START_PG 0x00 /* First page of TX buffer */
71 #define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */
72 #define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */
75 #define DAYNA_MAC_BASE 0xf0007
76 #define DAYNA_8390_BASE 0x80000 /* 3 */
77 #define DAYNA_8390_MEM 0x00000
78 #define DAYNA_MEMSIZE 0x04000 /* First word of each long ! */
80 #define APPLE_8390_BASE 0xE0000
81 #define APPLE_8390_MEM 0xD0000
82 #define APPLE_MEMSIZE 8192 /* FIXME: need to dynamically check */
84 #define KINETICS_8390_BASE 0x80003
85 #define KINETICS_8390_MEM 0x00000
86 #define KINETICS_MEMSIZE 8192 /* FIXME: need to dynamically check */
88 static int test_8390(volatile char *ptr
, int scale
)
93 if(hwreg_present(&ptr
[0x00])==0)
95 if(hwreg_present(&ptr
[0x0D<<scale
])==0)
97 if(hwreg_present(&ptr
[0x0D<<scale
])==0)
99 ptr
[0x00]=E8390_NODMA
+E8390_PAGE1
+E8390_STOP
;
100 regd
=ptr
[0x0D<<scale
];
101 ptr
[0x0D<<scale
]=0xFF;
102 ptr
[0x00]=E8390_NODMA
+E8390_PAGE0
;
104 if(ptr
[0x0D<<scale
]!=0)
106 ptr
[0x0D<<scale
]=regd
;
109 /* printk("NS8390 found at %p scaled %d\n", ptr,scale);*/
113 * Identify the species of NS8390 card/driver we need
116 #define NS8390_DAYNA 1
117 #define NS8390_INTERLAN 2
118 #define NS8390_KINETICS 3
119 #define NS8390_APPLE 4
120 #define NS8390_FARALLON 5
121 #define NS8390_ASANTE 6
123 int ns8390_ident(struct nubus_type
*nb
)
125 /* It appears anything with a software type of 0 is an apple
126 compatible - even if the hardware matches others */
128 if(nb
->DrSW
==0x0001 || nb
->DrSW
==0x0109 || nb
->DrSW
==0x0000 || nb
->DrSW
==0x0100)
131 /* Dayna ex Kinetics board */
137 return NS8390_ASANTE
;
139 return NS8390_INTERLAN
;
141 return NS8390_KINETICS
;
143 return NS8390_FARALLON
;
148 * Memory probe for 8390 cards
151 int apple_8390_mem_probe(volatile unsigned short *p
)
156 * 1. Check each block size of memory doesn't fault
157 * 2. Write a value to it
158 * 3. Check all previous blocks are unaffected
163 volatile unsigned short *m
=p
+4096*i
;
164 /* Unwriteable - we have a fully decoded card and the
167 if(hwreg_present(m
)==0)
174 /* Partial decode and wrap ? */
175 if(p
[4096*j
]!=(0xA5A0|j
))
177 /* This is the first misdecode, so it had
178 one less page than we tried */
183 /* Ok it still decodes.. move on 8K */
186 * We don't look past 16K. That should cover most cards
187 * and above 16K there isnt really any gain.
193 * Probe for 8390 cards.
194 * The ns8390_probe1() routine initializes the card and fills the
195 * station address field. On entry base_addr is set, irq is set
196 * (These come from the nubus probe code). dev->mem_start points
197 * at the memory ring, dev->mem_end gives the end of it.
200 int ns8390_probe(struct nubus_device_specifier
*d
, int slot
, struct nubus_type
*match
)
203 volatile unsigned short *i
;
204 volatile unsigned char *p
;
208 if(match
->category
!=NUBUS_CAT_NETWORK
|| match
->type
!=1)
210 /* Ok so it is an ethernet network device */
211 if((id
=ns8390_ident(match
))==-1)
213 printk("Ethernet but type unknown %d\n",match
->DrHW
);
216 dev
= init_etherdev(0, 0);
221 * Dayna specific init
225 dev
->base_addr
=(int)(nubus_slot_addr(slot
)+DAYNA_8390_BASE
);
226 dev
->mem_start
=(int)(nubus_slot_addr(slot
)+DAYNA_8390_MEM
);
227 dev
->mem_end
=dev
->mem_start
+DAYNA_MEMSIZE
; /* 8K it seems */
229 printk("daynaport: testing board: ");
233 i
=(void *)dev
->mem_start
;
234 memset((void *)i
,0xAA, DAYNA_MEMSIZE
);
235 while(i
<(volatile unsigned short *)dev
->mem_end
)
242 i
+=2; /* Skip a word */
245 printk("controller - ");
247 p
=(void *)dev
->base_addr
;
252 if(test_8390(p
,0)==0)
254 if(test_8390(p
,1)==0)
256 if(test_8390(p
,2)==0)
258 if(test_8390(p
,3)==0)
267 if(ns8390_probe1(dev
, 0, "dayna", id
, -1)==0)
270 /* Apple, Farallon, Asante */
271 if(id
==NS8390_APPLE
|| id
==NS8390_FARALLON
|| id
==NS8390_ASANTE
)
275 dev
->base_addr
=(int)(nubus_slot_addr(slot
)+APPLE_8390_BASE
);
276 dev
->mem_start
=(int)(nubus_slot_addr(slot
)+APPLE_8390_MEM
);
278 memsize
= apple_8390_mem_probe((void *)dev
->mem_start
);
280 dev
->mem_end
=dev
->mem_start
+memsize
;
282 printk("apple/clone: testing board: ");
284 printk("%dK memory - ", memsize
>>10);
286 i
=(void *)dev
->mem_start
;
287 memset((void *)i
,0xAA, memsize
);
288 while(i
<(volatile unsigned short *)dev
->mem_end
)
295 i
+=2; /* Skip a word */
299 if(id
==NS8390_FARALLON
)
301 if(ns8390_probe1(dev
, 1, "farallon", id
, -1)==0)
306 if(ns8390_probe1(dev
, 1, "apple/clone", id
, -1)==0)
311 if(id
==NS8390_INTERLAN
)
313 /* As apple and asante */
314 dev
->base_addr
=(int)(nubus_slot_addr(slot
)+APPLE_8390_BASE
);
315 dev
->mem_start
=(int)(nubus_slot_addr(slot
)+APPLE_8390_MEM
);
316 dev
->mem_end
=dev
->mem_start
+APPLE_MEMSIZE
; /* 8K it seems */
318 if(ns8390_probe1(dev
, 1, "interlan", id
, -1)==0)
322 if(id
==NS8390_KINETICS
)
324 dev
->base_addr
=(int)(nubus_slot_addr(slot
)+KINETICS_8390_BASE
);
325 dev
->mem_start
=(int)(nubus_slot_addr(slot
)+KINETICS_8390_MEM
);
326 dev
->mem_end
=dev
->mem_start
+KINETICS_MEMSIZE
; /* 8K it seems */
328 if(ns8390_probe1(dev
, 0, "kinetics", id
, -1)==0)
339 int ns8390_probe1(struct device
*dev
, int word16
, char *model_name
, int type
, int promoff
)
341 static unsigned version_printed
= 0;
343 static u32 fwrd4_offsets
[16]={
349 static u32 back4_offsets
[16]={
356 unsigned char *prom
=((unsigned char *)nubus_slot_addr(dev
->irq
))+promoff
;
358 if (ei_debug
&& version_printed
++ == 0)
361 /* Snarf the interrupt now. There's no point in waiting since we cannot
362 share a slot! and the board will usually be enabled. */
363 if (nubus_request_irq(dev
->irq
, dev
, ei_interrupt
))
365 printk (" unable to get nubus IRQ %d.\n", dev
->irq
);
369 /* Allocate dev->priv and fill in 8390 specific dev fields. */
370 if (ethdev_init(dev
))
372 printk (" unable to get memory for dev->priv.\n");
373 nubus_free_irq(dev
->irq
);
377 /* OK, we are certain this is going to work. Setup the device. */
379 ei_status
.name
= model_name
;
380 ei_status
.word16
= word16
;
381 ei_status
.tx_start_page
= WD_START_PG
;
382 ei_status
.rx_start_page
= WD_START_PG
+ TX_PAGES
;
384 dev
->rmem_start
= dev
->mem_start
+ TX_PAGES
*256;
385 ei_status
.stop_page
= (dev
->mem_end
- dev
->mem_start
)/256;
386 dev
->rmem_end
= dev
->mem_end
;
388 if(promoff
==-1) /* Use nubus resources ? */
390 if(nubus_ethernet_addr(dev
->irq
/* slot */, dev
->dev_addr
))
392 printk("mac_ns8390: MAC address not in resources!\n");
396 else /* Pull it off the card */
400 /* These should go in the end I hope */
401 if(type
==NS8390_DAYNA
)
403 if(type
==NS8390_INTERLAN
)
407 dev
->dev_addr
[i
]=*prom
;
411 printk("%02X",dev
->dev_addr
[i
++]);
415 printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
416 model_name
, dev
->irq
, dev
->mem_start
, dev
->mem_end
-1);
420 case NS8390_DAYNA
: /* Dayna card */
421 /* 16 bit, 4 word offsets */
422 ei_status
.reset_8390
= &ns8390_no_reset
;
423 ei_status
.block_input
= &dayna_block_input
;
424 ei_status
.block_output
= &dayna_block_output
;
425 ei_status
.get_8390_hdr
= &dayna_get_8390_hdr
;
426 ei_status
.reg_offset
= fwrd4_offsets
;
428 case NS8390_FARALLON
:
429 case NS8390_APPLE
: /* Apple/Asante/Farallon */
430 /* 16 bit card, register map is reversed */
431 ei_status
.reset_8390
= &ns8390_no_reset
;
432 ei_status
.block_input
= &slow_sane_block_input
;
433 ei_status
.block_output
= &slow_sane_block_output
;
434 ei_status
.get_8390_hdr
= &slow_sane_get_8390_hdr
;
435 ei_status
.reg_offset
= back4_offsets
;
438 /* 16 bit card, register map is reversed */
439 ei_status
.reset_8390
= &ns8390_no_reset
;
440 ei_status
.block_input
= &sane_block_input
;
441 ei_status
.block_output
= &sane_block_output
;
442 ei_status
.get_8390_hdr
= &sane_get_8390_hdr
;
443 ei_status
.reg_offset
= back4_offsets
;
445 case NS8390_INTERLAN
: /* Interlan */
446 /* 16 bit card, map is forward */
447 ei_status
.reset_8390
= &interlan_reset
;
448 ei_status
.block_input
= &sane_block_input
;
449 ei_status
.block_output
= &sane_block_output
;
450 ei_status
.get_8390_hdr
= &sane_get_8390_hdr
;
451 ei_status
.reg_offset
= back4_offsets
;
453 case NS8390_KINETICS
: /* Kinetics */
454 /* 8bit card, map is forward */
455 ei_status
.reset_8390
= &ns8390_no_reset
;
456 ei_status
.block_input
= &sane_block_input
;
457 ei_status
.block_output
= &sane_block_output
;
458 ei_status
.get_8390_hdr
= &sane_get_8390_hdr
;
459 ei_status
.reg_offset
= back4_offsets
;
462 panic("Detected a card I can't drive - whoops\n");
464 dev
->open
= &ns8390_open
;
465 dev
->stop
= &ns8390_close_card
;
472 static int ns8390_open(struct device
*dev
)
479 static void ns8390_no_reset(struct device
*dev
)
482 printk("Need to reset the NS8390 t=%lu...", jiffies
);
484 if (ei_debug
> 1) printk("reset not supported\n");
488 static int ns8390_close_card(struct device
*dev
)
491 printk("%s: Shutting down ethercard.\n", dev
->name
);
497 struct nubus_device_specifier nubus_8390
={
504 * Interlan Specific Code Starts Here
507 static void interlan_reset(struct device
*dev
)
509 unsigned char *target
=nubus_slot_addr(dev
->irq
);
511 printk("Need to reset the NS8390 t=%lu...", jiffies
);
513 /* This write resets the card */
515 if (ei_debug
> 1) printk("reset complete\n");
520 * Daynaport code (some is used by other drivers)
524 /* Grab the 8390 specific header. Similar to the block_input routine, but
525 we don't need to be concerned with ring wrap as the header will be at
526 the start of a page, so we optimize accordingly. */
529 /* Block input and output are easy on shared memory ethercards, and trivial
530 on the Daynaport card where there is no choice of how to do it.
531 The only complications are that the ring buffer wraps.
534 static void dayna_cpu_memcpy(struct device
*dev
, void *to
, int from
, int count
)
536 volatile unsigned short *ptr
;
537 unsigned short *target
=to
;
538 from
<<=1; /* word, skip overhead */
539 ptr
=(unsigned short *)(dev
->mem_start
+from
);
542 *target
++=*ptr
++; /* Copy and */
543 ptr
++; /* Cruft and */
552 unsigned short v
=*ptr
;
553 *((char *)target
)=v
>>8;
557 static void cpu_dayna_memcpy(struct device
*dev
, int to
, const void *from
, int count
)
559 volatile unsigned short *ptr
;
560 const unsigned short *src
=from
;
561 to
<<=1; /* word, skip overhead */
562 ptr
=(unsigned short *)(dev
->mem_start
+to
);
565 *ptr
++=*src
++; /* Copy and */
566 ptr
++; /* Cruft and */
575 unsigned short v
=*src
;
580 static void dayna_get_8390_hdr(struct device
*dev
, struct e8390_pkt_hdr
*hdr
, int ring_page
)
582 unsigned long hdr_start
= (ring_page
- WD_START_PG
)<<8;
583 dayna_cpu_memcpy(dev
, (void *)hdr
, hdr_start
, 4);
584 /* Register endianism - fix here rather than 8390.c */
585 hdr
->count
=(hdr
->count
&0xFF)<<8|(hdr
->count
>>8);
588 static void dayna_block_input(struct device
*dev
, int count
, struct sk_buff
*skb
, int ring_offset
)
590 unsigned long xfer_base
= ring_offset
- (WD_START_PG
<<8);
591 unsigned long xfer_start
= xfer_base
+dev
->mem_start
;
594 * Note the offset maths is done in card memory space which
595 * is word per long onto our space.
598 if (xfer_start
+ count
> dev
->rmem_end
)
600 /* We must wrap the input move. */
601 int semi_count
= dev
->rmem_end
- xfer_start
;
602 dayna_cpu_memcpy(dev
, skb
->data
, xfer_base
, semi_count
);
604 dayna_cpu_memcpy(dev
, skb
->data
+ semi_count
,
605 dev
->rmem_start
- dev
->mem_start
, count
);
609 dayna_cpu_memcpy(dev
, skb
->data
, xfer_base
, count
);
613 static void dayna_block_output(struct device
*dev
, int count
, const unsigned char *buf
,
616 long shmem
= (start_page
- WD_START_PG
)<<8;
618 cpu_dayna_memcpy(dev
, shmem
, buf
, count
);
622 * Cards with full width memory
626 static void sane_get_8390_hdr(struct device
*dev
, struct e8390_pkt_hdr
*hdr
, int ring_page
)
628 unsigned long hdr_start
= (ring_page
- WD_START_PG
)<<8;
629 memcpy((void *)hdr
, (char *)dev
->mem_start
+hdr_start
, 4);
630 /* Register endianism - fix here rather than 8390.c */
631 hdr
->count
=(hdr
->count
&0xFF)<<8|(hdr
->count
>>8);
634 static void sane_block_input(struct device
*dev
, int count
, struct sk_buff
*skb
, int ring_offset
)
636 unsigned long xfer_base
= ring_offset
- (WD_START_PG
<<8);
637 unsigned long xfer_start
= xfer_base
+dev
->mem_start
;
639 if (xfer_start
+ count
> dev
->rmem_end
)
641 /* We must wrap the input move. */
642 int semi_count
= dev
->rmem_end
- xfer_start
;
643 memcpy(skb
->data
, (char *)dev
->mem_start
+xfer_base
, semi_count
);
645 memcpy(skb
->data
+ semi_count
,
646 (char *)dev
->rmem_start
, count
);
650 memcpy(skb
->data
, (char *)dev
->mem_start
+xfer_base
, count
);
655 static void sane_block_output(struct device
*dev
, int count
, const unsigned char *buf
,
658 long shmem
= (start_page
- WD_START_PG
)<<8;
660 memcpy((char *)dev
->mem_start
+shmem
, buf
, count
);
663 static void word_memcpy_tocard(void *tp
, const void *fp
, int count
)
665 volatile unsigned short *to
= tp
;
666 const unsigned short *from
= fp
;
675 static void word_memcpy_fromcard(void *tp
, const void *fp
, int count
)
677 unsigned short *to
= tp
;
678 const volatile unsigned short *from
= fp
;
687 static void slow_sane_get_8390_hdr(struct device
*dev
, struct e8390_pkt_hdr
*hdr
, int ring_page
)
689 unsigned long hdr_start
= (ring_page
- WD_START_PG
)<<8;
690 word_memcpy_fromcard((void *)hdr
, (char *)dev
->mem_start
+hdr_start
, 4);
691 /* Register endianism - fix here rather than 8390.c */
692 hdr
->count
=(hdr
->count
&0xFF)<<8|(hdr
->count
>>8);
695 static void slow_sane_block_input(struct device
*dev
, int count
, struct sk_buff
*skb
, int ring_offset
)
697 unsigned long xfer_base
= ring_offset
- (WD_START_PG
<<8);
698 unsigned long xfer_start
= xfer_base
+dev
->mem_start
;
700 if (xfer_start
+ count
> dev
->rmem_end
)
702 /* We must wrap the input move. */
703 int semi_count
= dev
->rmem_end
- xfer_start
;
704 word_memcpy_fromcard(skb
->data
, (char *)dev
->mem_start
+xfer_base
, semi_count
);
706 word_memcpy_fromcard(skb
->data
+ semi_count
,
707 (char *)dev
->rmem_start
, count
);
711 word_memcpy_fromcard(skb
->data
, (char *)dev
->mem_start
+xfer_base
, count
);
715 static void slow_sane_block_output(struct device
*dev
, int count
, const unsigned char *buf
,
718 long shmem
= (start_page
- WD_START_PG
)<<8;
720 word_memcpy_tocard((char *)dev
->mem_start
+shmem
, buf
, count
);
722 long shmem
= (start_page
- WD_START_PG
)<<8;
723 volatile unsigned short *to
=(unsigned short *)(dev
->mem_start
+shmem
);
725 unsigned short *bp
=(unsigned short *)buf
;
740 * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c"
743 * kept-new-versions: 5