if_cs.c revision 38592
1/*
2 * Copyright (c) 1997,1998 Maxim Bolotin and Oleg Sharoiko.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice unmodified, this list of conditions, and the following
10 *    disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29/*
30 * $Id: if_cs.c,v 1.3 1998/08/13 20:31:17 msmith Exp $
31 *
32 * Device driver for Crystal Semiconductor CS8920 based ethernet
33 *   adapters. By Maxim Bolotin and Oleg Sharoiko, 27-April-1997
34 */
35
36/* #define	 CS_DEBUG */
37#include "cs.h"
38#include "bpfilter.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/malloc.h>
43#include <sys/sockio.h>
44#include <sys/kernel.h>
45#include <sys/mbuf.h>
46#include <sys/socket.h>
47#include <sys/sysctl.h>
48#include <sys/syslog.h>
49
50#include <net/if.h>
51#include <net/if_arp.h>
52#include <net/if_media.h>
53#include <net/ethernet.h>
54
55#if NBPFILTER > 0
56#include <net/bpf.h>
57#endif
58
59#include <machine/clock.h>
60
61#include <i386/isa/isa_device.h>
62#include <i386/isa/if_csreg.h>
63
64#include "pnp.h"
65
66#if NPNP > 0
67#include <i386/isa/pnp.h>
68#endif
69
70#ifdef  CS_USE_64K_DMA
71#define CS_DMA_BUFFER_SIZE 65536
72#else
73#define CS_DMA_BUFFER_SIZE 16384
74#endif
75
76/*
77 * cs_softc: per line info and status
78 */
79static struct cs_softc {
80
81        /* Ethernet common code */
82        struct arpcom arpcom;
83
84        /* Configuration words from EEPROM */
85        int auto_neg_cnf;               /* AutoNegotitation configuration */
86	int adapter_cnf;                /* Adapter configuration */
87        int isa_config;                 /* ISA configuration */
88        int chip_type;			/* Type of chip */
89
90        struct ifmedia media;		/* Media information */
91
92        int nic_addr; 			/* Base IO address of card */
93	int send_cmd;
94        int line_ctl;                   /* */
95        int send_underrun;
96        void *recv_ring;
97
98        unsigned char *buffer;
99        int buf_len;
100
101} cs_softc[NCS];
102
103static u_long	cs_unit = NCS;
104
105static int	cs_recv_delay = 570;
106SYSCTL_INT(_machdep, OID_AUTO, cs_recv_delay, CTLFLAG_RW, &cs_recv_delay, 0, "");
107
108static int	cs_attach		__P((struct cs_softc *, int, int));
109static int	cs_attach_isa		__P((struct isa_device *));
110static void	cs_init			__P((void *));
111static int	cs_ioctl		__P((struct ifnet *, u_long, caddr_t));
112static int	cs_probe		__P((struct isa_device *));
113static int	cs_cs89x0_probe		__P((struct cs_softc *,
114					 u_int *, int *, int, int, int));
115static void	cs_start		__P((struct ifnet *));
116static void	cs_stop			__P((struct cs_softc *));
117static void	cs_reset		__P((struct cs_softc *));
118static void	cs_watchdog		__P((struct ifnet *));
119
120static int	cs_mediachange	__P((struct ifnet *));
121static void	cs_mediastatus	__P((struct ifnet *, struct ifmediareq *));
122static int      cs_mediaset	__P((struct cs_softc *, int));
123
124static void	cs_write_mbufs(struct cs_softc*, struct mbuf*);
125static void	cs_xmit_buf(struct cs_softc*);
126static int	cs_get_packet(struct cs_softc*);
127static void	cs_setmode(struct cs_softc*);
128
129static int	get_eeprom_data(struct cs_softc *sc, int, int, int *);
130static int	get_eeprom_cksum(int, int, int *);
131static int	wait_eeprom_ready( struct cs_softc *);
132static void	control_dc_dc( struct cs_softc *, int );
133static int	send_test_pkt( struct cs_softc * );
134static int	enable_tp(struct cs_softc *);
135static int	enable_aui(struct cs_softc *);
136static int	enable_bnc(struct cs_softc *);
137static int      cs_duplex_auto(struct cs_softc *);
138
139struct isa_driver csdriver = {
140	cs_probe,
141	cs_attach_isa,
142	CS_NAME,
143	0
144};
145
146static int
147get_eeprom_data( struct cs_softc *sc, int off, int len, int *buffer)
148{
149	int i;
150
151#ifdef CS_DEBUG
152	printf(CS_NAME":EEPROM data from %x for %x:\n", off,len);
153#endif
154
155	for (i=0;i<len;i++) {
156		if (wait_eeprom_ready(sc) < 0) return -1;
157		/* Send command to EEPROM to read */
158		cs_writereg(sc->nic_addr, PP_EECMD, (off+i)|EEPROM_READ_CMD );
159		if (wait_eeprom_ready(sc)<0)
160			return -1;
161		buffer[i] = cs_readreg (sc->nic_addr, PP_EEData);
162
163#ifdef CS_DEBUG
164		printf("%02x %02x ",(unsigned char)buffer[i],
165					(unsigned char)buffer[i+1]);
166#endif
167	}
168
169#ifdef CS_DEBUG
170	printf("\n");
171#endif
172
173	return 0;
174}
175
176static int
177get_eeprom_cksum(int off, int len, int *buffer)
178{
179	int i,cksum=0;
180
181	for (i=0;i<len;i++)
182		cksum+=buffer[i];
183	cksum &= 0xffff;
184	if (cksum==0)
185		return 0;
186	return -1;
187}
188
189static int
190wait_eeprom_ready(struct cs_softc *sc)
191{
192	int timeout=1000;
193	DELAY ( 30000 );	/* XXX should we do some checks here ? */
194	return 0;
195}
196
197static void
198control_dc_dc(struct cs_softc *sc, int on_not_off)
199{
200	unsigned int self_control = HCB1_ENBL;
201
202	if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0) ^ on_not_off)
203		self_control |= HCB1;
204	else
205		self_control &= ~HCB1;
206	cs_writereg( sc->nic_addr, PP_SelfCTL, self_control );
207
208	DELAY( 500000 );
209}
210
211
212static int
213cs_duplex_auto(struct cs_softc *sc)
214{
215        int i, error=0, unit=sc->arpcom.ac_if.if_unit;
216
217        cs_writereg(sc->nic_addr, PP_AutoNegCTL,
218                    RE_NEG_NOW | ALLOW_FDX | AUTO_NEG_ENABLE );
219        for (i=0; cs_readreg(sc->nic_addr,PP_AutoNegST)&AUTO_NEG_BUSY; i++) {
220                if (i > 40000) {
221                        printf(CS_NAME"%1d: full/half duplex "
222                               "auto negotiation timeout\n", unit);
223			error = ETIMEDOUT;
224                        break;
225                }
226                DELAY(1000);
227        }
228        DELAY( 1000000 );
229	return error;
230}
231
232static int
233enable_tp(struct cs_softc *sc)
234{
235	int i;
236	int unit = sc->arpcom.ac_if.if_unit;
237
238	cs_writereg(sc->nic_addr, PP_LineCTL, sc->line_ctl & ~AUI_ONLY);
239	control_dc_dc(sc, 0);
240	DELAY( 150000 );
241
242	if ((cs_readreg(sc->nic_addr, PP_LineST) & LINK_OK)==0) {
243		printf(CS_NAME"%1d: failed to enable TP\n", unit);
244                return EINVAL;
245	}
246
247	return 0;
248}
249
250/*
251 * XXX This was rewritten from Linux driver without any tests.
252 */
253static int
254send_test_pkt(struct cs_softc *sc)
255{
256	int unit = sc->arpcom.ac_if.if_unit;
257	char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
258				0, 46,  /* A 46 in network order */
259				0, 0,   /* DSAP=0 & SSAP=0 fields */
260				0xf3, 0 /* Control (Test Req + P bit set) */ };
261	int i;
262	u_char ether_address_backup[ETHER_ADDR_LEN];
263
264	for (i = 0; i < ETHER_ADDR_LEN; i++) {
265		ether_address_backup[i] = sc->arpcom.ac_enaddr[i];
266	}
267
268	cs_writereg(sc->nic_addr, PP_LineCTL,
269		cs_readreg(sc->nic_addr, PP_LineCTL) | SERIAL_TX_ON );
270	bcopy(test_packet,
271			sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
272	bcopy(test_packet+ETHER_ADDR_LEN,
273			sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
274	outw(sc->nic_addr + TX_CMD_PORT, sc->send_cmd);
275	outw(sc->nic_addr + TX_LEN_PORT, sizeof(test_packet));
276
277	/* Wait for chip to allocate memory */
278	DELAY(50000);
279	if (!(cs_readreg(sc->nic_addr, PP_BusST) & READY_FOR_TX_NOW)) {
280		for (i = 0; i < ETHER_ADDR_LEN; i++) {
281			sc->arpcom.ac_enaddr[i] = ether_address_backup[i];
282		}
283		return 0;
284	}
285
286	outsw(sc->nic_addr + TX_FRAME_PORT, test_packet, sizeof(test_packet));
287
288	DELAY(30000);
289
290	if ((cs_readreg(sc->nic_addr,PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
291		for (i = 0; i < ETHER_ADDR_LEN; i++) {
292			sc->arpcom.ac_enaddr[i] = ether_address_backup[i];
293		}
294		return 1;
295	}
296	for (i = 0; i < ETHER_ADDR_LEN; i++) {
297		sc->arpcom.ac_enaddr[i] = ether_address_backup[i];
298	}
299	return 0;
300}
301
302/*
303 * XXX This was rewritten from Linux driver without any tests.
304 */
305static int
306enable_aui(struct cs_softc *sc)
307{
308	int unit = sc->arpcom.ac_if.if_unit;
309
310	control_dc_dc(sc, 0);
311	cs_writereg(sc->nic_addr, PP_LineCTL,
312		(sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY);
313
314	if (!send_test_pkt(sc)) {
315		printf(CS_NAME"%1d failed to enable AUI\n", unit);
316		return EINVAL;
317        }
318        return 0;
319}
320
321/*
322 * XXX This was rewritten from Linux driver without any tests.
323 */
324static int
325enable_bnc(struct cs_softc *sc)
326{
327	int unit = sc->arpcom.ac_if.if_unit;
328
329	control_dc_dc(sc, 1);
330	cs_writereg(sc->nic_addr, PP_LineCTL,
331		(sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY);
332
333	if (!send_test_pkt(sc)) {
334		printf(CS_NAME"%1d failed to enable BNC\n", unit);
335		return EINVAL;
336        }
337        return 0;
338}
339
340static int
341cs_cs89x0_probe(struct cs_softc *sc, u_int *dev_irq,
342			int *dev_drq, int iobase, int unit, int flags)
343{
344	unsigned rev_type = 0;
345	int i, irq=0, result;
346	int eeprom_buff[CHKSUM_LEN];
347	int chip_type, pp_isaint, pp_isadma;
348	char chip_revision;
349
350	if ((inw(iobase+ADD_PORT) & ADD_MASK) != ADD_SIG) {
351		/* Chip not detected. Let's try to reset it */
352		if (bootverbose)
353			printf(CS_NAME"%1d: trying to reset the chip.\n", unit);
354		outw(iobase+ADD_PORT, PP_SelfCTL);
355		i = inw(iobase+DATA_PORT);
356		outw(iobase+ADD_PORT, PP_SelfCTL);
357		outw(iobase+DATA_PORT, i | POWER_ON_RESET);
358		if ((inw(iobase+ADD_PORT) & ADD_MASK) != ADD_SIG)
359			return 0;
360	}
361
362	outw(iobase+ADD_PORT, PP_ChipID);
363	if (inw(iobase+DATA_PORT) != CHIP_EISA_ID_SIG)
364		return 0;
365
366	rev_type = cs_readreg(iobase, PRODUCT_ID_ADD);
367	chip_type = rev_type & ~REVISON_BITS;
368	chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
369
370	sc->nic_addr = iobase;
371	sc->chip_type = chip_type;
372	if(chip_type==CS8900) {
373		pp_isaint = PP_CS8900_ISAINT;
374		pp_isadma = PP_CS8900_ISADMA;
375		sc->send_cmd = TX_CS8900_AFTER_ALL;
376	} else {
377		pp_isaint = PP_CS8920_ISAINT;
378		pp_isadma = PP_CS8920_ISADMA;
379		sc->send_cmd = TX_CS8920_AFTER_ALL;
380	}
381
382        /*
383         * Clear some fields so that fail of EEPROM will left them clean
384         */
385        sc->auto_neg_cnf = 0;
386        sc->adapter_cnf  = 0;
387        sc->isa_config   = 0;
388
389	/*
390	 * EEPROM
391	 */
392	if((cs_readreg(iobase, PP_SelfST) & EEPROM_PRESENT) == 0) {
393		printf(CS_NAME"%1d: No EEPROM, assuming defaults.\n",
394			unit);
395	} else {
396		if (get_eeprom_data(sc,START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) {
397			 printf(CS_NAME"%1d: EEPROM read failed, "
398				"assuming defaults..\n", unit);
399		} else {
400			if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) {
401				printf( CS_NAME"%1d: EEPROM cheksum bad, "
402					"assuming defaults..\n", unit );
403			} else {
404                                sc->auto_neg_cnf =
405                                        eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
406                                sc->adapter_cnf =
407                                        eeprom_buff[ADAPTER_CNF_OFFSET/2];
408                                sc->isa_config =
409                                        eeprom_buff[ISA_CNF_OFFSET/2];
410
411                                for (i=0; i<ETHER_ADDR_LEN/2; i++) {
412                                        sc->arpcom.ac_enaddr[i*2]=
413                                                eeprom_buff[i];
414                                        sc->arpcom.ac_enaddr[i*2+1]=
415                                                eeprom_buff[i] >> 8;
416                                }
417
418                                /*
419                                 * If no interrupt specified (or "?"),
420                                 * use what the board tells us.
421                                 */
422                                if (*dev_irq <= 0) {
423                                        irq = sc->isa_config & INT_NO_MASK;
424                                        if (chip_type==CS8900) {
425						switch(irq) {
426                                                case 0: irq=10; break;
427                                                case 1: irq=11; break;
428                                                case 2: irq=12; break;
429                                                case 3: irq=5;  break;
430                                                default: printf(CS_NAME"%1d: invalid irq in EEPROM.\n",unit);
431						}
432						if (irq!=0)
433							*dev_irq=(u_short)(1<<irq);
434					} else {
435						if (irq!=0 && irq<=CS8920_NO_INTS)
436							*dev_irq=(u_short)(1<<irq);
437					}
438                                }
439			}
440                }
441        }
442
443        if ((irq=ffs(*dev_irq))) {
444                irq--;
445                if (chip_type == CS8900) {
446			switch(irq) {
447                        case  5: irq = 3; break;
448                        case 10: irq = 0; break;
449                        case 11: irq = 1; break;
450                        case 12: irq = 2; break;
451                        default: printf(CS_NAME"%1d: invalid irq\n", unit);
452                                return 0;
453			}
454                } else {
455                        if (irq > CS8920_NO_INTS) {
456                                printf(CS_NAME"%1d: invalid irq\n", unit);
457                                return 0;
458                        }
459                }
460                cs_writereg(iobase, pp_isaint, irq);
461	} else {
462	       	printf(CS_NAME"%1d: invalid irq\n", unit);
463                return 0;
464        }
465
466        /*
467         * Temporary disabled
468         *
469        if (drq>0)
470		cs_writereg(iobase, pp_isadma, drq);
471	else {
472		printf( CS_NAME"%1d: incorrect drq\n", unit );
473		return 0;
474	}
475        */
476
477	if (bootverbose)
478		 printf(CS_NAME"%1d: model CS89%c0%s rev %c\n"
479			CS_NAME"%1d: media%s%s%s\n"
480			CS_NAME"%1d: irq %d drq %d\n",
481			unit,
482			chip_type==CS8900 ? '0' : '2',
483			chip_type==CS8920M ? "M" : "",
484			chip_revision,
485			unit,
486			(sc->adapter_cnf & A_CNF_10B_T) ? " TP"  : "",
487			(sc->adapter_cnf & A_CNF_AUI)   ? " AUI" : "",
488			(sc->adapter_cnf & A_CNF_10B_2) ? " BNC" : "",
489			unit, (int)*dev_irq, (int)*dev_drq);
490
491        if ((sc->adapter_cnf & A_CNF_EXTND_10B_2) &&
492            (sc->adapter_cnf & A_CNF_LOW_RX_SQUELCH))
493                sc->line_ctl = LOW_RX_SQUELCH;
494        else
495                sc->line_ctl = 0;
496
497
498	return PP_ISAIOB;
499}
500
501/*
502 * Determine if the device is present
503 *
504 *   on entry:
505 * 	a pointer to an isa_device struct
506 *   on exit:
507 *	NULL if device not found
508 *	or # of i/o addresses used (if found)
509 */
510static int
511cs_probe(struct isa_device *dev)
512{
513	int nports;
514
515	struct cs_softc *sc=&cs_softc[dev->id_unit];
516
517	nports=cs_cs89x0_probe(sc, &(dev->id_irq), &(dev->id_drq),
518			(dev->id_iobase), (dev->id_unit), (dev->id_flags));
519
520	if (nports)
521		return (nports);
522
523	return (0);
524}
525
526/*
527 * Install the interface into kernel networking data structures
528 */
529static int
530cs_attach(struct cs_softc *sc, int unit, int flags)
531{
532        int media=0;
533/*	struct cs_softc *sc = &cs_softc[dev->id_unit]; */
534	struct ifnet *ifp = &(sc->arpcom.ac_if);
535
536	if (!ifp->if_name) {
537		ifp->if_softc=sc;
538		ifp->if_unit=unit;
539		ifp->if_name=csdriver.name;
540		ifp->if_output=ether_output;
541		ifp->if_start=cs_start;
542		ifp->if_ioctl=cs_ioctl;
543		ifp->if_watchdog=cs_watchdog;
544		ifp->if_init=cs_init;
545		ifp->if_snd.ifq_maxlen= IFQ_MAXLEN;
546		/*
547                 *  MIB DATA
548                 */
549                /*
550		ifp->if_linkmib=&sc->mibdata;
551		ifp->if_linkmiblen=sizeof sc->mibdata;
552                */
553
554		ifp->if_flags=(IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST );
555
556		/*
557		 * this code still in progress (DMA support)
558		 *
559
560		sc->recv_ring=malloc(CS_DMA_BUFFER_SIZE<<1, M_DEVBUF, M_NOWAIT);
561		if (sc->recv_ring == NULL) {
562			log(LOG_ERR,CS_NAME
563			"%d: Couldn't allocate memory for NIC\n", unit);
564			return(0);
565		}
566		if ((sc->recv_ring-(sc->recv_ring & 0x1FFFF))
567		    < (128*1024-CS_DMA_BUFFER_SIZE))
568		    sc->recv_ring+=16*1024;
569
570		*/
571
572		sc->buffer=malloc(ETHER_MAX_LEN-ETHER_CRC_LEN,M_DEVBUF,M_NOWAIT);
573		if (sc->buffer == NULL) {
574                        printf(CS_NAME"%d: Couldn't allocate memory for NIC\n",
575                               unit);
576                        return(0);
577		}
578
579		/*
580		 * Initialize the media structures.
581		 */
582		ifmedia_init(&sc->media, 0, cs_mediachange, cs_mediastatus);
583
584		if (sc->adapter_cnf & A_CNF_10B_T) {
585			ifmedia_add(&sc->media, IFM_ETHER|IFM_10_T, 0, NULL);
586			if (sc->chip_type != CS8900) {
587				ifmedia_add(&sc->media,
588					IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
589				ifmedia_add(&sc->media,
590					IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
591			}
592		}
593
594		if (sc->adapter_cnf & A_CNF_10B_2)
595			ifmedia_add(&sc->media, IFM_ETHER|IFM_10_2, 0, NULL);
596
597		if (sc->adapter_cnf & A_CNF_AUI)
598			ifmedia_add(&sc->media, IFM_ETHER|IFM_10_5, 0, NULL);
599
600                if (sc->adapter_cnf & A_CNF_MEDIA)
601                        ifmedia_add(&sc->media, IFM_ETHER|IFM_AUTO, 0, NULL);
602
603                /* Set default media from EEPROM */
604                switch (sc->adapter_cnf & A_CNF_MEDIA_TYPE) {
605                case A_CNF_MEDIA_AUTO:  media = IFM_ETHER|IFM_AUTO; break;
606                case A_CNF_MEDIA_10B_T: media = IFM_ETHER|IFM_10_T; break;
607                case A_CNF_MEDIA_10B_2: media = IFM_ETHER|IFM_10_2; break;
608                case A_CNF_MEDIA_AUI:   media = IFM_ETHER|IFM_10_5; break;
609                default: printf(CS_NAME"%d: adapter has no media\n", unit);
610                }
611                ifmedia_set(&sc->media, media);
612		cs_mediaset(sc, media);
613
614		if_attach(ifp);
615		cs_stop( sc );
616		ether_ifattach(ifp);
617	}
618
619	if (bootverbose)
620		printf(CS_NAME"%d: ethernet address %6D\n",
621		       ifp->if_unit, sc->arpcom.ac_enaddr, ":");
622
623#if NBPFILTER > 0
624	bpfattach(ifp, DLT_EN10MB, sizeof (struct ether_header));
625#endif
626	return 1;
627}
628
629static int
630cs_attach_isa(struct isa_device *dev)
631{
632        int unit=dev->id_unit;
633        struct cs_softc *sc=&cs_softc[unit];
634        int flags=dev->id_flags;
635
636        return cs_attach(sc, unit, flags);
637}
638
639/*
640 * Initialize the board
641 */
642static void
643cs_init(void *xsc)
644{
645	struct cs_softc *sc=(struct cs_softc *)xsc;
646	struct ifnet *ifp = &sc->arpcom.ac_if;
647	int i, s, result, rx_cfg;
648
649	/* address not known */
650	if (TAILQ_EMPTY(&ifp->if_addrhead)) /* unlikely? XXX */
651		return;
652
653	/*
654	 * reset whatchdog timer
655	 */
656	ifp->if_timer=0;
657	sc->buf_len = 0;
658
659	s=splimp();
660
661	/*
662	 * Hardware initialization of cs
663	 */
664
665	/* Enable receiver and transmitter */
666	cs_writereg(sc->nic_addr, PP_LineCTL,
667		cs_readreg( sc->nic_addr, PP_LineCTL ) |
668		SERIAL_RX_ON | SERIAL_TX_ON);
669
670	/* Configure the receiver mode */
671	cs_setmode(sc);
672
673	/*
674	 * This defines what type of frames will cause interrupts
675	 * Bad frames should generate interrupts so that the driver
676	 * could track statistics of discarded packets
677	 */
678        rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL | RX_RUNT_ENBL |
679		 RX_EXTRA_DATA_ENBL;
680	if (sc->isa_config & STREAM_TRANSFER)
681		rx_cfg |= RX_STREAM_ENBL;
682	cs_writereg(sc->nic_addr, PP_RxCFG, rx_cfg);
683
684	cs_writereg(sc->nic_addr, PP_TxCFG, TX_LOST_CRS_ENBL |
685		    TX_SQE_ERROR_ENBL | TX_OK_ENBL | TX_LATE_COL_ENBL |
686		    TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
687
688	cs_writereg(sc->nic_addr, PP_BufCFG, READY_FOR_TX_ENBL |
689		    RX_MISS_COUNT_OVRFLOW_ENBL | TX_COL_COUNT_OVRFLOW_ENBL |
690		    TX_UNDERRUN_ENBL /*| RX_DMA_ENBL*/);
691
692        /* Write MAC address into IA filter */
693        for (i=0; i<ETHER_ADDR_LEN/2; i++)
694                cs_writereg(sc->nic_addr, PP_IA+i*2,
695                            sc->arpcom.ac_enaddr[i*2] |
696                            (sc->arpcom.ac_enaddr[i*2+1] << 8) );
697
698	/*
699	 * Now enable everything
700	 */
701/*
702#ifdef	CS_USE_64K_DMA
703	cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ | RX_DMA_SIZE_64K);
704        #else
705
706        cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ);
707#endif
708*/
709	cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ);
710
711	/*
712	 * Set running and clear output active flags
713	 */
714	sc->arpcom.ac_if.if_flags |= IFF_RUNNING;
715	sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
716
717	/*
718	 * Start sending process
719	 */
720	cs_start(ifp);
721
722	(void) splx(s);
723}
724
725/*
726 * Get the packet from the board and send it to the upper layer
727 * via ether_input().
728 */
729static int
730cs_get_packet(struct cs_softc *sc)
731{
732	struct ifnet *ifp = &(sc->arpcom.ac_if);
733	int iobase = sc->nic_addr, status, length;
734	struct ether_header *eh;
735	struct mbuf *m;
736
737#ifdef CS_DEBUG
738	int i;
739#endif
740
741	status = inw(iobase + RX_FRAME_PORT);
742	length = inw(iobase + RX_FRAME_PORT);
743
744#ifdef CS_DEBUG
745	printf(CS_NAME"%1d: rcvd: stat %x, len %d\n",
746		ifp->if_unit, status, length);
747#endif
748
749	if (!(status & RX_OK)) {
750#ifdef CS_DEBUG
751		printf(CS_NAME"%1d: bad pkt stat %x\n", ifp->if_unit, status);
752#endif
753		ifp->if_ierrors++;
754		return -1;
755	}
756
757	MGETHDR(m, M_DONTWAIT, MT_DATA);
758	if (m==NULL)
759		return -1;
760
761	if (length > MHLEN) {
762		MCLGET(m, M_DONTWAIT);
763		if (!(m->m_flags & M_EXT)) {
764			m_freem(m);
765			return -1;
766		}
767	}
768
769	/* Initialize packet's header info */
770	m->m_pkthdr.rcvif = ifp;
771	m->m_pkthdr.len = length;
772	m->m_len = length;
773
774	/* Get the data */
775	insw(iobase + RX_FRAME_PORT, m->m_data, (length+1)>>1);
776
777	eh = mtod(m, struct ether_header *);
778
779#if NBPFILTER > 0
780	if (ifp->if_bpf)
781		bpf_mtap(ifp, m);
782#endif
783
784#ifdef CS_DEBUG
785	for (i=0;i<length;i++)
786	     printf(" %02x",(unsigned char)*((char *)(m->m_data+i)));
787	printf( "\n" );
788#endif
789
790	if (status & (RX_IA | RX_BROADCAST) ||
791	    (ifp->if_flags & IFF_MULTICAST && status & RX_HASHED)) {
792		m->m_pkthdr.len -= sizeof(struct ether_header);
793		m->m_len -= sizeof(struct ether_header);
794		m->m_data += sizeof(struct ether_header);
795
796		/* Feed the packet to the upper layer */
797		ether_input(ifp, eh, m);
798
799		ifp->if_ipackets++;
800
801		if (length==ETHER_MAX_LEN-ETHER_CRC_LEN)
802                        DELAY( cs_recv_delay );
803	} else {
804		m_freem(m);
805	}
806
807	return 0;
808}
809
810/*
811 * Software calls interrupt handler
812 */
813static void
814csintr_sc(struct cs_softc *sc, int unit)
815{
816	struct ifnet *ifp = &(sc->arpcom.ac_if);
817	int status, s;
818
819#ifdef CS_DEBUG
820	printf(CS_NAME"%1d: Interrupt.\n", unit);
821#endif
822
823	while ((status=cs_readword(sc->nic_addr, ISQ_PORT))) {
824
825#ifdef CS_DEBUG
826		printf( CS_NAME"%1d:from ISQ: %04x\n", unit, status );
827#endif
828
829		switch (status & ISQ_EVENT_MASK) {
830                case ISQ_RECEIVER_EVENT:
831                        cs_get_packet(sc);
832                        break;
833
834                case ISQ_TRANSMITTER_EVENT:
835                        if (status & TX_OK)
836                                ifp->if_opackets++;
837                        else
838                                ifp->if_oerrors++;
839                        ifp->if_flags &= ~IFF_OACTIVE;
840                        ifp->if_timer = 0;
841                        break;
842
843                case ISQ_BUFFER_EVENT:
844                        if (status & READY_FOR_TX) {
845                                ifp->if_flags &= ~IFF_OACTIVE;
846                                ifp->if_timer = 0;
847                        }
848
849                        if (status & TX_UNDERRUN) {
850                                ifp->if_flags &= ~IFF_OACTIVE;
851                                ifp->if_timer = 0;
852                                ifp->if_oerrors++;
853                        }
854                        break;
855
856                case ISQ_RX_MISS_EVENT:
857                        ifp->if_ierrors+=(status>>6);
858                        break;
859
860                case ISQ_TX_COL_EVENT:
861                        ifp->if_collisions+=(status>>6);
862                        break;
863                }
864        }
865
866        if (!(ifp->if_flags & IFF_OACTIVE)) {
867                cs_start(ifp);
868        }
869}
870
871/*
872 * Handle interrupts
873 */
874void
875csintr(int unit)
876{
877	struct cs_softc *sc = &cs_softc[unit];
878
879	csintr_sc(sc, unit);
880}
881
882/*
883 * Save the data in buffer
884 */
885
886static void
887cs_write_mbufs( struct cs_softc *sc, struct mbuf *m )
888{
889	int len;
890	struct mbuf *mp;
891	unsigned char *data, *buf;
892
893	for (mp=m, buf=sc->buffer, sc->buf_len=0; mp != NULL; mp=mp->m_next) {
894		len = mp->m_len;
895
896		/*
897		 * Ignore empty parts
898		 */
899		if (!len)
900		continue;
901
902		/*
903		 * Find actual data address
904		 */
905		data = mtod(mp, caddr_t);
906
907		bcopy((caddr_t) data, (caddr_t) buf, len);
908		buf += len;
909		sc->buf_len += len;
910	}
911}
912
913
914static void
915cs_xmit_buf( struct cs_softc *sc )
916{
917	outsw(sc->nic_addr+TX_FRAME_PORT, sc->buffer, (sc->buf_len+1)>>1);
918	sc->buf_len = 0;
919}
920
921static void
922cs_start(struct ifnet *ifp)
923{
924	int s, length;
925	struct mbuf *m, *mp;
926	struct cs_softc *sc = ifp->if_softc;
927
928	s = splimp();
929
930	for (;;) {
931		if (sc->buf_len)
932			length = sc->buf_len;
933		else {
934			IF_DEQUEUE( &ifp->if_snd, m );
935
936			if (m==NULL) {
937				(void) splx(s);
938				return;
939			}
940
941			for (length=0, mp=m; mp != NULL; mp=mp->m_next)
942				length += mp->m_len;
943
944			/* Skip zero-length packets */
945			if (length == 0) {
946				m_freem(m);
947				continue;
948			}
949
950			cs_write_mbufs(sc, m);
951
952#if NBPFILTER > 0
953			if (ifp->if_bpf) {
954				bpf_mtap(ifp, m);
955			}
956#endif
957
958			m_freem(m);
959		}
960
961		/*
962		 * Issue a SEND command
963		 */
964		outw(sc->nic_addr+TX_CMD_PORT, sc->send_cmd);
965		outw(sc->nic_addr+TX_LEN_PORT, length );
966
967		/*
968		 * If there's no free space in the buffer then leave
969		 * this packet for the next time: indicate output active
970		 * and return.
971		 */
972		if (!(cs_readreg(sc->nic_addr, PP_BusST) & READY_FOR_TX_NOW)) {
973			ifp->if_timer = sc->buf_len;
974			(void) splx(s);
975			ifp->if_flags |= IFF_OACTIVE;
976			return;
977		}
978
979               	cs_xmit_buf(sc);
980
981		/*
982		 * Set the watchdog timer in case we never hear
983		 * from board again. (I don't know about correct
984		 * value for this timeout)
985		 */
986		ifp->if_timer = length;
987
988		(void) splx(s);
989		ifp->if_flags |= IFF_OACTIVE;
990		return;
991	}
992}
993
994/*
995 * Stop everything on the interface
996 */
997static void
998cs_stop(struct cs_softc *sc)
999{
1000	int s = splimp();
1001
1002	cs_writereg(sc->nic_addr, PP_RxCFG, 0);
1003	cs_writereg(sc->nic_addr, PP_TxCFG, 0);
1004	cs_writereg(sc->nic_addr, PP_BufCFG, 0);
1005	cs_writereg(sc->nic_addr, PP_BusCTL, 0);
1006
1007	sc->arpcom.ac_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1008	sc->arpcom.ac_if.if_timer = 0;
1009
1010	(void) splx(s);
1011}
1012
1013/*
1014 * Reset the interface
1015 */
1016static void
1017cs_reset(struct cs_softc *sc)
1018{
1019	cs_stop(sc);
1020	cs_init(sc);
1021}
1022
1023static void
1024cs_setmode(struct cs_softc *sc)
1025{
1026	struct ifnet *ifp = &(sc->arpcom.ac_if);
1027	int rx_ctl;
1028
1029	/* Stop the receiver while changing filters */
1030	cs_writereg(sc->nic_addr, PP_LineCTL,
1031			cs_readreg(sc->nic_addr, PP_LineCTL) & ~SERIAL_RX_ON);
1032
1033	if (ifp->if_flags & IFF_PROMISC) {
1034		/* Turn on promiscuous mode. */
1035		rx_ctl = RX_OK_ACCEPT | RX_PROM_ACCEPT;
1036	} else {
1037		if (ifp->if_flags & IFF_MULTICAST) {
1038			/* Allow receiving frames with multicast addresses */
1039			rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT |
1040				 RX_OK_ACCEPT | RX_MULTCAST_ACCEPT;
1041			/*
1042			 * Here the reconfiguration of chip's multicast
1043			 * filters should be done but I've no idea about
1044			 * hash transformation in this chip. If you can
1045			 * add this code or describe me the transformation
1046			 * I'd be very glad.
1047			 */
1048		} else {
1049			/*
1050			 * Receive only good frames addressed for us and
1051			 * good broadcasts.
1052			 */
1053			rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT |
1054				 RX_OK_ACCEPT;
1055		}
1056	}
1057
1058	/* Set up the filter */
1059	cs_writereg(sc->nic_addr, PP_RxCTL, RX_DEF_ACCEPT | RX_MULTCAST_ACCEPT);
1060
1061	/* Turn on receiver */
1062	cs_writereg(sc->nic_addr, PP_LineCTL,
1063			cs_readreg(sc->nic_addr, PP_LineCTL) | SERIAL_RX_ON);
1064}
1065
1066static int
1067cs_ioctl(register struct ifnet *ifp, u_long command, caddr_t data)
1068{
1069	struct cs_softc *sc=ifp->if_softc;
1070	struct ifreq *ifr = (struct ifreq *)data;
1071	int s,error=0;
1072
1073#ifdef CS_DEBUG
1074	printf(CS_NAME"%d: ioctl(%x)\n",sc->arpcom.ac_if.if_unit,command);
1075#endif
1076
1077	s=splimp();
1078
1079	switch (command) {
1080	case SIOCSIFADDR:
1081	case SIOCGIFADDR:
1082	case SIOCSIFMTU:
1083		ether_ioctl(ifp, command, data);
1084		break;
1085
1086	case SIOCSIFFLAGS:
1087		/*
1088		 * Switch interface state between "running" and
1089		 * "stopped", reflecting the UP flag.
1090                 */
1091                if (sc->arpcom.ac_if.if_flags & IFF_UP) {
1092                        if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)==0) {
1093                                cs_init(sc);
1094                        }
1095                } else {
1096                        if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)!=0) {
1097                                cs_stop(sc);
1098                        }
1099		}
1100		/*
1101		 * Promiscuous and/or multicast flags may have changed,
1102		 * so reprogram the multicast filter and/or receive mode.
1103		 *
1104		 * See note about multicasts in cs_setmode
1105		 */
1106		cs_setmode(sc);
1107		break;
1108
1109	case SIOCADDMULTI:
1110	case SIOCDELMULTI:
1111	    /*
1112	     * Multicast list has changed; set the hardware filter
1113	     * accordingly.
1114	     *
1115	     * See note about multicasts in cs_setmode
1116	     */
1117	    cs_setmode(sc);
1118	    error = 0;
1119	    break;
1120
1121        case SIOCSIFMEDIA:
1122        case SIOCGIFMEDIA:
1123                error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
1124                break;
1125
1126        default:
1127		error = EINVAL;
1128        }
1129
1130	(void) splx(s);
1131	return error;
1132}
1133
1134/*
1135 * Device timeout/watchdog routine. Entered if the device neglects to
1136 * generate an interrupt after a transmit has been started on it.
1137 */
1138static void
1139cs_watchdog(struct ifnet *ifp)
1140{
1141	struct cs_softc *sc = &cs_softc[ifp->if_unit];
1142
1143	ifp->if_oerrors++;
1144	log(LOG_ERR, CS_NAME"%d: device timeout\n", ifp->if_unit);
1145
1146	/* Reset the interface */
1147	if (ifp->if_flags & IFF_UP)
1148		cs_reset(sc);
1149	else
1150		cs_stop(sc);
1151}
1152
1153static int
1154cs_mediachange(struct ifnet *ifp)
1155{
1156	struct cs_softc *sc = ifp->if_softc;
1157	struct ifmedia *ifm = &sc->media;
1158
1159	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1160		return EINVAL;
1161
1162	return cs_mediaset(sc, ifm->ifm_media);
1163}
1164
1165static void
1166cs_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
1167{
1168	int line_status;
1169	struct cs_softc *sc = ifp->if_softc;
1170
1171	ifmr->ifm_active = IFM_ETHER;
1172	line_status = cs_readreg(sc->nic_addr, PP_LineST);
1173	if (line_status & TENBASET_ON) {
1174		ifmr->ifm_active |= IFM_10_T;
1175		if (sc->chip_type != CS8900) {
1176			if (cs_readreg(sc->nic_addr, PP_AutoNegST) & FDX_ACTIVE)
1177				ifmr->ifm_active |= IFM_FDX;
1178			if (cs_readreg(sc->nic_addr, PP_AutoNegST) & HDX_ACTIVE)
1179				ifmr->ifm_active |= IFM_HDX;
1180		}
1181		ifmr->ifm_status = IFM_AVALID;
1182		if (line_status & LINK_OK)
1183			ifmr->ifm_status |= IFM_ACTIVE;
1184	} else {
1185		if (line_status & AUI_ON) {
1186			cs_writereg(sc->nic_addr, PP_SelfCTL,
1187				    cs_readreg(sc->nic_addr, PP_SelfCTL) |
1188				    HCB1_ENBL);
1189			if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0)^
1190			    (cs_readreg(sc->nic_addr, PP_SelfCTL)&HCB1))
1191				ifmr->ifm_active |= IFM_10_2;
1192			else
1193				ifmr->ifm_active |= IFM_10_5;
1194		}
1195	}
1196}
1197
1198static int
1199cs_mediaset(struct cs_softc *sc, int media)
1200{
1201        int error;
1202
1203	/* Stop the receiver & transmitter */
1204	cs_writereg(sc->nic_addr, PP_LineCTL,
1205                    cs_readreg(sc->nic_addr, PP_LineCTL) &
1206		    ~(SERIAL_RX_ON | SERIAL_TX_ON));
1207
1208#ifdef CS_DEBUG
1209	printf(CS_NAME"%d: cs_setmedia(%x)\n",sc->arpcom.ac_if.if_unit,media);
1210#endif
1211
1212	switch (IFM_SUBTYPE(media)) {
1213	default:
1214	case IFM_AUTO:
1215		if ((error=enable_tp(sc))==0)
1216			error = cs_duplex_auto(sc);
1217		else if (error=enable_bnc(sc))
1218			error = enable_aui(sc);
1219		break;
1220	case IFM_10_T:
1221		if (error=enable_tp(sc))
1222			break;
1223		if (media & IFM_FDX)
1224			cs_duplex_full(sc);
1225		else if (media & IFM_HDX)
1226			cs_duplex_half(sc);
1227		else
1228			error = cs_duplex_auto(sc);
1229		break;
1230	case IFM_10_2:
1231		error = enable_bnc(sc);
1232		break;
1233	case IFM_10_5:
1234		error = enable_aui(sc);
1235		break;
1236	}
1237
1238	/*
1239	 * Turn the transmitter & receiver back on
1240	 */
1241	cs_writereg(sc->nic_addr, PP_LineCTL,
1242		    cs_readreg( sc->nic_addr, PP_LineCTL ) |
1243		    SERIAL_RX_ON | SERIAL_TX_ON);
1244
1245	return error;
1246}
1247
1248
1249#if NPNP > 0
1250
1251static struct cspnp_ids {
1252	u_long	vend_id;
1253	char 	*id_str;
1254} cspnp_ids[]= {
1255	{ 0x4060630e, "CSC6040" },
1256	{ 0x10104d24, "IBM EtherJet" },
1257	{ 0 }
1258};
1259
1260static char *cs_pnp_probe(u_long, u_long);
1261static void cs_pnp_attach(u_long, u_long, char *, struct isa_device *);
1262
1263struct pnp_device cs_pnp = {
1264	"CS8920 based PnP Ethernet",
1265	cs_pnp_probe,
1266	cs_pnp_attach,
1267	&cs_unit,
1268	&net_imask	/* imask */
1269};
1270
1271DATA_SET (pnpdevice_set, cs_pnp);
1272
1273struct csintr_list {
1274	struct cs_softc *sc;
1275	int unit;
1276	struct csintr_list *next;
1277};
1278
1279static struct csintr_list *csintr_head;
1280
1281static void csintr_pnp_add(struct cs_softc *sc, int unit);
1282static void csintr_pnp(int unit);
1283
1284static void
1285csintr_pnp_add(struct cs_softc *sc, int unit)
1286{
1287    struct csintr_list *intr;
1288
1289    if (!sc) return;
1290
1291    intr = malloc (sizeof (*intr), M_DEVBUF, M_WAITOK);
1292    if (!intr) return;
1293
1294    intr->sc = sc;
1295    intr->unit = unit;
1296    intr->next = csintr_head;
1297    csintr_head = intr;
1298}
1299
1300/*
1301 * Interrupt handler for PNP installed card
1302 * We have to find the number of the card.
1303 */
1304static void
1305csintr_pnp(int unit)
1306{
1307    struct cs_softc *sc;
1308    struct csintr_list *intr;
1309
1310    for (intr=csintr_head; intr; intr=intr->next) {
1311	    if (intr->unit == unit)
1312		csintr_sc(intr->sc, unit);
1313		break;
1314	}
1315}
1316
1317static char *
1318cs_pnp_probe(u_long csn, u_long vend_id)
1319{
1320    struct cspnp_ids *ids;
1321    char	     *s=NULL;
1322
1323    for(ids = cspnp_ids; ids->vend_id != 0; ids++) {
1324	if (vend_id == ids->vend_id) {
1325	    s = ids->id_str;
1326	    break;
1327	}
1328    }
1329
1330    if (s) {
1331	struct pnp_cinfo d;
1332	int ldn = 0;
1333
1334	read_pnp_parms(&d, ldn);
1335	if (d.enable == 0) {
1336	    printf("This is a %s, but LDN %d is disabled\n", s, ldn);
1337	    return NULL ;
1338	}
1339	return s;
1340    }
1341
1342    return NULL ;
1343}
1344
1345static void
1346cs_pnp_attach(u_long csn, u_long vend_id, char *name,
1347	struct isa_device *dev)
1348{
1349
1350    struct pnp_cinfo d;
1351    int	ldn = 0;
1352    int iobase, unit, flags;
1353    u_short irq;
1354    short drq;
1355    struct isa_device *dvp;
1356    struct cs_softc *sc = malloc(sizeof *sc, M_DEVBUF, M_NOWAIT);
1357
1358    if (read_pnp_parms ( &d , ldn ) == 0 ) {
1359	printf("failed to read pnp parms\n");
1360	return;
1361    }
1362
1363    write_pnp_parms( &d, ldn );
1364    enable_pnp_card();
1365
1366    iobase = dev->id_iobase = d.port[0];
1367    irq = dev->id_irq = (1 << d.irq[0] );
1368    drq = dev->id_drq = d.drq[0];
1369    dev->id_maddr = 0;
1370    dev->id_intr = csintr_pnp;
1371    flags = dev->id_flags = 0;
1372    unit = dev->id_unit;
1373
1374    if (dev->id_driver == NULL) {
1375	dev->id_driver = &csdriver;
1376	dvp = find_isadev(isa_devtab_net, &csdriver, 0);
1377	if (dvp != NULL)
1378	dev->id_id = dvp->id_id;
1379    }
1380
1381    if (!sc) return;
1382
1383    bzero(sc, sizeof *sc);
1384    if (cs_cs89x0_probe(sc, &irq, &drq, iobase, unit, flags) == 0
1385	|| cs_attach(sc, unit, flags) == 0) {
1386	    free(sc, M_DEVBUF);
1387    } else {
1388	if ((irq != dev->id_irq)
1389	    || (drq != dev->id_drq)
1390	    || (iobase != dev->id_iobase)
1391	    || (unit != dev->id_unit)
1392	    || (flags != dev->id_flags)
1393		) {
1394		printf("failed to pnp card parametars\n");
1395	}
1396    }
1397    csintr_pnp_add(sc, dev->id_unit);
1398}
1399#endif /* NPNP */
1400