Deleted Added
sdiff udiff text old ( 104252 ) new ( 106937 )
full compact
1/*
2 * Copyright (c) 1997,1998 Maxim Bolotin and Oleg Sharoiko.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
10 * disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29/*
30 * $FreeBSD: head/sys/dev/cs/if_cs.c 106937 2002-11-14 23:54:55Z sam $
31 *
32 * Device driver for Crystal Semiconductor CS8920 based ethernet
33 * adapters. By Maxim Bolotin and Oleg Sharoiko, 27-April-1997
34 */
35
36/*
37#define CS_DEBUG
38 */
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/malloc.h>
43#include <sys/mbuf.h>
44#include <sys/socket.h>
45#include <sys/sockio.h>
46#include <sys/kernel.h>
47#include <sys/sysctl.h>
48#include <sys/syslog.h>
49
50#include <sys/module.h>
51#include <sys/bus.h>
52#include <machine/bus.h>
53#include <sys/rman.h>
54#include <machine/resource.h>
55
56#include <net/if.h>
57#include <net/if_arp.h>
58#include <net/if_media.h>
59#include <net/ethernet.h>
60#include <net/bpf.h>
61
62#include <dev/cs/if_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, sc->arpcom.ac_enaddr);
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 */
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}