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