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