]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/snc/dp83932.c
Start each of the license/copyright comments with /*-, minor shuffle of lines
[FreeBSD/FreeBSD.git] / sys / dev / snc / dp83932.c
1 /*      $FreeBSD$       */
2 /*      $NecBSD: dp83932.c,v 1.5 1999/07/29 05:08:44 kmatsuda Exp $     */
3 /*      $NetBSD: if_snc.c,v 1.18 1998/04/25 21:27:40 scottr Exp $       */
4
5 /*-
6  * Copyright (c) 1997, 1998, 1999
7  *      Kouichi Matsuda.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Kouichi Matsuda for
20  *      NetBSD/pc98.
21  * 4. The name of the author may not be used to endorse or promote products
22  *    derived from this software without specific prior written permission
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35
36 /*
37  * Modified for FreeBSD(98) 4.0 from NetBSD/pc98 1.4.2 by Motomichi Matsuzaki.
38  */
39
40 /*
41  * Modified for NetBSD/pc98 1.2G from NetBSD/mac68k 1.2G by Kouichi Matsuda.
42  * Make adapted for NEC PC-9801-83, 84, PC-9801-103, 104, PC-9801N-25 and
43  * PC-9801N-J02, J02R, which uses National Semiconductor DP83934AVQB as
44  * Ethernet Controller and National Semiconductor NS46C46 as
45  * (64 * 16 bits) Microwire Serial EEPROM.
46  */
47
48 /*-
49  * National Semiconductor  DP8393X SONIC Driver
50  * Copyright (c) 1991   Algorithmics Ltd (http://www.algor.co.uk)
51  * You may use, copy, and modify this program so long as you retain the
52  * copyright line.
53  *
54  * This driver has been substantially modified since Algorithmics donated
55  * it.
56  *
57  *   Denton Gentry <denny1@home.com>
58  * and also
59  *   Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp>
60  * did the work to get this running on the Macintosh.
61  */
62
63 #include "opt_inet.h"
64
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/sockio.h>
68 #include <sys/mbuf.h>
69 #include <sys/protosw.h>
70 #include <sys/socket.h>
71 #include <sys/syslog.h>
72 #include <sys/errno.h>
73 #if NRND > 0
74 #include <sys/rnd.h>
75 #endif
76
77 #include <net/ethernet.h>
78 #include <net/if.h>
79 #include <net/if_arp.h>
80 #include <net/if_dl.h>
81 #include <net/if_media.h>
82
83 #include <net/bpf.h>
84
85 #include <sys/bus.h>
86 #include <machine/bus.h>
87 #include <dev/snc/dp83932reg.h>
88 #include <dev/snc/dp83932var.h>
89
90 hide void       sncwatchdog(struct ifnet *);
91 hide void       sncinit(void *);
92 hide int        sncstop(struct snc_softc *sc);
93 hide int        sncioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
94 hide void       sncstart(struct ifnet *ifp);
95 hide void       sncreset(struct snc_softc *sc);
96
97 hide void       caminitialise(struct snc_softc *);
98 hide void       camentry(struct snc_softc *, int, u_char *ea);
99 hide void       camprogram(struct snc_softc *);
100 hide void       initialise_tda(struct snc_softc *);
101 hide void       initialise_rda(struct snc_softc *);
102 hide void       initialise_rra(struct snc_softc *);
103 #ifdef SNCDEBUG
104 hide void       camdump(struct snc_softc *sc);
105 #endif
106
107 hide void       sonictxint(struct snc_softc *);
108 hide void       sonicrxint(struct snc_softc *);
109
110 hide u_int      sonicput(struct snc_softc *sc, struct mbuf *m0, int mtd_next);
111 hide int        sonic_read(struct snc_softc *, u_int32_t, int);
112 hide struct mbuf *sonic_get(struct snc_softc *, u_int32_t, int);
113
114 int     snc_enable(struct snc_softc *);
115 void    snc_disable(struct snc_softc *);
116
117 int     snc_mediachange(struct ifnet *);
118 void    snc_mediastatus(struct ifnet *, struct ifmediareq *);
119
120 #ifdef NetBSD
121 #if NetBSD <= 199714
122 struct cfdriver snc_cd = {
123         NULL, "snc", DV_IFNET
124 };
125 #endif
126 #endif
127
128 #undef assert
129 #undef _assert
130
131 #ifdef NDEBUG
132 #define assert(e)       ((void)0)
133 #define _assert(e)      ((void)0)
134 #else
135 #define _assert(e)      assert(e)
136 #ifdef __STDC__
137 #define assert(e)       ((e) ? (void)0 : __assert("snc ", __FILE__, __LINE__, #e))
138 #else   /* PCC */
139 #define assert(e)       ((e) ? (void)0 : __assert("snc "__FILE__, __LINE__, "e"))
140 #endif
141 #endif
142
143 #ifdef  SNCDEBUG
144 #define SNC_SHOWTXHDR   0x01    /* show tx ether_header */
145 #define SNC_SHOWRXHDR   0x02    /* show rx ether_header */
146 #define SNC_SHOWCAMENT  0x04    /* show CAM entry */
147 #endif  /* SNCDEBUG */
148 int sncdebug = 0;
149
150
151 void
152 sncconfig(sc, media, nmedia, defmedia, myea)
153         struct snc_softc *sc;
154         int *media, nmedia, defmedia;
155         u_int8_t *myea;
156 {
157         struct ifnet *ifp = &sc->sc_if;
158         int i;
159
160 #ifdef SNCDEBUG
161         if ((sncdebug & SNC_SHOWCAMENT) != 0) {
162                 camdump(sc);
163         }
164 #endif
165
166 #ifdef SNCDEBUG
167         device_printf(sc->sc_dev,
168                       "buffers: rra=0x%x cda=0x%x rda=0x%x tda=0x%x\n",
169                       sc->v_rra[0], sc->v_cda,
170                       sc->v_rda, sc->mtda[0].mtd_vtxp);
171 #endif
172
173         ifp->if_softc = sc;
174         if_initname(ifp, device_get_name(sc->sc_dev),
175             device_get_unit(sc->sc_dev));
176         ifp->if_ioctl = sncioctl;
177         ifp->if_start = sncstart;
178         ifp->if_flags =
179             IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_NEEDSGIANT;
180         ifp->if_watchdog = sncwatchdog;
181         ifp->if_init = sncinit;
182         ifp->if_mtu = ETHERMTU;
183         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
184         bcopy(myea, sc->sc_ethercom.ac_enaddr, ETHER_ADDR_LEN);
185
186         /* Initialize media goo. */
187         ifmedia_init(&sc->sc_media, 0, snc_mediachange,
188             snc_mediastatus);
189         if (media != NULL) {
190                 for (i = 0; i < nmedia; i++)
191                         ifmedia_add(&sc->sc_media, media[i], 0, NULL);
192                 ifmedia_set(&sc->sc_media, defmedia);
193         } else {
194                 ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
195                 ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
196         }
197
198         ether_ifattach(ifp, myea);
199
200 #if NRND > 0
201         rnd_attach_source(&sc->rnd_source, device_get_nameunit(sc->sc_dev),
202             RND_TYPE_NET, 0);
203 #endif
204 }
205
206 void
207 sncshutdown(arg)
208         void *arg;
209 {
210
211         sncstop((struct snc_softc *)arg);
212 }
213
214 /*
215  * Media change callback.
216  */
217 int
218 snc_mediachange(ifp)
219         struct ifnet *ifp;
220 {
221         struct snc_softc *sc = ifp->if_softc;
222
223         if (sc->sc_mediachange)
224                 return ((*sc->sc_mediachange)(sc));
225         return (EINVAL);
226 }
227
228 /*
229  * Media status callback.
230  */
231 void
232 snc_mediastatus(ifp, ifmr)
233         struct ifnet *ifp;
234         struct ifmediareq *ifmr;
235 {
236         struct snc_softc *sc = ifp->if_softc;
237
238         if (sc->sc_enabled == 0) {
239                 ifmr->ifm_active = IFM_ETHER | IFM_NONE;
240                 ifmr->ifm_status = 0;
241                 return;
242         }
243
244         if (sc->sc_mediastatus)
245                 (*sc->sc_mediastatus)(sc, ifmr);
246 }
247
248
249 hide int
250 sncioctl(ifp, cmd, data)
251         struct ifnet *ifp;
252         u_long cmd;
253         caddr_t data;
254 {
255         struct ifreq *ifr;
256         struct snc_softc *sc = ifp->if_softc;
257         int     s = splhardnet(), err = 0;
258         int     temp;
259
260         switch (cmd) {
261
262         case SIOCSIFFLAGS:
263                 if ((ifp->if_flags & IFF_UP) == 0 &&
264                     (ifp->if_flags & IFF_RUNNING) != 0) {
265                         /*
266                          * If interface is marked down and it is running,
267                          * then stop it.
268                          */
269                         sncstop(sc);
270                         ifp->if_flags &= ~IFF_RUNNING;
271                         snc_disable(sc);
272                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
273                     (ifp->if_flags & IFF_RUNNING) == 0) {
274                         /*
275                          * If interface is marked up and it is stopped,
276                          * then start it.
277                          */
278                         if ((err = snc_enable(sc)) != 0)
279                                 break;
280                         sncinit(sc);
281                 } else if (sc->sc_enabled) {
282                         /*
283                          * reset the interface to pick up any other changes
284                          * in flags
285                          */
286                         temp = ifp->if_flags & IFF_UP;
287                         sncreset(sc);
288                         ifp->if_flags |= temp;
289                         sncstart(ifp);
290                 }
291                 break;
292
293         case SIOCADDMULTI:
294         case SIOCDELMULTI:
295                 if (sc->sc_enabled == 0) {
296                         err = EIO;
297                         break;
298                 }
299                 temp = ifp->if_flags & IFF_UP;
300                 sncreset(sc);
301                 ifp->if_flags |= temp;
302                 err = 0;
303                 break;
304         case SIOCGIFMEDIA:
305         case SIOCSIFMEDIA:
306                 ifr = (struct ifreq *) data;
307                 err = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
308                 break;
309         default:
310                 err = ether_ioctl(ifp, cmd, data);
311                 break;
312         }
313         splx(s);
314         return (err);
315 }
316
317 /*
318  * Encapsulate a packet of type family for the local net.
319  */
320 hide void
321 sncstart(ifp)
322         struct ifnet *ifp;
323 {
324         struct snc_softc        *sc = ifp->if_softc;
325         struct mbuf     *m;
326         int             mtd_next;
327
328         if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
329                 return;
330
331 outloop:
332         /* Check for room in the xmit buffer. */
333         if ((mtd_next = (sc->mtd_free + 1)) == NTDA)
334                 mtd_next = 0;
335
336         if (mtd_next == sc->mtd_hw) {
337                 ifp->if_flags |= IFF_OACTIVE;
338                 return;
339         }
340
341         IF_DEQUEUE(&ifp->if_snd, m);
342         if (m == 0)
343                 return;
344
345         /* We need the header for m_pkthdr.len. */
346         M_ASSERTPKTHDR(m);
347
348         /*
349          * If bpf is listening on this interface, let it
350          * see the packet before we commit it to the wire.
351          */
352         BPF_MTAP(ifp, m);
353
354         /*
355          * If there is nothing in the o/p queue, and there is room in
356          * the Tx ring, then send the packet directly.  Otherwise append
357          * it to the o/p queue.
358          */
359         if ((sonicput(sc, m, mtd_next)) == 0) {
360                 IF_PREPEND(&ifp->if_snd, m);
361                 return;
362         }
363
364         sc->mtd_prev = sc->mtd_free;
365         sc->mtd_free = mtd_next;
366
367         ifp->if_opackets++;             /* # of pkts */
368
369         /* Jump back for possibly more punishment. */
370         goto outloop;
371 }
372
373 /*
374  * reset and restart the SONIC.  Called in case of fatal
375  * hardware/software errors.
376  */
377 hide void
378 sncreset(sc)
379         struct snc_softc *sc;
380 {
381         sncstop(sc);
382         sncinit(sc);
383 }
384
385 hide void
386 sncinit(xsc)
387         void *xsc;
388 {
389         struct snc_softc *sc = xsc;
390         u_long  s_rcr;
391         int     s;
392
393         if (sc->sc_if.if_flags & IFF_RUNNING)
394                 /* already running */
395                 return;
396
397         s = splhardnet();
398
399         NIC_PUT(sc, SNCR_CR, CR_RST);   /* DCR only accessable in reset mode! */
400
401         /* config it */
402         NIC_PUT(sc, SNCR_DCR, (sc->sncr_dcr |
403                 (sc->bitmode ? DCR_DW32 : DCR_DW16)));
404         NIC_PUT(sc, SNCR_DCR2, sc->sncr_dcr2);
405
406         s_rcr = RCR_BRD | RCR_LBNONE;
407         if (sc->sc_if.if_flags & IFF_PROMISC)
408                 s_rcr |= RCR_PRO;
409         if (sc->sc_if.if_flags & IFF_ALLMULTI)
410                 s_rcr |= RCR_AMC;
411         NIC_PUT(sc, SNCR_RCR, s_rcr);
412
413         NIC_PUT(sc, SNCR_IMR, (IMR_PRXEN | IMR_PTXEN | IMR_TXEREN | IMR_LCDEN));
414
415         /* clear pending interrupts */
416         NIC_PUT(sc, SNCR_ISR, ISR_ALL);
417
418         /* clear tally counters */
419         NIC_PUT(sc, SNCR_CRCT, -1);
420         NIC_PUT(sc, SNCR_FAET, -1);
421         NIC_PUT(sc, SNCR_MPT, -1);
422
423         initialise_tda(sc);
424         initialise_rda(sc);
425         initialise_rra(sc);
426
427         /* enable the chip */
428         NIC_PUT(sc, SNCR_CR, 0);
429         wbflush();
430
431         /* program the CAM */
432         camprogram(sc);
433
434         /* get it to read resource descriptors */
435         NIC_PUT(sc, SNCR_CR, CR_RRRA);
436         wbflush();
437         while ((NIC_GET(sc, SNCR_CR)) & CR_RRRA)
438                 continue;
439
440         /* enable rx */
441         NIC_PUT(sc, SNCR_CR, CR_RXEN);
442         wbflush();
443
444         /* flag interface as "running" */
445         sc->sc_if.if_flags |= IFF_RUNNING;
446         sc->sc_if.if_flags &= ~IFF_OACTIVE;
447
448         splx(s);
449         return;
450 }
451
452 /*
453  * close down an interface and free its buffers
454  * Called on final close of device, or if sncinit() fails
455  * part way through.
456  */
457 hide int
458 sncstop(sc)
459         struct snc_softc *sc;
460 {
461         struct mtd *mtd;
462         int     s = splhardnet();
463
464         /* stick chip in reset */
465         NIC_PUT(sc, SNCR_CR, CR_RST);
466         wbflush();
467
468         /* free all receive buffers (currently static so nothing to do) */
469
470         /* free all pending transmit mbufs */
471         while (sc->mtd_hw != sc->mtd_free) {
472                 mtd = &sc->mtda[sc->mtd_hw];
473                 if (mtd->mtd_mbuf)
474                         m_freem(mtd->mtd_mbuf);
475                 if (++sc->mtd_hw == NTDA) sc->mtd_hw = 0;
476         }
477
478         sc->sc_if.if_timer = 0;
479         sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
480
481         splx(s);
482         return (0);
483 }
484
485 /*
486  * Called if any Tx packets remain unsent after 5 seconds,
487  * In all cases we just reset the chip, and any retransmission
488  * will be handled by higher level protocol timeouts.
489  */
490 hide void
491 sncwatchdog(ifp)
492         struct ifnet *ifp;
493 {
494         struct snc_softc *sc = ifp->if_softc;
495         struct mtd *mtd;
496         int     temp;
497
498         if (sc->mtd_hw != sc->mtd_free) {
499                 /* something still pending for transmit */
500                 mtd = &sc->mtda[sc->mtd_hw];
501                 if (SRO(sc, mtd->mtd_vtxp, TXP_STATUS) == 0)
502                         log(LOG_ERR, "%s: Tx - timeout\n",
503                             device_get_nameunit(sc->sc_dev));
504                 else
505                         log(LOG_ERR, "%s: Tx - lost interrupt\n",
506                             device_get_nameunit(sc->sc_dev));
507                 temp = ifp->if_flags & IFF_UP;
508                 sncreset(sc);
509                 ifp->if_flags |= temp;
510         }
511 }
512
513 /*
514  * stuff packet into sonic (at splnet)
515  */
516 hide u_int
517 sonicput(sc, m0, mtd_next)
518         struct snc_softc *sc;
519         struct mbuf *m0;
520         int mtd_next;
521 {
522         struct mtd *mtdp;
523         struct mbuf *m;
524         u_int32_t buff;
525         u_int32_t txp;
526         u_int   len = 0;
527         u_int   totlen = 0;
528
529 #ifdef whyonearthwouldyoudothis
530         if (NIC_GET(sc, SNCR_CR) & CR_TXP)
531                 return (0);
532 #endif
533
534         /* grab the replacement mtd */
535         mtdp = &sc->mtda[sc->mtd_free];
536
537         buff = mtdp->mtd_vbuf;
538         
539         /* this packet goes to mtdnext fill in the TDA */
540         mtdp->mtd_mbuf = m0;
541         txp = mtdp->mtd_vtxp;
542
543         /* Write to the config word. Every (NTDA/2)+1 packets we set an intr */
544         if (sc->mtd_pint == 0) {
545                 sc->mtd_pint = NTDA/2;
546                 SWO(sc, txp, TXP_CONFIG, TCR_PINT);
547         } else {
548                 sc->mtd_pint--;
549                 SWO(sc, txp, TXP_CONFIG, 0);
550         }
551
552         for (m = m0; m; m = m->m_next) {
553                 len = m->m_len;
554                 totlen += len;
555                 (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), buff, len);
556                 buff += len;
557         }
558         if (totlen >= TXBSIZE) {
559                 panic("%s: sonicput: packet overflow",
560                       device_get_nameunit(sc->sc_dev));
561         }
562
563         SWO(sc, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FPTRLO,
564             LOWER(mtdp->mtd_vbuf));
565         SWO(sc, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FPTRHI,
566             UPPER(mtdp->mtd_vbuf));
567
568         if (totlen < ETHERMIN + sizeof(struct ether_header)) {
569                 int pad = ETHERMIN + sizeof(struct ether_header) - totlen;
570                 (*sc->sc_zerobuf)(sc, mtdp->mtd_vbuf + totlen, pad);
571                 totlen = ETHERMIN + sizeof(struct ether_header);
572         }
573
574         SWO(sc, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FSIZE,
575             totlen);
576         SWO(sc, txp, TXP_FRAGCNT, 1);
577         SWO(sc, txp, TXP_PKTSIZE, totlen);
578
579         /* link onto the next mtd that will be used */
580         SWO(sc, txp, TXP_FRAGOFF + (1 * TXP_FRAGSIZE) + TXP_FPTRLO,
581             LOWER(sc->mtda[mtd_next].mtd_vtxp) | EOL);
582
583         /*
584          * The previous txp.tlink currently contains a pointer to
585          * our txp | EOL. Want to clear the EOL, so write our
586          * pointer to the previous txp.
587          */
588         SWO(sc, sc->mtda[sc->mtd_prev].mtd_vtxp, sc->mtd_tlinko,
589             LOWER(mtdp->mtd_vtxp));
590
591         /* make sure chip is running */
592         wbflush();
593         NIC_PUT(sc, SNCR_CR, CR_TXP);
594         wbflush();
595         sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */
596
597         return (totlen);
598 }
599
600 /*
601  * These are called from sonicioctl() when /etc/ifconfig is run to set
602  * the address or switch the i/f on.
603  */
604 /*
605  * CAM support
606  */
607 hide void
608 caminitialise(sc)
609         struct snc_softc *sc;
610 {
611         u_int32_t v_cda = sc->v_cda;
612         int     i;
613         int     camoffset;
614
615         for (i = 0; i < MAXCAM; i++) {
616                 camoffset = i * CDA_CAMDESC;
617                 SWO(sc, v_cda, (camoffset + CDA_CAMEP), i);
618                 SWO(sc, v_cda, (camoffset + CDA_CAMAP2), 0);
619                 SWO(sc, v_cda, (camoffset + CDA_CAMAP1), 0);
620                 SWO(sc, v_cda, (camoffset + CDA_CAMAP0), 0);
621         }
622         SWO(sc, v_cda, CDA_ENABLE, 0);
623
624 #ifdef SNCDEBUG
625         if ((sncdebug & SNC_SHOWCAMENT) != 0) {
626                 camdump(sc);
627         }
628 #endif
629 }
630
631 hide void
632 camentry(sc, entry, ea)
633         int entry;
634         u_char *ea;
635         struct snc_softc *sc;
636 {
637         u_int32_t v_cda = sc->v_cda;
638         int     camoffset = entry * CDA_CAMDESC;
639
640         SWO(sc, v_cda, camoffset + CDA_CAMEP, entry);
641         SWO(sc, v_cda, camoffset + CDA_CAMAP2, (ea[5] << 8) | ea[4]);
642         SWO(sc, v_cda, camoffset + CDA_CAMAP1, (ea[3] << 8) | ea[2]);
643         SWO(sc, v_cda, camoffset + CDA_CAMAP0, (ea[1] << 8) | ea[0]);
644         SWO(sc, v_cda, CDA_ENABLE, 
645             (SRO(sc, v_cda, CDA_ENABLE) | (1 << entry)));
646 }
647
648 hide void
649 camprogram(sc)
650         struct snc_softc *sc;
651 {
652         struct ifmultiaddr      *ifma;
653         struct ifnet *ifp;
654         int     timeout;
655         int     mcount = 0;
656
657         caminitialise(sc);
658
659         ifp = &sc->sc_if;
660
661         /* Always load our own address first. */
662         camentry (sc, mcount, sc->sc_ethercom.ac_enaddr);
663         mcount++;
664
665         /* Assume we won't need allmulti bit. */
666         ifp->if_flags &= ~IFF_ALLMULTI;
667
668         /* Loop through multicast addresses */
669         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
670                 if (ifma->ifma_addr->sa_family != AF_LINK)
671                         continue;
672                 if (mcount == MAXCAM) {
673                          ifp->if_flags |= IFF_ALLMULTI;
674                          break;
675                 }
676
677                 /* program the CAM with the specified entry */
678                 camentry(sc, mcount,
679                          LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
680                 mcount++;
681         }
682
683         NIC_PUT(sc, SNCR_CDP, LOWER(sc->v_cda));
684         NIC_PUT(sc, SNCR_CDC, MAXCAM);
685         NIC_PUT(sc, SNCR_CR, CR_LCAM);
686         wbflush();
687
688         timeout = 10000;
689         while ((NIC_GET(sc, SNCR_CR) & CR_LCAM) && timeout--)
690                 continue;
691         if (timeout == 0) {
692                 /* XXX */
693                 panic("%s: CAM initialisation failed\n",
694                       device_get_nameunit(sc->sc_dev));
695         }
696         timeout = 10000;
697         while (((NIC_GET(sc, SNCR_ISR) & ISR_LCD) == 0) && timeout--)
698                 continue;
699
700         if (NIC_GET(sc, SNCR_ISR) & ISR_LCD)
701                 NIC_PUT(sc, SNCR_ISR, ISR_LCD);
702         else
703                 device_printf(sc->sc_dev,
704                               "CAM initialisation without interrupt\n");
705 }
706
707 #ifdef SNCDEBUG
708 hide void
709 camdump(sc)
710         struct snc_softc *sc;
711 {
712         int     i;
713
714         printf("CAM entries:\n");
715         NIC_PUT(sc, SNCR_CR, CR_RST);
716         wbflush();
717
718         for (i = 0; i < 16; i++) {
719                 u_short  ap2, ap1, ap0;
720                 NIC_PUT(sc, SNCR_CEP, i);
721                 wbflush();
722                 ap2 = NIC_GET(sc, SNCR_CAP2);
723                 ap1 = NIC_GET(sc, SNCR_CAP1);
724                 ap0 = NIC_GET(sc, SNCR_CAP0);
725                 printf("%d: ap2=0x%x ap1=0x%x ap0=0x%x\n", i, ap2, ap1, ap0);
726         }
727         printf("CAM enable 0x%x\n", NIC_GET(sc, SNCR_CEP));
728
729         NIC_PUT(sc, SNCR_CR, 0);
730         wbflush();
731 }
732 #endif
733
734 hide void
735 initialise_tda(sc)
736         struct snc_softc *sc;
737 {
738         struct mtd *mtd;
739         int     i;
740
741         for (i = 0; i < NTDA; i++) {
742                 mtd = &sc->mtda[i];
743                 mtd->mtd_mbuf = 0;
744         }
745
746         sc->mtd_hw = 0;
747         sc->mtd_prev = NTDA - 1;
748         sc->mtd_free = 0;
749         sc->mtd_tlinko = TXP_FRAGOFF + 1*TXP_FRAGSIZE + TXP_FPTRLO;
750         sc->mtd_pint = NTDA/2;
751
752         NIC_PUT(sc, SNCR_UTDA, UPPER(sc->mtda[0].mtd_vtxp));
753         NIC_PUT(sc, SNCR_CTDA, LOWER(sc->mtda[0].mtd_vtxp));
754 }
755
756 hide void
757 initialise_rda(sc)
758         struct snc_softc *sc;
759 {
760         int             i;
761         u_int32_t       vv_rda = 0;
762         u_int32_t       v_rda = 0;
763
764         /* link the RDA's together into a circular list */
765         for (i = 0; i < (sc->sc_nrda - 1); i++) {
766                 v_rda = sc->v_rda + (i * RXPKT_SIZE(sc));
767                 vv_rda = sc->v_rda + ((i+1) * RXPKT_SIZE(sc));
768                 SWO(sc, v_rda, RXPKT_RLINK, LOWER(vv_rda));
769                 SWO(sc, v_rda, RXPKT_INUSE, 1);
770         }
771         v_rda = sc->v_rda + ((sc->sc_nrda - 1) * RXPKT_SIZE(sc));
772         SWO(sc, v_rda, RXPKT_RLINK, LOWER(sc->v_rda) | EOL);
773         SWO(sc, v_rda, RXPKT_INUSE, 1);
774
775         /* mark end of receive descriptor list */
776         sc->sc_rdamark = sc->sc_nrda - 1;
777
778         sc->sc_rxmark = 0;
779
780         NIC_PUT(sc, SNCR_URDA, UPPER(sc->v_rda));
781         NIC_PUT(sc, SNCR_CRDA, LOWER(sc->v_rda));
782         wbflush();
783 }
784
785 hide void
786 initialise_rra(sc)
787         struct snc_softc *sc;
788 {
789         int     i;
790         u_int   v;
791         int     bitmode = sc->bitmode;
792
793         if (bitmode)
794                 NIC_PUT(sc, SNCR_EOBC, RBASIZE(sc) / 2 - 2);
795         else
796                 NIC_PUT(sc, SNCR_EOBC, RBASIZE(sc) / 2 - 1);
797
798         NIC_PUT(sc, SNCR_URRA, UPPER(sc->v_rra[0]));
799         NIC_PUT(sc, SNCR_RSA, LOWER(sc->v_rra[0]));
800         /* rea must point just past the end of the rra space */
801         NIC_PUT(sc, SNCR_REA, LOWER(sc->v_rea));
802         NIC_PUT(sc, SNCR_RRP, LOWER(sc->v_rra[0]));
803         NIC_PUT(sc, SNCR_RSC, 0);
804
805         /* fill up SOME of the rra with buffers */
806         for (i = 0; i < NRBA; i++) {
807                 v = SONIC_GETDMA(sc->rbuf[i]);
808                 SWO(sc, sc->v_rra[i], RXRSRC_PTRHI, UPPER(v));
809                 SWO(sc, sc->v_rra[i], RXRSRC_PTRLO, LOWER(v));
810                 SWO(sc, sc->v_rra[i], RXRSRC_WCHI, UPPER(NBPG/2));
811                 SWO(sc, sc->v_rra[i], RXRSRC_WCLO, LOWER(NBPG/2));
812         }
813         sc->sc_rramark = NRBA;
814         NIC_PUT(sc, SNCR_RWP, LOWER(sc->v_rra[sc->sc_rramark]));
815         wbflush();
816 }
817
818 void
819 sncintr(arg)
820         void    *arg;
821 {
822         struct snc_softc *sc = (struct snc_softc *)arg;
823         int     isr;
824
825         if (sc->sc_enabled == 0)
826                 return;
827
828         while ((isr = (NIC_GET(sc, SNCR_ISR) & ISR_ALL)) != 0) {
829                 /* scrub the interrupts that we are going to service */
830                 NIC_PUT(sc, SNCR_ISR, isr);
831                 wbflush();
832
833                 if (isr & (ISR_BR | ISR_LCD | ISR_TC))
834                         device_printf(sc->sc_dev,
835                                       "unexpected interrupt status 0x%x\n",
836                                       isr);
837
838                 if (isr & (ISR_TXDN | ISR_TXER | ISR_PINT))
839                         sonictxint(sc);
840
841                 if (isr & ISR_PKTRX)
842                         sonicrxint(sc);
843
844                 if (isr & (ISR_HBL | ISR_RDE | ISR_RBE | ISR_RBAE | ISR_RFO)) {
845                         if (isr & ISR_HBL)
846                                 /*
847                                  * The repeater is not providing a heartbeat.
848                                  * In itself this isn't harmful, lots of the
849                                  * cheap repeater hubs don't supply a heartbeat.
850                                  * So ignore the lack of heartbeat. Its only
851                                  * if we can't detect a carrier that we have a
852                                  * problem.
853                                  */
854                                 ;
855                         if (isr & ISR_RDE)
856                                 device_printf(sc->sc_dev, 
857                                         "receive descriptors exhausted\n");
858                         if (isr & ISR_RBE)
859                                 device_printf(sc->sc_dev, 
860                                         "receive buffers exhausted\n");
861                         if (isr & ISR_RBAE)
862                                 device_printf(sc->sc_dev, 
863                                         "receive buffer area exhausted\n");
864                         if (isr & ISR_RFO)
865                                 device_printf(sc->sc_dev, 
866                                         "receive FIFO overrun\n");
867                 }
868                 if (isr & (ISR_CRC | ISR_FAE | ISR_MP)) {
869 #ifdef notdef
870                         if (isr & ISR_CRC)
871                                 sc->sc_crctally++;
872                         if (isr & ISR_FAE)
873                                 sc->sc_faetally++;
874                         if (isr & ISR_MP)
875                                 sc->sc_mptally++;
876 #endif
877                 }
878                 sncstart(&sc->sc_if);
879
880 #if NRND > 0
881                 if (isr)
882                         rnd_add_uint32(&sc->rnd_source, isr);
883 #endif
884         }
885         return;
886 }
887
888 /*
889  * Transmit interrupt routine
890  */
891 hide void
892 sonictxint(sc)
893         struct snc_softc *sc;
894 {
895         struct mtd      *mtd;
896         u_int32_t       txp;
897         unsigned short  txp_status;
898         int             mtd_hw;
899         struct ifnet    *ifp = &sc->sc_if;
900
901         mtd_hw = sc->mtd_hw;
902
903         if (mtd_hw == sc->mtd_free)
904                 return;
905
906         while (mtd_hw != sc->mtd_free) {
907                 mtd = &sc->mtda[mtd_hw];
908
909                 txp = mtd->mtd_vtxp;
910
911                 if (SRO(sc, txp, TXP_STATUS) == 0) {
912                         break; /* it hasn't really gone yet */
913                 }
914
915 #ifdef SNCDEBUG
916                 if ((sncdebug & SNC_SHOWTXHDR) != 0)
917                 {
918                         struct ether_header eh;
919
920                         (*sc->sc_copyfrombuf)(sc, &eh, mtd->mtd_vbuf, sizeof(eh));
921                         device_printf(sc->sc_dev,
922                             "xmit status=0x%x len=%d type=0x%x from %6D",
923                             SRO(sc, txp, TXP_STATUS),
924                             SRO(sc, txp, TXP_PKTSIZE),
925                             htons(eh.ether_type),
926                             eh.ether_shost, ":");
927                         printf(" (to %6D)\n", eh.ether_dhost, ":");
928                 }
929 #endif /* SNCDEBUG */
930
931                 ifp->if_flags &= ~IFF_OACTIVE;
932
933                 if (mtd->mtd_mbuf != 0) {
934                         m_freem(mtd->mtd_mbuf);
935                         mtd->mtd_mbuf = 0;
936                 }
937                 if (++mtd_hw == NTDA) mtd_hw = 0;
938
939                 txp_status = SRO(sc, txp, TXP_STATUS);
940
941                 ifp->if_collisions += (txp_status & TCR_EXC) ? 16 :
942                         ((txp_status & TCR_NC) >> 12);
943
944                 if ((txp_status & TCR_PTX) == 0) {
945                         ifp->if_oerrors++;
946                         device_printf(sc->sc_dev, "Tx packet status=0x%x\n",
947                                       txp_status);
948                         
949                         /* XXX - DG This looks bogus */
950                         if (mtd_hw != sc->mtd_free) {
951                                 printf("resubmitting remaining packets\n");
952                                 mtd = &sc->mtda[mtd_hw];
953                                 NIC_PUT(sc, SNCR_CTDA, LOWER(mtd->mtd_vtxp));
954                                 NIC_PUT(sc, SNCR_CR, CR_TXP);
955                                 wbflush();
956                                 break;
957                         }
958                 }
959         }
960
961         sc->mtd_hw = mtd_hw;
962         return;
963 }
964
965 /*
966  * Receive interrupt routine
967  */
968 hide void
969 sonicrxint(sc)
970         struct snc_softc *sc;
971 {
972         u_int32_t rda;
973         int     orra;
974         int     len;
975         int     rramark;
976         int     rdamark;
977         u_int16_t rxpkt_ptr;
978
979         rda = sc->v_rda + (sc->sc_rxmark * RXPKT_SIZE(sc));
980
981         while (SRO(sc, rda, RXPKT_INUSE) == 0) {
982                 u_int status = SRO(sc, rda, RXPKT_STATUS);
983
984                 orra = RBASEQ(SRO(sc, rda, RXPKT_SEQNO)) & RRAMASK;
985                 rxpkt_ptr = SRO(sc, rda, RXPKT_PTRLO);
986                 /*
987                  * Do not trunc ether_header length.
988                  * Our sonic_read() and sonic_get() require it.
989                  */
990                 len = SRO(sc, rda, RXPKT_BYTEC) - FCSSIZE;
991                 if (status & RCR_PRX) {
992                         /* XXX: Does PGOFSET require? */
993                         u_int32_t pkt =
994                             sc->rbuf[orra & RBAMASK] + (rxpkt_ptr & PGOFSET);
995                         if (sonic_read(sc, pkt, len))
996                                 sc->sc_if.if_ipackets++;
997                         else
998                                 sc->sc_if.if_ierrors++;
999                 } else
1000                         sc->sc_if.if_ierrors++;
1001
1002                 /*
1003                  * give receive buffer area back to chip.
1004                  *
1005                  * If this was the last packet in the RRA, give the RRA to
1006                  * the chip again.
1007                  * If sonic read didnt copy it out then we would have to
1008                  * wait !!
1009                  * (dont bother add it back in again straight away)
1010                  *
1011                  * Really, we're doing v_rra[rramark] = v_rra[orra] but
1012                  * we have to use the macros because SONIC might be in
1013                  * 16 or 32 bit mode.
1014                  */
1015                 if (status & RCR_LPKT) {
1016                         u_int32_t tmp1, tmp2;
1017
1018                         rramark = sc->sc_rramark;
1019                         tmp1 = sc->v_rra[rramark];
1020                         tmp2 = sc->v_rra[orra];
1021                         SWO(sc, tmp1, RXRSRC_PTRLO,
1022                                 SRO(sc, tmp2, RXRSRC_PTRLO));
1023                         SWO(sc, tmp1, RXRSRC_PTRHI,
1024                                 SRO(sc, tmp2, RXRSRC_PTRHI));
1025                         SWO(sc, tmp1, RXRSRC_WCLO,
1026                                 SRO(sc, tmp2, RXRSRC_WCLO));
1027                         SWO(sc, tmp1, RXRSRC_WCHI,
1028                                 SRO(sc, tmp2, RXRSRC_WCHI));
1029
1030                         /* zap old rra for fun */
1031                         SWO(sc, tmp2, RXRSRC_WCHI, 0);
1032                         SWO(sc, tmp2, RXRSRC_WCLO, 0);
1033
1034                         sc->sc_rramark = (++rramark) & RRAMASK;
1035                         NIC_PUT(sc, SNCR_RWP, LOWER(sc->v_rra[rramark]));
1036                         wbflush();
1037                 }
1038
1039                 /*
1040                  * give receive descriptor back to chip simple
1041                  * list is circular
1042                  */
1043                 rdamark = sc->sc_rdamark;
1044                 SWO(sc, rda, RXPKT_INUSE, 1);
1045                 SWO(sc, rda, RXPKT_RLINK,
1046                         SRO(sc, rda, RXPKT_RLINK) | EOL);
1047                 SWO(sc, (sc->v_rda + (rdamark * RXPKT_SIZE(sc))), RXPKT_RLINK,
1048                         SRO(sc, (sc->v_rda + (rdamark * RXPKT_SIZE(sc))),
1049                         RXPKT_RLINK) & ~EOL);
1050                 sc->sc_rdamark = sc->sc_rxmark;
1051
1052                 if (++sc->sc_rxmark >= sc->sc_nrda)
1053                         sc->sc_rxmark = 0;
1054                 rda = sc->v_rda + (sc->sc_rxmark * RXPKT_SIZE(sc));
1055         }
1056 }
1057
1058 /*
1059  * sonic_read -- pull packet off interface and forward to
1060  * appropriate protocol handler
1061  */
1062 hide int
1063 sonic_read(sc, pkt, len)
1064         struct snc_softc *sc;
1065         u_int32_t pkt;
1066         int len;
1067 {
1068         struct ifnet *ifp = &sc->sc_if;
1069         struct ether_header *et;
1070         struct mbuf *m;
1071
1072         if (len <= sizeof(struct ether_header) ||
1073             len > ETHERMTU + sizeof(struct ether_header)) {
1074                 device_printf(sc->sc_dev,
1075                               "invalid packet length %d bytes\n", len);
1076                 return (0);
1077         }
1078
1079         /* Pull packet off interface. */
1080         m = sonic_get(sc, pkt, len);
1081         if (m == 0) {
1082                 return (0);
1083         }
1084
1085         /* We assume that the header fit entirely in one mbuf. */
1086         et = mtod(m, struct ether_header *);
1087
1088 #ifdef SNCDEBUG
1089         if ((sncdebug & SNC_SHOWRXHDR) != 0)
1090         {
1091                 device_printf(sc->sc_dev, "rcvd 0x%x len=%d type=0x%x from %6D",
1092                     pkt, len, htons(et->ether_type),
1093                     et->ether_shost, ":");
1094                 printf(" (to %6D)\n", et->ether_dhost, ":");
1095         }
1096 #endif /* SNCDEBUG */
1097
1098         /* Pass the packet up. */
1099         (*ifp->if_input)(ifp, m);
1100         return (1);
1101 }
1102
1103
1104 /*
1105  * munge the received packet into an mbuf chain
1106  */
1107 hide struct mbuf *
1108 sonic_get(sc, pkt, datalen)
1109         struct snc_softc *sc;
1110         u_int32_t pkt;
1111         int datalen;
1112 {
1113         struct  mbuf *m, *top, **mp;
1114         int     len;
1115         /*
1116          * Do not trunc ether_header length.
1117          * Our sonic_read() and sonic_get() require it.
1118          */
1119
1120         MGETHDR(m, M_DONTWAIT, MT_DATA);
1121         if (m == 0)
1122                 return (0);
1123         m->m_pkthdr.rcvif = &sc->sc_if;
1124         m->m_pkthdr.len = datalen;
1125         len = MHLEN;
1126         top = 0;
1127         mp = &top;
1128
1129         while (datalen > 0) {
1130                 if (top) {
1131                         MGET(m, M_DONTWAIT, MT_DATA);
1132                         if (m == 0) {
1133                                 m_freem(top);
1134                                 return (0);
1135                         }
1136                         len = MLEN;
1137                 }
1138                 if (datalen >= MINCLSIZE) {
1139                         MCLGET(m, M_DONTWAIT);
1140                         if ((m->m_flags & M_EXT) == 0) {
1141                                 if (top) m_freem(top);
1142                                 return (0);
1143                         }
1144                         len = MCLBYTES;
1145                 }
1146 #if 0
1147                 /* XXX: Require? */
1148                 if (!top) {
1149                         register int pad =
1150                             ALIGN(sizeof(struct ether_header)) -
1151                                 sizeof(struct ether_header);
1152                         m->m_data += pad;
1153                         len -= pad;
1154                 }
1155 #endif
1156                 m->m_len = len = min(datalen, len);
1157
1158                 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), pkt, len);
1159                 pkt += len;
1160                 datalen -= len;
1161                 *mp = m;
1162                 mp = &m->m_next;
1163         }
1164
1165         return (top);
1166 }
1167 /*
1168  * Enable power on the interface.
1169  */
1170 int
1171 snc_enable(sc)
1172         struct snc_softc *sc;
1173 {
1174
1175 #ifdef  SNCDEBUG
1176         device_printf(sc->sc_dev, "snc_enable()\n");
1177 #endif  /* SNCDEBUG */
1178
1179         if (sc->sc_enabled == 0 && sc->sc_enable != NULL) {
1180                 if ((*sc->sc_enable)(sc) != 0) {
1181                         device_printf(sc->sc_dev, "device enable failed\n");
1182                         return (EIO);
1183                 }
1184         }
1185
1186         sc->sc_enabled = 1;
1187         return (0);
1188 }
1189
1190 /*
1191  * Disable power on the interface.
1192  */
1193 void
1194 snc_disable(sc)
1195         struct snc_softc *sc;
1196 {
1197
1198 #ifdef  SNCDEBUG
1199         device_printf(sc->sc_dev, "snc_disable()\n");
1200 #endif  /* SNCDEBUG */
1201
1202         if (sc->sc_enabled != 0 && sc->sc_disable != NULL) {
1203                 (*sc->sc_disable)(sc);
1204                 sc->sc_enabled = 0;
1205         }
1206 }
1207
1208