1 /* $NetBSD: if_ie.c,v 1.26 2009/05/12 06:54:10 cegger Exp $ */
4 * Copyright (c) 1995 Melvin Tang-Richardson.
7 * This driver is a major hash up of src/sys/dev/isa/if_ie.c and
8 * src/sys/arch/acorn32/podulebus/kgdb_ie.c Please refer to copyright
9 * notices from them too.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by RiscBSD.
22 * 4. The name of the company nor the name of the author may be used to
23 * endorse or promote products derived from this software without specific
24 * prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY RISCBSD ``AS IS'' AND ANY EXPRESS OR IMPLIED
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL RISCBSD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * RiscBSD kernel project
42 * Ether 1 podule driver
48 * This driver is at it's last beta release. It should not cause
49 * any problems (Touch wood)
51 * If it passes field tests again. This will constitute the realse
55 #include <sys/cdefs.h>
56 __KERNEL_RCSID(0, "$NetBSD: if_ie.c,v 1.26 2009/05/12 06:54:10 cegger Exp $");
58 #define IGNORE_ETHER1_IDROM_CHECKSUM
60 /* Standard podule includes */
65 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/kernel.h>
70 #include <sys/malloc.h>
71 #include <sys/device.h>
72 #include <machine/io.h>
73 #include <machine/intr.h>
74 #include <arm/arm32/katelib.h>
75 #include <acorn32/podulebus/podulebus.h>
76 #include <dev/podulebus/podules.h>
78 /* Include for interface to the net and ethernet subsystems */
80 #include <sys/socket.h>
81 #include <sys/syslog.h>
82 #include <sys/ioctl.h>
86 #include <net/if_types.h>
87 #include <net/if_dl.h>
88 #include <net/if_ether.h>
91 #include <netinet/in.h>
92 #include <netinet/in_systm.h>
93 #include <netinet/in_var.h>
94 #include <netinet/ip.h>
95 #include <netinet/if_inarp.h>
100 #include <netns/ns_if.h>
103 /* Import our data structres */
105 #include "if_iereg.h"
109 #include "bpfilter.h"
112 #include <net/bpfdesc.h>
115 /* Some useful defines and macros */
117 #define PODULE_IRQ_PENDING (1)
118 #define NFRAMES (16) /* number of frame to allow for receive */
119 #define NRXBUF (48) /* number of receive buffers to allocate */
120 #define IE_RXBUF_SIZE (256) /* receive buf size */
121 #define NTXBUF (2) /* number of transmit buffers to allocate */
122 #define IE_TXBUF_SIZE (1522) /* size of tx buffer */
124 #define PWriteShort(a,b) WriteWord(a,(b)<<16|(b))
126 #define xoffsetof(type, member) (offsetof(type, member) << 1)
128 /* Some data structres local to this file */
131 struct device sc_dev
;
132 int sc_podule_number
;
142 struct ethercom sc_ethercom
;
146 u_long rframes
[NFRAMES
];
147 u_long rbuffs
[NRXBUF
];
148 u_long cbuffs
[NRXBUF
];
149 int rfhead
, rftail
, rbhead
, rbtail
;
151 u_long xmit_cmds
[NTXBUF
];
152 u_long xmit_buffs
[NTXBUF
];
153 u_long xmit_cbuffs
[NTXBUF
];
160 /* Function and data prototypes */
162 static void host2ie( struct ie_softc
*sc
, void *src
, u_long dest
, int size
);
163 static void ie2host( struct ie_softc
*sc
, u_long src
, void *dest
, int size
);
164 static void iezero( struct ie_softc
*sc
, u_long p
, int size
);
165 void iereset( struct ie_softc
*sc
);
166 void iewatchdog( struct ifnet
*ifp
);
167 int ieioctl( struct ifnet
*ifp
, u_long cmd
, void *data
);
168 void iestart( struct ifnet
*ifp
);
169 int iestop( struct ie_softc
*sc
);
170 int ieinit( struct ie_softc
*sc
);
171 int ieintr( void *arg
);
172 void ietint( struct ie_softc
*sc
);
174 /* A whopper of a function */
175 static int command_and_wait( struct ie_softc
*sc
, u_short cmd
,
176 struct ie_sys_ctl_block
*pscb
,
177 void *pcmd
, int ocmd
, int scmd
, int mask
);
179 int ieprobe(struct device
*, struct cfdata
*, void *);
180 void ieattach(struct device
*, struct device
*, void *);
182 static inline void ie_cli(struct ie_softc
*);
183 static inline void ieattn(struct ie_softc
*);
184 static inline void setpage(struct ie_softc
*, u_long
);
185 static void ie_ack(struct ie_softc
*, u_short
);
186 void PWriteShorts(char *, char *, int);
187 void ReadShorts(char *, char *, int);
188 static void run_tdr(struct ie_softc
*);
189 u_long
setup_rfa(struct ie_softc
*, u_long
);
190 static inline int ie_buflen(struct ie_softc
*, int);
191 static inline int ie_packet_len(struct ie_softc
*);
192 struct mbuf
*ieget(struct ie_softc
*, int *);
193 void ie_drop_packet_buffer(struct ie_softc
*);
194 void ie_read_frame(struct ie_softc
*, int num
);
195 void ierint(struct ie_softc
*);
196 void iexmit(struct ie_softc
*);
197 static void start_receiver(struct ie_softc
*);
201 * Our cfattach structure for the autoconfig system to chew on
204 CFATTACH_DECL(ie
, sizeof(struct ie_softc
),
205 ieprobe
, ieattach
, NULL
, NULL
);
210 * Clear all pending interrupts from the i82586 chip
214 ie_cli(struct ie_softc
*sc
)
216 WriteByte(sc
->sc_fastbase
+ (IE_CONTROL
<<2), IE_CONT_CLI
);
220 * Wake the i82586 chip up and get it to do something
224 ieattn(struct ie_softc
*sc
)
226 WriteByte ( sc
->sc_control
+ (IE_CONTROL
<<2), IE_CONT_ATTN
);
230 * Set the podule page register to bring a given address into view
234 setpage(struct ie_softc
*sc
, u_long off
)
236 WriteByte ( sc
->sc_control
+ (IE_PAGE
<<2), IE_COFF2PAGE(off
) );
244 ie_ack(struct ie_softc
*sc
, u_short mask
)
248 setpage(sc
, IE_IBASE
+ IE_SCB_OFF
);
250 stat
= ReadShort ( sc
->sc_ram
+ IE_COFF2POFF(IE_IBASE
+IE_SCB_OFF
) +
251 (xoffsetof(struct ie_sys_ctl_block
, ie_status
)) );
253 PWriteShort ( sc
->sc_ram
+ IE_COFF2POFF(IE_IBASE
+IE_SCB_OFF
) +
254 (xoffsetof(struct ie_sys_ctl_block
, ie_command
)),
259 for ( i
=4000; --i
>=0; ) {
260 if ( !ReadShort(sc
->sc_ram
+ IE_COFF2POFF(IE_IBASE
+IE_SCB_OFF
) +
261 (xoffsetof(struct ie_sys_ctl_block
, ie_command
))) )
267 printf ( "ie: command timed out\n" );
272 * This routine does the checksumming for the idrom
275 #ifndef IGNORE_ETHER1_IDROM_CHECKSUM
277 crc32(u_char
*p
, int l
)
283 for ( i
=8; --i
>= 0; b
>>=1 )
285 crc
=(crc
<<1)^0x4c11db7;
294 * Probe for the ether1 card. return 1 on success 0 on failure
298 ieprobe(struct device
*parent
, struct cfdata
*cf
, void *aux
)
300 struct podule_attach_args
*pa
= (void *)aux
;
302 /* Look for a network slot interface */
304 return (pa
->pa_product
== PODULE_ETHER1
);
308 * Attach our driver to the interfaces it uses
311 void ieattach ( struct device
*parent
, struct device
*self
, void *aux
)
313 struct ie_softc
*sc
= (void *)self
;
314 struct podule_attach_args
*pa
= (void *)aux
;
315 struct ifnet
*ifp
= &sc
->sc_ethercom
.ec_if
;
318 u_int8_t hwaddr
[ETHER_ADDR_LEN
];
320 /* Check a few things about the attach args */
322 if (pa
->pa_podule_number
== -1)
323 panic("Podule has disappeared !");
325 sc
->sc_podule_number
= pa
->pa_podule_number
;
326 sc
->sc_podule
= pa
->pa_podule
;
327 podules
[sc
->sc_podule_number
].attached
= 1;
332 * This needs a serious clean up. Alot of this code was in the probe function
333 * but required the softc structure. As a temporary measure until I rewrite it
334 * I have just bolted in the probe code here.
337 /* Index some podule areas */
338 sc
->sc_iobase
= sc
->sc_podule
->sync_base
; /* OBSOLETE */
339 sc
->sc_fastbase
= sc
->sc_podule
->fast_base
; /* OBSOLETE */
340 sc
->sc_rom
= sc
->sc_podule
->sync_base
;
341 sc
->sc_control
= sc
->sc_podule
->fast_base
;
342 sc
->sc_ram
= sc
->sc_podule
->fast_base
+ IE_MEMOFF
;
344 /* Set the page mask to something know and neutral */
345 setpage(sc
, IE_SCB_OFF
);
347 /* Fetch the first part of the idrom */
348 for ( i
=0; i
<16; i
++ )
349 idrom
[i
] = ReadByte ( sc
->sc_rom
+ (i
<<2) );
351 /* Verify the podulebus probe incase RiscOS lied */
352 if ( ReadByte ( sc
->sc_rom
+ (3<<2) ) != 0x03 ) {
353 printf(": Ether1 ROM probablly broken. ECID corrupt\n");
354 sc
->sc_flags
|= IE_BROKEN
;
358 /* Reset the 82586 */
359 WriteByte ( sc
->sc_fastbase
+ (IE_CONTROL
<<2), IE_CONT_RESET
);
361 WriteByte ( sc
->sc_fastbase
+ (IE_CONTROL
<<2), 0 );
364 /* Clear pending interrupts */
369 struct ie_sys_conf_ptr scp
;
370 bzero (&scp
, sizeof(scp
) );
371 scp
.ie_iscp_ptr
= (void *)IE_ISCP_ADDR
;
372 host2ie(sc
, &scp
, IE_SCP_ADDR
, sizeof (scp
) );
377 struct ie_int_sys_conf_ptr iscp
;
378 bzero ( &iscp
, sizeof(iscp
) );
380 iscp
.ie_base
= (void *)IE_IBASE
;
381 iscp
.ie_scb_offset
= IE_SCB_OFF
;
382 host2ie(sc
, &iscp
, IE_ISCP_ADDR
, sizeof(iscp
) );
385 /* Initialise the control block */
386 iezero ( sc
, IE_IBASE
+ IE_SCB_OFF
, sizeof(struct ie_sys_ctl_block
) );
389 /* Wait for not busy */
390 setpage ( sc
, IE_ISCP_ADDR
);
391 for ( i
=10000; --i
>=0; ) {
392 if ( !ReadShort( sc
->sc_ram
+ IE_COFF2POFF(IE_ISCP_ADDR
) +
393 ( xoffsetof(struct ie_int_sys_conf_ptr
, ie_busy
)) ) )
398 /* If the busy didn't go low, the i82586 is broken or too slow */
400 printf ( ": ether1 chipset didn't respond\n" );
401 sc
->sc_flags
|= IE_BROKEN
;
405 /* Ensure that the podule sends interrupts */
406 for ( i
=1000; --i
>=0 ; ) {
407 if ( ReadByte(sc
->sc_rom
+ 0) & PODULE_IRQ_PENDING
)
412 /* If we didn't see the interrupt then the IRQ line is broken */
414 printf ( ": interrupt from chipset didn't reach host\n" );
415 sc
->sc_flags
|= IE_BROKEN
;
419 /* Ack our little test operation */
420 ie_ack(sc
,IE_ST_WHENCE
);
423 /* Get second part of idrom */
424 for ( i
=16; i
<32; i
++ )
425 idrom
[i
] = ReadByte ( sc
->sc_rom
+ (i
<<2) );
427 /* This checksum always fails. For some reason the first 16 */
428 /* bytes are duplicated in the second 16 bytes, the checksum */
429 /* should be at location 28 it is clearly not */
431 /* It is possible that this ether1 card is buggered */
433 #ifndef IGNORE_ETHER1_IDROM_CHECKSUM
434 if ( crc32(idrom
,28) != *(u_long
*)(idrom
+28) )
436 printf ( "ie: ether1 idrom failed checksum %08x!=%08x\n",
437 crc32(idrom
,28), *(u_long
*)(idrom
+28));
438 for ( i
=0; i
<32; i
+=8 ) {
439 printf ( "IDROM: %02x %02x %02x %02x %02x %02x %02x %02x\n",
440 idrom
[0+i
], idrom
[1+i
], idrom
[2+i
], idrom
[3+i
],
441 idrom
[4+i
], idrom
[5+i
], idrom
[6+i
], idrom
[7+i
] );
443 printf ( "ie: I'll ignore this fact for now!\n" );
447 /* Get our ethernet address. Do explicit copy */
448 for ( i
=0; i
<ETHER_ADDR_LEN
; i
++ )
449 hwaddr
[i
] = idrom
[9+i
];
451 /* Fill in my application form to attach to the inet system */
453 memcpy(ifp
->if_xname
, device_xname(&sc
->sc_dev
), IFNAMSIZ
);
455 ifp
->if_start
= iestart
;
456 ifp
->if_ioctl
= ieioctl
;
457 ifp
->if_watchdog
= iewatchdog
;
458 ifp
->if_flags
= IFF_BROADCAST
| IFF_NOTRAILERS
;
460 /* Signed, dated then sent */
462 ether_ifattach(ifp
, hwaddr
);
464 /* "Hmm," said nuts, "what if the attach fails" */
466 /* Write some pretty things on the annoucement line */
467 printf ( ": %s using %dk card ram",
468 ether_sprintf(hwaddr
),
469 ((NRXBUF
*IE_RXBUF_SIZE
)+(NTXBUF
*IE_TXBUF_SIZE
))/1024 );
471 sc
->sc_ih
.ih_func
= ieintr
;
472 sc
->sc_ih
.ih_arg
= sc
;
473 sc
->sc_ih
.ih_level
= IPL_NET
;
474 sc
->sc_ih
.ih_name
= "net: ie";
475 sc
->sc_ih
.ih_maskaddr
= sc
->sc_podule
->irq_addr
;
476 sc
->sc_ih
.ih_maskbits
= sc
->sc_podule
->irq_mask
;
478 if (irq_claim(sc
->sc_podule
->interrupt
, &sc
->sc_ih
)) {
481 panic("%s: Cannot install IRQ handler", sc
->sc_dev
.dv_xname
);
492 * Oh no!! Where's my shorts!!! I'm sure I put them on this morning
496 PWriteShorts(char *src
, char *dest
, int cnt
)
498 for (cnt
/= 2; --cnt
>= 0; ) {
499 PWriteShort(dest
, *(u_short
*)src
);
506 ReadShorts(char *src
, char *dest
, int cnt
)
508 for (cnt
/= 2; --cnt
>= 0; ) {
509 *(u_short
*)dest
= ReadShort(src
);
516 * A bcopy or memcpy to adapter ram. It handles the page register for you
517 * so you dont have to worry about the ram windowing
521 host2ie(struct ie_softc
*sc
, void *src
, u_long dest
, int size
)
532 cnt
= IE_PAGESIZE
- dest
% IE_PAGESIZE
;
536 PWriteShorts(sptr
, (char *)sc
->sc_ram
+ IE_COFF2POFF(dest
), cnt
);
544 ie2host(struct ie_softc
*sc
, u_long src
, void *dest
, int size
)
555 cnt
= IE_PAGESIZE
- src
% IE_PAGESIZE
;
559 ReadShorts((char *)sc
->sc_ram
+ IE_COFF2POFF(src
), dptr
, cnt
);
567 * Like a bzero or memset 0 for adapter memory. It handles the page
568 * register so you dont have to worry about it
572 iezero(struct ie_softc
*sc
, u_long p
, int size
)
577 cnt
= IE_PAGESIZE
- p
% IE_PAGESIZE
;
581 memset((char *)sc
->sc_ram
+ IE_COFF2POFF(p
), 0, 2*cnt
);
588 * I/O Control interface to the kernel, entry point here
592 ieioctl(struct ifnet
*ifp
, unsigned long cmd
, void *data
)
594 struct ie_softc
*sc
= ifp
->if_softc
;
595 struct ifaddr
*ifa
= (struct ifaddr
*)data
;
604 ifp
->if_flags
|= IFF_UP
;
605 switch (ifa
->ifa_addr
->sa_family
) {
609 arp_ifinit(ifp
, ifa
);
618 #define IZSET(a,b) ((a->if_flags&b)!=0)
619 #define IZCLR(a,b) ((a->if_flags&b)==0)
620 #define DOSET(a,b) (a->if_flags|=b)
621 #define DOCLR(a,b) (a->if_flags&=~b)
624 if ((error
= ifioctl_common(ifp
, cmd
, data
)) != 0)
626 sc
->promisc
= ifp
->if_flags
& ( IFF_PROMISC
| IFF_ALLMULTI
);
628 if ( IZCLR(ifp
,IFF_UP
) && IZSET(ifp
,IFF_RUNNING
) )
630 /* Interface was marked down and its running so stop it */
632 DOCLR(ifp
,IFF_RUNNING
);
634 else if ( IZSET(ifp
,IFF_UP
) && IZCLR(ifp
,IFF_RUNNING
) )
636 /* Just marked up and we're not running so start it */
641 /* else reset to invoke changes in other registers */
647 error
= ether_ioctl(ifp
, cmd
, data
);
655 * Reset the card. Completely.
659 iereset(struct ie_softc
*sc
)
661 struct ie_sys_ctl_block scb
;
666 ie2host(sc
, IE_IBASE
+ IE_SCB_OFF
, &scb
, sizeof scb
);
668 if (command_and_wait(sc
, IE_RU_ABORT
|IE_CU_ABORT
, 0, 0, 0, 0, 0))
669 printf("ie0: abort commands timed out\n");
671 if (command_and_wait(sc
, IE_RU_DISABLE
|IE_CU_STOP
, 0, 0, 0, 0, 0))
672 printf("ie0: abort commands timed out\n");
680 * Watchdog entry point. This is the entry for the kernel to call us
684 iewatchdog(struct ifnet
*ifp
)
686 struct ie_softc
*sc
= ifp
->if_softc
;
688 log(LOG_ERR
, "%s: device timeout\n", device_xname(&sc
->sc_dev
));
694 * Start the time-domain-refloctometer running
698 run_tdr(struct ie_softc
*sc
)
700 struct ie_sys_ctl_block scb
;
701 u_long ptr
= IE_IBASE
+ IE_SCB_OFF
+ sizeof scb
;
702 struct ie_tdr_cmd cmd
;
705 bzero ( &scb
, sizeof(scb
) );
706 bzero ( &cmd
, sizeof(cmd
) );
708 cmd
.com
.ie_cmd_status
= 0;
709 cmd
.com
.ie_cmd_cmd
= IE_CMD_TDR
| IE_CMD_LAST
;
710 cmd
.com
.ie_cmd_link
= 0xffff;
713 scb
.ie_command_list
= (u_short
)ptr
;
716 if ( command_and_wait(sc
, IE_CU_START
, &scb
, &cmd
, ptr
, sizeof cmd
,
721 else if ( !(cmd
.com
.ie_cmd_status
& IE_STAT_OK
) )
727 result
= cmd
.ie_tdr_time
;
729 ie_ack ( sc
, IE_ST_WHENCE
);
731 if (result
& IE_TDR_SUCCESS
)
734 /* Very messy. I'll tidy it later */
736 if ( result
& 0x10000 )
738 printf ( "ie: TDR command failed\n" );
740 else if ( result
& IE_TDR_XCVR
)
742 printf ( "ie: tranceiver problem. Is it plugged in?\n" );
744 else if ( result
& IE_TDR_OPEN
)
746 if ((result
& IE_TDR_TIME
)>0)
747 printf ( "ie: TDR detected an open %d clocks away.\n",
748 result
& IE_TDR_TIME
);
750 else if ( result
& IE_TDR_SHORT
)
752 if ((result
& IE_TDR_TIME
)>0)
753 printf ( "ie: TDR detected a short %d clock away.\n",
754 result
& IE_TDR_TIME
);
758 printf ( "ie: TDR returned unknown status %x\n", result
);
763 setup_rfa(struct ie_softc
*sc
, u_long ptr
)
767 /* Receive frame descriptors */
768 struct ie_recv_frame_desc rfd
;
769 memset( &rfd
, 0, sizeof rfd
);
770 for ( i
=0; i
<NFRAMES
; i
++ )
772 sc
->rframes
[i
] = ptr
;
773 rfd
.ie_fd_next
= ptr
+ sizeof rfd
;
774 host2ie(sc
, (char *)&rfd
, ptr
, sizeof rfd
);
777 rfd
.ie_fd_next
= sc
->rframes
[0];
778 rfd
.ie_fd_last
|= IE_FD_LAST
;
779 host2ie(sc
, (char *)&rfd
, sc
->rframes
[NFRAMES
-1], sizeof rfd
);
781 ie2host(sc
, sc
->rframes
[0], (char *)&rfd
, sizeof rfd
);
782 rfd
.ie_fd_buf_desc
= (u_short
) ptr
;
783 host2ie(sc
, (char *)&rfd
, sc
->rframes
[0], sizeof rfd
);
787 /* Receive frame descriptors */
788 struct ie_recv_buf_desc rbd
;
789 memset(&rbd
, 0, sizeof rbd
);
790 for ( i
=0; i
<NRXBUF
; i
++ )
793 rbd
.ie_rbd_length
= IE_RXBUF_SIZE
;
794 rbd
.ie_rbd_buffer
= (void *)(ptr
+ sizeof rbd
);
795 rbd
.ie_rbd_next
= (u_short
)(ptr
+ sizeof rbd
+ IE_RXBUF_SIZE
);
796 host2ie(sc
, &rbd
, ptr
, sizeof rbd
);
802 rbd
.ie_rbd_next
= sc
->rbuffs
[0];
803 rbd
.ie_rbd_length
|= IE_RBD_LAST
;
804 host2ie(sc
, &rbd
, sc
->rbuffs
[NRXBUF
-1], sizeof rbd
);
808 sc
->rftail
= NFRAMES
-1;
810 sc
->rbtail
= NRXBUF
-1;
813 struct ie_sys_ctl_block scb
;
814 bzero ( &scb
, sizeof scb
);
815 scb
.ie_recv_list
= (u_short
)sc
->rframes
[0];
816 host2ie(sc
, (char *)&scb
, (IE_IBASE
+ IE_SCB_OFF
), sizeof scb
);
822 start_receiver(struct ie_softc
*sc
)
824 struct ie_sys_ctl_block scb
;
825 ie2host ( sc
, IE_IBASE
+ IE_SCB_OFF
, &scb
, sizeof scb
);
826 scb
.ie_recv_list
= (u_short
)sc
->rframes
[0];
827 command_and_wait(sc
, IE_RU_START
, &scb
, 0, 0, 0, 0);
828 ie_ack(sc
, IE_ST_WHENCE
);
832 * Take our configuration and update all the other data structures that
833 * require information from the driver.
835 * CALL AT SPLIMP OR HIGHER
839 ieinit(struct ie_softc
*sc
)
842 struct ie_sys_ctl_block scb
;
843 struct ie_config_cmd cmd
;
844 struct ie_iasetup_cmd iasetup_cmd
;
845 u_long ptr
= IE_IBASE
+ IE_SCB_OFF
+ sizeof scb
;
848 ifp
= &sc
->sc_ethercom
.ec_if
;
850 bzero ( &scb
, sizeof(scb
) );
852 /* Send the configure command */
854 cmd
.com
.ie_cmd_status
= 0;
855 cmd
.com
.ie_cmd_cmd
= IE_CMD_CONFIG
| IE_CMD_LAST
;
856 cmd
.com
.ie_cmd_link
= 0xffff;
858 cmd
.ie_config_count
= 0x0c;
860 cmd
.ie_save_bad
= 0x40;
861 cmd
.ie_addr_len
= 0x2e;
865 cmd
.ie_slot_high
= 0xf2;
866 cmd
.ie_promisc
= 0; /* Hey nuts, look at this! */
871 scb
.ie_command_list
= (u_short
)ptr
;
873 if ( command_and_wait(sc
, IE_CU_START
, &scb
, &cmd
, ptr
, sizeof cmd
,
876 printf ( "%s: command failed: timeout\n", device_xname(&sc
->sc_dev
));
880 if ( !(cmd
.com
.ie_cmd_status
& IE_STAT_OK
) )
882 printf ( "%s: command failed: !IE_STAT_OK\n", device_xname(&sc
->sc_dev
));
886 /* Individual address setup command */
888 iasetup_cmd
.com
.ie_cmd_status
= 0;
889 iasetup_cmd
.com
.ie_cmd_cmd
= IE_CMD_IASETUP
| IE_CMD_LAST
;
890 iasetup_cmd
.com
.ie_cmd_link
= 0xffff;
892 bcopy ( CLLADDR(ifp
->if_sadl
), (void *) &iasetup_cmd
.ie_address
,
893 sizeof (iasetup_cmd
.ie_address
) );
895 if ( command_and_wait(sc
, IE_CU_START
, &scb
, &iasetup_cmd
, ptr
, sizeof cmd
,
898 printf ( "%s: iasetup failed : timeout\n", device_xname(&sc
->sc_dev
));
902 if ( !(cmd
.com
.ie_cmd_status
& IE_STAT_OK
) )
904 printf ( "%s: iasetup failed : !IE_STAT_OK\n", device_xname(&sc
->sc_dev
));
908 ie_ack ( sc
, IE_ST_WHENCE
);
910 /* Run the time-domain refloctometer */
913 ie_ack ( sc
, IE_ST_WHENCE
);
916 ptr
= setup_rfa(sc
, ptr
);
918 ifp
->if_flags
|= IFF_RUNNING
;
919 ifp
->if_flags
&= ~IFF_OACTIVE
;
921 /* Setup transmit buffers */
923 for ( n
=0; n
<NTXBUF
; n
++ ) {
924 sc
->xmit_cmds
[n
] = ptr
;
925 iezero(sc
, ptr
, sizeof(struct ie_xmit_cmd
) );
926 ptr
+= sizeof(struct ie_xmit_cmd
);
928 sc
->xmit_buffs
[n
] = ptr
;
929 iezero(sc
, ptr
, sizeof(struct ie_xmit_buf
));
930 ptr
+= sizeof(struct ie_xmit_buf
);
933 for ( n
=0; n
<NTXBUF
; n
++ ) {
934 sc
->xmit_cbuffs
[n
] = ptr
;
935 ptr
+= IE_TXBUF_SIZE
;
938 sc
->xmit_free
= NTXBUF
;
939 sc
->xchead
= sc
->xctail
= 0;
942 struct ie_xmit_cmd xmcmd
;
943 bzero ( &xmcmd
, sizeof xmcmd
);
944 xmcmd
.ie_xmit_status
= IE_STAT_COMPL
;
945 host2ie(sc
, &xmcmd
, sc
->xmit_cmds
[0], sizeof xmcmd
);
954 iestop(struct ie_softc
*sc
)
956 struct ie_sys_ctl_block scb
;
959 ie2host ( sc
, IE_IBASE
+ IE_SCB_OFF
, &scb
, sizeof scb
);
961 if ( command_and_wait(sc
, IE_RU_DISABLE
, &scb
, 0, 0, 0, 0) )
962 printf ( "ie0: abort commands timed out\n" );
969 * Send a command to the card and awaits it's completion.
970 * Timeout if it's taking too long
976 command_and_wait(struct ie_softc
*sc
, u_short cmd
, struct ie_sys_ctl_block
*pscb
, void *pcmd
, int ocmd
, int scmd
, int mask
)
980 /* Copy the command to the card */
983 host2ie(sc
, pcmd
, ocmd
, scmd
); /* transfer the command to the card */
985 /* Copy the scb to the card */
988 pscb
->ie_command
= cmd
;
989 host2ie(sc
, pscb
, IE_IBASE
+ IE_SCB_OFF
, sizeof *pscb
);
993 setpage ( sc
, IE_IBASE
+ IE_SCB_OFF
);
994 PWriteShort ( sc
->sc_ram
+ IE_COFF2POFF(IE_IBASE
+IE_SCB_OFF
) +
995 (xoffsetof(struct ie_sys_ctl_block
, ie_command
)), cmd
);
998 /* Prod the card to act on the newly loaded command */
1001 /* Wait for the command to complete */
1002 if ( IE_ACTION_COMMAND(cmd
) && pcmd
)
1005 for ( i
=4000; --i
>=0; ) {
1006 if ( ReadShort(sc
->sc_ram
+ IE_COFF2POFF(ocmd
) +
1007 (xoffsetof(struct ie_config_cmd
, ie_config_status
))) & mask
)
1014 for ( i
=4000; --i
>=0; ) {
1015 if ( !ReadShort(sc
->sc_ram
+ IE_COFF2POFF(IE_IBASE
+IE_SCB_OFF
) +
1016 (xoffsetof(struct ie_sys_ctl_block
, ie_command
))) )
1022 /* Update the host structures to reflect the state on the card */
1024 ie2host(sc
, IE_IBASE
+ IE_SCB_OFF
, pscb
, sizeof *pscb
);
1026 ie2host(sc
, ocmd
, pcmd
, scmd
);
1031 #define READ_MEMBER(sc,type,member,ptr,dest) \
1033 dest = ReadShort(sc->sc_ram + IE_COFF2POFF(ptr) + \
1034 (xoffsetof(type, member)) );
1036 #define WRITE_MEMBER(sc,type,member,ptr,dest) \
1038 PWriteShort(sc->sc_ram + IE_COFF2POFF(ptr) + \
1039 (xoffsetof(type, member)), dest );
1042 ie_buflen(struct ie_softc
*sc
, int head
)
1046 READ_MEMBER(sc
,struct ie_recv_buf_desc
, ie_rbd_actual
,
1047 sc
->rbuffs
[head
], actual
);
1049 return(actual
& (IE_RXBUF_SIZE
| (IE_RXBUF_SIZE
-1))) ;
1053 ie_packet_len(struct ie_softc
*sc
)
1057 int head
= sc
->rbhead
;
1061 READ_MEMBER(sc
,struct ie_recv_buf_desc
, ie_rbd_actual
,
1062 sc
->rbuffs
[sc
->rbhead
], actual
);
1063 if (!(actual
&IE_RBD_USED
))
1068 READ_MEMBER(sc
,struct ie_recv_buf_desc
, ie_rbd_actual
,
1069 sc
->rbuffs
[head
], i
);
1070 i
= i
& IE_RBD_LAST
;
1072 acc
+= ie_buflen(sc
, head
);
1073 head
= (head
+1) % NRXBUF
;
1080 ieget(struct ie_softc
*sc
, int *to_bpf
)
1082 struct mbuf
*top
, **mp
, *m
;
1084 int resid
, totlen
, thisrboff
, thismboff
;
1086 struct ether_header eh
;
1088 totlen
= ie_packet_len(sc
);
1090 if ( totlen
> ETHER_MAX_LEN
)
1092 printf ( "ie: Gosh that packet was s-o-o-o big.\n" );
1101 /* Read the ethernet header */
1102 ie2host ( sc
, sc
->cbuffs
[head
], (void *)&eh
, sizeof eh
);
1104 /* Check if the packet is for us */
1108 MGETHDR ( m
, M_DONTWAIT
, MT_DATA
);
1112 m
->m_pkthdr
.rcvif
= &sc
->sc_ethercom
.ec_if
;
1113 m
->m_pkthdr
.len
= totlen
;
1119 * This loop goes through and allocates mbufs for all the data we will
1120 * be copying in. It does not actually do the copying yet.
1122 while (totlen
> 0) {
1124 MGET(m
, M_DONTWAIT
, MT_DATA
);
1131 if (totlen
>= MINCLSIZE
) {
1132 MCLGET(m
, M_DONTWAIT
);
1133 if (m
->m_flags
& M_EXT
)
1138 void *newdata
= (void *)
1139 ALIGN(m
->m_data
+ sizeof(struct ether_header
)) -
1140 sizeof(struct ether_header
);
1141 len
-= newdata
- m
->m_data
;
1142 m
->m_data
= newdata
;
1145 m
->m_len
= len
= min(totlen
, len
);
1156 * Copy the Ethernet header into the mbuf chain.
1158 memcpy(mtod(m
, void *), &eh
, sizeof(struct ether_header
));
1159 thismboff
= sizeof(struct ether_header
);
1160 thisrboff
= sizeof(struct ether_header
);
1161 resid
-= sizeof(struct ether_header
);
1164 * Now we take the mbuf chain (hopefully only one mbuf most of the
1165 * time) and stuff the data into it. There are no possible failures at
1166 * or after this point.
1169 int thisrblen
= ie_buflen(sc
, head
) - thisrboff
,
1170 thismblen
= m
->m_len
- thismboff
;
1171 len
= min(thisrblen
, thismblen
);
1173 /* bcopy((void *)(sc->cbuffs[head] + thisrboff),
1174 mtod(m, void *) + thismboff, (u_int)len); */
1179 ie2host(sc
, sc
->cbuffs
[head
]+thisrboff
,
1180 mtod(m
, void *) + thismboff
, (u_int
)len
+1);
1184 ie2host(sc
, sc
->cbuffs
[head
]+thisrboff
,
1185 mtod(m
, void *) + thismboff
, (u_int
)len
);
1190 if (len
== thismblen
) {
1196 if (len
== thisrblen
) {
1197 head
= (head
+ 1) % NRXBUF
;
1208 ie_drop_packet_buffer(struct ie_softc
*sc
)
1210 int i
, actual
, last
;
1213 READ_MEMBER(sc
,struct ie_recv_buf_desc
, ie_rbd_actual
,
1214 sc
->rbuffs
[sc
->rbhead
], actual
);
1215 if (!(actual
&IE_RBD_USED
))
1221 i
= actual
& IE_RBD_LAST
;
1223 READ_MEMBER(sc
,struct ie_recv_buf_desc
,ie_rbd_length
,
1224 sc
->rbuffs
[sc
->rbhead
], last
);
1225 last
|= IE_RBD_LAST
;
1226 WRITE_MEMBER(sc
,struct ie_recv_buf_desc
,ie_rbd_length
,
1227 sc
->rbuffs
[sc
->rbhead
], last
);
1229 WRITE_MEMBER(sc
,struct ie_recv_buf_desc
,ie_rbd_actual
,
1230 sc
->rbuffs
[sc
->rbhead
], 0 );
1232 sc
->rbhead
= ( sc
->rbhead
+ 1 ) % NRXBUF
;
1234 READ_MEMBER(sc
,struct ie_recv_buf_desc
,ie_rbd_length
,
1235 sc
->rbuffs
[sc
->rbtail
], last
);
1236 last
&= ~IE_RBD_LAST
;
1237 WRITE_MEMBER(sc
,struct ie_recv_buf_desc
,ie_rbd_length
,
1238 sc
->rbuffs
[sc
->rbtail
], last
);
1240 sc
->rbtail
= ( sc
->rbtail
+ 1 ) % NRXBUF
;
1245 ie_read_frame(struct ie_softc
*sc
, int num
)
1248 struct ie_recv_frame_desc rfd
;
1253 ifp
= &sc
->sc_ethercom
.ec_if
;
1255 ie2host(sc
, sc
->rframes
[num
], &rfd
, sizeof rfd
);
1256 status
= rfd
.ie_fd_status
;
1258 /* Advance the RFD list, since we're done with this descriptor */
1260 WRITE_MEMBER(sc
,struct ie_recv_frame_desc
,ie_fd_status
,
1261 sc
->rframes
[num
], 0 );
1263 READ_MEMBER(sc
,struct ie_recv_frame_desc
,ie_fd_last
,
1264 sc
->rframes
[num
], last
);
1266 WRITE_MEMBER(sc
,struct ie_recv_frame_desc
,ie_fd_last
,
1267 sc
->rframes
[num
], last
);
1269 READ_MEMBER(sc
,struct ie_recv_frame_desc
,ie_fd_last
,
1270 sc
->rframes
[sc
->rftail
], last
);
1271 last
&= ~IE_FD_LAST
;
1272 WRITE_MEMBER(sc
,struct ie_recv_frame_desc
,ie_fd_last
,
1273 sc
->rframes
[sc
->rftail
], last
);
1275 sc
->rftail
= ( sc
->rftail
+ 1 ) % NFRAMES
;
1276 sc
->rfhead
= ( sc
->rfhead
+ 1 ) % NFRAMES
;
1278 if ( status
& IE_FD_OK
) {
1280 ie_drop_packet_buffer(sc
);
1291 if ( ifp
->if_bpf
) {
1292 bpf_mtap(ifp
->if_bpf
, m
);
1296 (*ifp
->if_input
)(ifp
, m
);
1300 ierint(struct ie_softc
*sc
)
1303 int times_thru
= 1024;
1304 struct ie_sys_ctl_block scb
;
1306 int safety_catch
= 0;
1311 if ( (safety_catch
++)>100 )
1313 printf ( "ie: ierint safety catch tripped\n" );
1318 READ_MEMBER(sc
,struct ie_recv_frame_desc
,ie_fd_status
,
1319 sc
->rframes
[i
],status
);
1321 if ((status
&IE_FD_COMPLETE
)&&(status
&IE_FD_OK
)) {
1322 if ( !--times_thru
) {
1323 printf ( "IERINT: Uh oh. Nuts, look at this bit!!!\n" );
1324 ie2host ( sc
, IE_IBASE
+ IE_SCB_OFF
, &scb
, sizeof scb
);
1325 sc
->sc_ethercom
.ec_if
.if_ierrors
+= scb
.ie_err_crc
+
1327 scb
.ie_err_resource
+
1329 scb
.ie_err_crc
= scb
.ie_err_align
= 0;
1330 scb
.ie_err_resource
= scb
.ie_err_overrun
= 0;
1331 host2ie(sc
, &scb
, IE_SCP_ADDR
, sizeof (scb
) );
1333 ie_read_frame(sc
, i
);
1335 ie2host ( sc
, IE_IBASE
+ IE_SCB_OFF
, &scb
, sizeof scb
);
1337 if ( ((status
&IE_FD_RNR
)!=0) && ((scb
.ie_status
&IE_RU_READY
)==0) )
1339 WRITE_MEMBER(sc
,struct ie_recv_frame_desc
, ie_fd_buf_desc
,
1340 sc
->rframes
[0], sc
->rbuffs
[0] );
1342 scb
.ie_recv_list
= sc
->rframes
[0];
1343 host2ie(sc
, (char *)&scb
, IE_IBASE
+ IE_SCB_OFF
, sizeof (scb
) );
1344 command_and_wait(sc
, IE_RU_START
, &scb
, 0, 0, 0, 0);
1348 i
= (i
+ 1) % NFRAMES
;
1352 static int in_intr
= 0;
1357 struct ie_softc
*sc
= arg
;
1359 int safety_catch
= 0;
1360 static int safety_net
= 0;
1363 panic ( "ie: INTERRUPT REENTERED\n" );
1365 /* Clear the interrrupt */
1368 setpage(sc
, IE_IBASE
+ IE_SCB_OFF
);
1369 status
= ReadShort ( sc
->sc_ram
+ IE_COFF2POFF(IE_IBASE
+IE_SCB_OFF
) +
1370 (xoffsetof(struct ie_sys_ctl_block
, ie_status
)) );
1372 status
= status
& IE_ST_WHENCE
;
1383 if (status
& (IE_ST_FR
| IE_ST_RNR
))
1386 if (status
& IE_ST_CX
)
1389 if (status
& IE_ST_RNR
) {
1390 printf ( "ie: receiver not ready\n" );
1391 sc
->sc_ethercom
.ec_if
.if_ierrors
++;
1395 setpage(sc
, IE_IBASE
+ IE_SCB_OFF
);
1396 status
= ReadShort ( sc
->sc_ram
+ IE_COFF2POFF(IE_IBASE
+IE_SCB_OFF
) +
1397 (xoffsetof(struct ie_sys_ctl_block
, ie_status
)) );
1398 status
= status
& IE_ST_WHENCE
;
1407 /* This is prehaps a little over cautious */
1408 if ( safety_catch
++ > 10 )
1410 printf ( "ie: Interrupt couldn't be cleared\n" );
1413 if ( safety_net
++ > 50 )
1415 /* printf ( "ie: safety net catches driver, shutting down\n" );
1416 disable_irq ( IRQ_PODULE );*/
1426 iexmit(struct ie_softc
*sc
)
1429 struct ie_sys_ctl_block scb
;
1431 struct ie_xmit_cmd xc
;
1432 struct ie_xmit_buf xb
;
1434 ie2host(sc
, sc
->xmit_buffs
[sc
->xctail
], (char *)&xb
, sizeof xb
);
1435 xb
.ie_xmit_flags
|= IE_XMIT_LAST
;
1436 xb
.ie_xmit_next
= 0xffff;
1437 xb
.ie_xmit_buf
= (void *)sc
->xmit_cbuffs
[sc
->xctail
];
1438 host2ie(sc
, &xb
, sc
->xmit_buffs
[sc
->xctail
], sizeof xb
);
1440 bzero ( &xc
, sizeof xc
);
1441 xc
.com
.ie_cmd_link
= 0xffff;
1442 xc
.com
.ie_cmd_cmd
= IE_CMD_XMIT
| IE_CMD_INTR
| IE_CMD_LAST
;
1443 xc
.ie_xmit_status
= 0x0000;
1444 xc
.ie_xmit_desc
= sc
->xmit_buffs
[sc
->xctail
];
1445 host2ie(sc
, (char *)&xc
, sc
->xmit_cmds
[sc
->xctail
], sizeof xc
);
1447 ie2host ( sc
, IE_IBASE
+ IE_SCB_OFF
, &scb
, sizeof scb
);
1448 scb
.ie_command_list
= sc
->xmit_cmds
[sc
->xctail
];
1449 host2ie(sc
, (char *)&scb
, (IE_IBASE
+ IE_SCB_OFF
), sizeof scb
);
1451 command_and_wait(sc
, IE_CU_START
, &scb
, &xc
, sc
->xmit_cmds
[sc
->xctail
]
1452 , sizeof xc
, IE_STAT_COMPL
);
1454 sc
->sc_ethercom
.ec_if
.if_timer
= 5;
1457 * Start sending all the queued buffers.
1461 iestart(struct ifnet
*ifp
)
1463 struct ie_softc
*sc
= ifp
->if_softc
;
1464 struct mbuf
*m0
, *m
;
1467 char txbuf
[IE_TXBUF_SIZE
];
1468 int safety_catch
= 0;
1470 if ((ifp
->if_flags
& IFF_OACTIVE
) != 0)
1474 if ( (safety_catch
++)>100 )
1476 printf ( "ie: iestart safety catch tripped\n" );
1480 if (sc
->xmit_free
== 0) {
1481 ifp
->if_flags
|= IFF_OACTIVE
;
1485 IF_DEQUEUE(&ifp
->if_snd
, m
);
1489 /* TODO: Write directly to the card */
1491 /* buffer = sc->xmit_cbuffs[sc->xchead]; */
1494 for (m0
= m
; m
&& (len
+ m
->m_len
) < IE_TXBUF_SIZE
;
1496 memcpy(buffer
, mtod(m
, void *), m
->m_len
);
1503 bpf_mtap(ifp
->if_bpf
, m0
);
1507 if (len
< ETHER_MIN_LEN
- ETHER_CRC_LEN
) {
1508 memset(buffer
, 0, ETHER_MIN_LEN
- ETHER_CRC_LEN
- len
);
1509 len
= ETHER_MIN_LEN
- ETHER_CRC_LEN
;
1510 buffer
+= ETHER_MIN_LEN
- ETHER_CRC_LEN
;
1513 /* When we write directly to the card we dont need this */
1515 host2ie(sc
, txbuf
, sc
->xmit_cbuffs
[sc
->xchead
], len
+1 );
1517 host2ie(sc
, txbuf
, sc
->xmit_cbuffs
[sc
->xchead
], len
);
1519 /* sc->xmit_buffs[sc->xchead]->ie_xmit_flags = len; */
1521 WRITE_MEMBER(sc
,struct ie_xmit_buf
, ie_xmit_flags
,
1522 sc
->xmit_buffs
[sc
->xchead
], len
)
1524 /* Start the first packet transmitting. */
1525 if (sc
->xmit_free
== NTXBUF
)
1528 sc
->xchead
= (sc
->xchead
+ 1) % NTXBUF
;
1534 ietint(struct ie_softc
*sc
)
1536 struct ifnet
*ifp
= &sc
->sc_ethercom
.ec_if
;
1541 ifp
->if_flags
&= ~IFF_OACTIVE
;
1543 READ_MEMBER(sc
,struct ie_xmit_cmd
, ie_xmit_status
,
1544 sc
->xmit_cmds
[sc
->xctail
], status
);
1546 if (!(status
&IE_STAT_COMPL
) || (status
& IE_STAT_BUSY
) )
1547 printf ( "ietint: command still busy!\n" );
1549 if ( status
& IE_STAT_OK
) {
1551 ifp
->if_collisions
+= status
& IE_XS_MAXCOLL
;
1554 if ( status
& IE_STAT_ABORT
)
1555 printf ( "ie: send aborted\n" );
1556 if ( status
& IE_XS_LATECOLL
)
1557 printf ( "ie: late collision\n" );
1558 if ( status
& IE_XS_NOCARRIER
)
1559 printf ( "ie: no carrier\n" );
1560 if ( status
& IE_XS_LOSTCTS
)
1561 printf ( "ie: lost CTS\n" );
1562 if ( status
& IE_XS_UNDERRUN
)
1563 printf ( "ie: DMA underrun\n" );
1564 if ( status
& IE_XS_EXCMAX
)
1565 printf ( "ie: too many collisions\n" );
1566 ifp
->if_collisions
+=16;
1568 /* Done with the buffer */
1570 sc
->xctail
= (sc
->xctail
+ 1 ) % NTXBUF
;
1572 /* Start the next packet transmitting, if any */
1573 if ( sc
->xmit_free
<NTXBUF
)
1579 /* End of if_ie.c */