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