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