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