if_mc.c revision 1.25 1 1.25 chs /* $NetBSD: if_mc.c,v 1.25 2005/01/15 16:00:59 chs Exp $ */
2 1.2 briggs
3 1.1 briggs /*-
4 1.23 wiz * Copyright (c) 1997 David Huang <khym (at) azeotrope.org>
5 1.1 briggs * All rights reserved.
6 1.1 briggs *
7 1.1 briggs * Portions of this code are based on code by Denton Gentry <denny1 (at) home.com>,
8 1.1 briggs * Charles M. Hannum, Yanagisawa Takeshi <yanagisw (at) aa.ap.titech.ac.jp>, and
9 1.1 briggs * Jason R. Thorpe.
10 1.1 briggs *
11 1.1 briggs * Redistribution and use in source and binary forms, with or without
12 1.1 briggs * modification, are permitted provided that the following conditions
13 1.1 briggs * are met:
14 1.1 briggs * 1. Redistributions of source code must retain the above copyright
15 1.1 briggs * notice, this list of conditions and the following disclaimer.
16 1.1 briggs * 2. The name of the author may not be used to endorse or promote products
17 1.1 briggs * derived from this software without specific prior written permission
18 1.1 briggs *
19 1.1 briggs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 1.1 briggs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 1.1 briggs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 1.1 briggs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 1.1 briggs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 1.1 briggs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 1.1 briggs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 1.1 briggs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 1.1 briggs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 1.1 briggs * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 1.1 briggs *
30 1.1 briggs */
31 1.1 briggs
32 1.1 briggs /*
33 1.1 briggs * Driver for the AMD Am79C940 (MACE) ethernet chip, used for onboard
34 1.1 briggs * ethernet on the Centris/Quadra 660av and Quadra 840av.
35 1.1 briggs */
36 1.22 lukem
37 1.22 lukem #include <sys/cdefs.h>
38 1.25 chs __KERNEL_RCSID(0, "$NetBSD: if_mc.c,v 1.25 2005/01/15 16:00:59 chs Exp $");
39 1.1 briggs
40 1.7 jonathan #include "opt_ddb.h"
41 1.7 jonathan #include "opt_inet.h"
42 1.8 jonathan #include "opt_ccitt.h"
43 1.9 jonathan #include "opt_llc.h"
44 1.10 jonathan #include "opt_ns.h"
45 1.7 jonathan
46 1.1 briggs #include <sys/param.h>
47 1.1 briggs #include <sys/systm.h>
48 1.1 briggs #include <sys/mbuf.h>
49 1.1 briggs #include <sys/buf.h>
50 1.1 briggs #include <sys/protosw.h>
51 1.1 briggs #include <sys/socket.h>
52 1.1 briggs #include <sys/syslog.h>
53 1.1 briggs #include <sys/ioctl.h>
54 1.1 briggs #include <sys/errno.h>
55 1.1 briggs #include <sys/device.h>
56 1.1 briggs
57 1.20 thorpej #include <uvm/uvm_extern.h>
58 1.20 thorpej
59 1.1 briggs #include <net/if.h>
60 1.1 briggs #include <net/if_dl.h>
61 1.1 briggs #include <net/if_ether.h>
62 1.1 briggs
63 1.1 briggs #ifdef INET
64 1.1 briggs #include <netinet/in.h>
65 1.1 briggs #include <netinet/if_inarp.h>
66 1.1 briggs #include <netinet/in_systm.h>
67 1.1 briggs #include <netinet/in_var.h>
68 1.1 briggs #include <netinet/ip.h>
69 1.1 briggs #endif
70 1.1 briggs
71 1.1 briggs #ifdef NS
72 1.1 briggs #include <netns/ns.h>
73 1.1 briggs #include <netns/ns_if.h>
74 1.1 briggs #endif
75 1.1 briggs
76 1.1 briggs #if defined(CCITT) && defined(LLC)
77 1.1 briggs #include <sys/socketvar.h>
78 1.1 briggs #include <netccitt/x25.h>
79 1.1 briggs #include <netccitt/pk.h>
80 1.1 briggs #include <netccitt/pk_var.h>
81 1.1 briggs #include <netccitt/pk_extern.h>
82 1.1 briggs #endif
83 1.1 briggs
84 1.16 mrg #include <uvm/uvm_extern.h>
85 1.1 briggs
86 1.1 briggs #include "bpfilter.h"
87 1.1 briggs #if NBPFILTER > 0
88 1.1 briggs #include <net/bpf.h>
89 1.1 briggs #include <net/bpfdesc.h>
90 1.1 briggs #endif
91 1.1 briggs
92 1.1 briggs #include <machine/bus.h>
93 1.1 briggs #include <mac68k/dev/if_mcreg.h>
94 1.1 briggs #include <mac68k/dev/if_mcvar.h>
95 1.1 briggs
96 1.25 chs hide void mcwatchdog(struct ifnet *);
97 1.25 chs hide int mcinit(struct mc_softc *);
98 1.25 chs hide int mcstop(struct mc_softc *);
99 1.25 chs hide int mcioctl(struct ifnet *, u_long, caddr_t);
100 1.25 chs hide void mcstart(struct ifnet *);
101 1.25 chs hide void mcreset(struct mc_softc *);
102 1.25 chs
103 1.25 chs integrate u_int maceput(struct mc_softc *, struct mbuf *);
104 1.25 chs integrate void mc_tint(struct mc_softc *);
105 1.25 chs integrate void mace_read(struct mc_softc *, caddr_t, int);
106 1.25 chs integrate struct mbuf *mace_get(struct mc_softc *, caddr_t, int);
107 1.25 chs static void mace_calcladrf(struct ethercom *, u_int8_t *);
108 1.25 chs static inline u_int16_t ether_cmp(void *, void *);
109 1.1 briggs
110 1.1 briggs
111 1.1 briggs /*
112 1.1 briggs * Compare two Ether/802 addresses for equality, inlined and
113 1.1 briggs * unrolled for speed. Use this like bcmp().
114 1.1 briggs *
115 1.1 briggs * XXX: Add <machine/inlines.h> for stuff like this?
116 1.1 briggs * XXX: or maybe add it to libkern.h instead?
117 1.1 briggs *
118 1.1 briggs * "I'd love to have an inline assembler version of this."
119 1.1 briggs * XXX: Who wanted that? mycroft? I wrote one, but this
120 1.1 briggs * version in C is as good as hand-coded assembly. -gwr
121 1.1 briggs *
122 1.1 briggs * Please do NOT tweak this without looking at the actual
123 1.1 briggs * assembly code generated before and after your tweaks!
124 1.1 briggs */
125 1.1 briggs static inline u_int16_t
126 1.25 chs ether_cmp(void *one, void *two)
127 1.1 briggs {
128 1.25 chs u_int16_t *a = (u_short *) one;
129 1.25 chs u_int16_t *b = (u_short *) two;
130 1.25 chs u_int16_t diff;
131 1.1 briggs
132 1.1 briggs #ifdef m68k
133 1.1 briggs /*
134 1.1 briggs * The post-increment-pointer form produces the best
135 1.1 briggs * machine code for m68k. This was carefully tuned
136 1.1 briggs * so it compiles to just 8 short (2-byte) op-codes!
137 1.1 briggs */
138 1.1 briggs diff = *a++ - *b++;
139 1.1 briggs diff |= *a++ - *b++;
140 1.1 briggs diff |= *a++ - *b++;
141 1.1 briggs #else
142 1.1 briggs /*
143 1.1 briggs * Most modern CPUs do better with a single expresion.
144 1.1 briggs * Note that short-cut evaluation is NOT helpful here,
145 1.1 briggs * because it just makes the code longer, not faster!
146 1.1 briggs */
147 1.1 briggs diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
148 1.1 briggs #endif
149 1.1 briggs
150 1.1 briggs return (diff);
151 1.1 briggs }
152 1.1 briggs
153 1.1 briggs #define ETHER_CMP ether_cmp
154 1.1 briggs
155 1.1 briggs /*
156 1.1 briggs * Interface exists: make available by filling in network interface
157 1.1 briggs * record. System will initialize the interface when it is ready
158 1.1 briggs * to accept packets.
159 1.1 briggs */
160 1.1 briggs int
161 1.25 chs mcsetup(struct mc_softc *sc, u_int8_t *lladdr)
162 1.1 briggs {
163 1.1 briggs struct ifnet *ifp = &sc->sc_if;
164 1.1 briggs
165 1.1 briggs /* reset the chip and disable all interrupts */
166 1.1 briggs NIC_PUT(sc, MACE_BIUCC, SWRST);
167 1.1 briggs DELAY(100);
168 1.1 briggs NIC_PUT(sc, MACE_IMR, ~0);
169 1.1 briggs
170 1.25 chs memcpy(sc->sc_enaddr, lladdr, ETHER_ADDR_LEN);
171 1.1 briggs printf(": address %s\n", ether_sprintf(lladdr));
172 1.1 briggs
173 1.25 chs memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
174 1.1 briggs ifp->if_softc = sc;
175 1.1 briggs ifp->if_ioctl = mcioctl;
176 1.1 briggs ifp->if_start = mcstart;
177 1.1 briggs ifp->if_flags =
178 1.1 briggs IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
179 1.1 briggs ifp->if_watchdog = mcwatchdog;
180 1.1 briggs
181 1.1 briggs if_attach(ifp);
182 1.1 briggs ether_ifattach(ifp, lladdr);
183 1.1 briggs
184 1.1 briggs return (0);
185 1.1 briggs }
186 1.1 briggs
187 1.1 briggs hide int
188 1.25 chs mcioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
189 1.1 briggs {
190 1.1 briggs struct mc_softc *sc = ifp->if_softc;
191 1.1 briggs struct ifaddr *ifa;
192 1.1 briggs struct ifreq *ifr;
193 1.1 briggs
194 1.1 briggs int s = splnet(), err = 0;
195 1.1 briggs
196 1.1 briggs switch (cmd) {
197 1.1 briggs
198 1.1 briggs case SIOCSIFADDR:
199 1.1 briggs ifa = (struct ifaddr *)data;
200 1.1 briggs ifp->if_flags |= IFF_UP;
201 1.1 briggs switch (ifa->ifa_addr->sa_family) {
202 1.1 briggs #ifdef INET
203 1.1 briggs case AF_INET:
204 1.1 briggs mcinit(sc);
205 1.1 briggs arp_ifinit(ifp, ifa);
206 1.1 briggs break;
207 1.1 briggs #endif
208 1.1 briggs #ifdef NS
209 1.1 briggs case AF_NS:
210 1.1 briggs {
211 1.25 chs struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
212 1.1 briggs
213 1.1 briggs if (ns_nullhost(*ina))
214 1.1 briggs ina->x_host =
215 1.1 briggs *(union ns_host *)LLADDR(ifp->if_sadl);
216 1.1 briggs else {
217 1.25 chs memcpy(LLADDR(ifp->if_sadl),
218 1.25 chs ina->x_host.c_host,
219 1.1 briggs sizeof(sc->sc_enaddr));
220 1.1 briggs }
221 1.1 briggs /* Set new address. */
222 1.1 briggs mcinit(sc);
223 1.1 briggs break;
224 1.1 briggs }
225 1.1 briggs #endif
226 1.1 briggs default:
227 1.1 briggs mcinit(sc);
228 1.1 briggs break;
229 1.1 briggs }
230 1.1 briggs break;
231 1.1 briggs
232 1.1 briggs case SIOCSIFFLAGS:
233 1.1 briggs if ((ifp->if_flags & IFF_UP) == 0 &&
234 1.1 briggs (ifp->if_flags & IFF_RUNNING) != 0) {
235 1.1 briggs /*
236 1.1 briggs * If interface is marked down and it is running,
237 1.1 briggs * then stop it.
238 1.1 briggs */
239 1.1 briggs mcstop(sc);
240 1.1 briggs ifp->if_flags &= ~IFF_RUNNING;
241 1.1 briggs } else if ((ifp->if_flags & IFF_UP) != 0 &&
242 1.1 briggs (ifp->if_flags & IFF_RUNNING) == 0) {
243 1.1 briggs /*
244 1.1 briggs * If interface is marked up and it is stopped,
245 1.1 briggs * then start it.
246 1.1 briggs */
247 1.1 briggs (void)mcinit(sc);
248 1.1 briggs } else {
249 1.1 briggs /*
250 1.1 briggs * reset the interface to pick up any other changes
251 1.1 briggs * in flags
252 1.1 briggs */
253 1.1 briggs mcreset(sc);
254 1.1 briggs mcstart(ifp);
255 1.1 briggs }
256 1.1 briggs break;
257 1.1 briggs
258 1.1 briggs case SIOCADDMULTI:
259 1.1 briggs case SIOCDELMULTI:
260 1.1 briggs ifr = (struct ifreq *) data;
261 1.1 briggs err = (cmd == SIOCADDMULTI) ?
262 1.1 briggs ether_addmulti(ifr, &sc->sc_ethercom) :
263 1.1 briggs ether_delmulti(ifr, &sc->sc_ethercom);
264 1.1 briggs
265 1.1 briggs if (err == ENETRESET) {
266 1.1 briggs /*
267 1.1 briggs * Multicast list has changed; set the hardware
268 1.1 briggs * filter accordingly. But remember UP flag!
269 1.1 briggs */
270 1.24 thorpej if (ifp->if_flags & IFF_RUNNING)
271 1.24 thorpej mcreset(sc);
272 1.1 briggs err = 0;
273 1.1 briggs }
274 1.1 briggs break;
275 1.1 briggs default:
276 1.1 briggs err = EINVAL;
277 1.1 briggs }
278 1.1 briggs splx(s);
279 1.1 briggs return (err);
280 1.1 briggs }
281 1.1 briggs
282 1.1 briggs /*
283 1.1 briggs * Encapsulate a packet of type family for the local net.
284 1.1 briggs */
285 1.1 briggs hide void
286 1.25 chs mcstart(struct ifnet *ifp)
287 1.1 briggs {
288 1.1 briggs struct mc_softc *sc = ifp->if_softc;
289 1.25 chs struct mbuf *m;
290 1.1 briggs
291 1.1 briggs if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
292 1.1 briggs return;
293 1.1 briggs
294 1.1 briggs while (1) {
295 1.1 briggs if (ifp->if_flags & IFF_OACTIVE)
296 1.1 briggs return;
297 1.1 briggs
298 1.1 briggs IF_DEQUEUE(&ifp->if_snd, m);
299 1.1 briggs if (m == 0)
300 1.1 briggs return;
301 1.1 briggs
302 1.1 briggs #if NBPFILTER > 0
303 1.1 briggs /*
304 1.1 briggs * If bpf is listening on this interface, let it
305 1.1 briggs * see the packet before we commit it to the wire.
306 1.1 briggs */
307 1.1 briggs if (ifp->if_bpf)
308 1.1 briggs bpf_mtap(ifp->if_bpf, m);
309 1.1 briggs #endif
310 1.1 briggs
311 1.1 briggs /*
312 1.1 briggs * Copy the mbuf chain into the transmit buffer.
313 1.1 briggs */
314 1.1 briggs ifp->if_flags |= IFF_OACTIVE;
315 1.1 briggs maceput(sc, m);
316 1.1 briggs
317 1.1 briggs ifp->if_opackets++; /* # of pkts */
318 1.1 briggs }
319 1.1 briggs }
320 1.1 briggs
321 1.1 briggs /*
322 1.1 briggs * reset and restart the MACE. Called in case of fatal
323 1.1 briggs * hardware/software errors.
324 1.1 briggs */
325 1.1 briggs hide void
326 1.25 chs mcreset(struct mc_softc *sc)
327 1.1 briggs {
328 1.1 briggs mcstop(sc);
329 1.1 briggs mcinit(sc);
330 1.1 briggs }
331 1.1 briggs
332 1.1 briggs hide int
333 1.25 chs mcinit(struct mc_softc *sc)
334 1.1 briggs {
335 1.1 briggs int s;
336 1.1 briggs u_int8_t maccc, ladrf[8];
337 1.1 briggs
338 1.1 briggs if (sc->sc_if.if_flags & IFF_RUNNING)
339 1.1 briggs /* already running */
340 1.1 briggs return (0);
341 1.1 briggs
342 1.1 briggs s = splnet();
343 1.1 briggs
344 1.1 briggs NIC_PUT(sc, MACE_BIUCC, sc->sc_biucc);
345 1.1 briggs NIC_PUT(sc, MACE_FIFOCC, sc->sc_fifocc);
346 1.1 briggs NIC_PUT(sc, MACE_IMR, ~0); /* disable all interrupts */
347 1.1 briggs NIC_PUT(sc, MACE_PLSCC, sc->sc_plscc);
348 1.1 briggs
349 1.1 briggs NIC_PUT(sc, MACE_UTR, RTRD); /* disable reserved test registers */
350 1.1 briggs
351 1.1 briggs /* set MAC address */
352 1.1 briggs NIC_PUT(sc, MACE_IAC, ADDRCHG);
353 1.1 briggs while (NIC_GET(sc, MACE_IAC) & ADDRCHG)
354 1.1 briggs ;
355 1.1 briggs NIC_PUT(sc, MACE_IAC, PHYADDR);
356 1.1 briggs bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_PADR),
357 1.1 briggs sc->sc_enaddr, ETHER_ADDR_LEN);
358 1.1 briggs
359 1.1 briggs /* set logical address filter */
360 1.1 briggs mace_calcladrf(&sc->sc_ethercom, ladrf);
361 1.1 briggs
362 1.1 briggs NIC_PUT(sc, MACE_IAC, ADDRCHG);
363 1.1 briggs while (NIC_GET(sc, MACE_IAC) & ADDRCHG)
364 1.1 briggs ;
365 1.1 briggs NIC_PUT(sc, MACE_IAC, LOGADDR);
366 1.1 briggs bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_LADRF),
367 1.1 briggs ladrf, 8);
368 1.1 briggs
369 1.1 briggs NIC_PUT(sc, MACE_XMTFC, APADXMT);
370 1.1 briggs /*
371 1.1 briggs * No need to autostrip padding on receive... Ethernet frames
372 1.1 briggs * don't have a length field, unlike 802.3 frames, so the MACE
373 1.1 briggs * can't figure out the length of the packet anyways.
374 1.1 briggs */
375 1.1 briggs NIC_PUT(sc, MACE_RCVFC, 0);
376 1.1 briggs
377 1.1 briggs maccc = ENXMT | ENRCV;
378 1.1 briggs if (sc->sc_if.if_flags & IFF_PROMISC)
379 1.1 briggs maccc |= PROM;
380 1.1 briggs
381 1.1 briggs NIC_PUT(sc, MACE_MACCC, maccc);
382 1.1 briggs
383 1.1 briggs if (sc->sc_bus_init)
384 1.1 briggs (*sc->sc_bus_init)(sc);
385 1.1 briggs
386 1.1 briggs /*
387 1.1 briggs * Enable all interrupts except receive, since we use the DMA
388 1.1 briggs * completion interrupt for that.
389 1.1 briggs */
390 1.1 briggs NIC_PUT(sc, MACE_IMR, RCVINTM);
391 1.1 briggs
392 1.1 briggs /* flag interface as "running" */
393 1.1 briggs sc->sc_if.if_flags |= IFF_RUNNING;
394 1.1 briggs sc->sc_if.if_flags &= ~IFF_OACTIVE;
395 1.1 briggs
396 1.1 briggs splx(s);
397 1.1 briggs return (0);
398 1.1 briggs }
399 1.1 briggs
400 1.1 briggs /*
401 1.1 briggs * close down an interface and free its buffers
402 1.1 briggs * Called on final close of device, or if mcinit() fails
403 1.1 briggs * part way through.
404 1.1 briggs */
405 1.1 briggs hide int
406 1.25 chs mcstop(struct mc_softc *sc)
407 1.1 briggs {
408 1.25 chs int s;
409 1.25 chs
410 1.25 chs s = splnet();
411 1.1 briggs
412 1.1 briggs NIC_PUT(sc, MACE_BIUCC, SWRST);
413 1.1 briggs DELAY(100);
414 1.1 briggs
415 1.1 briggs sc->sc_if.if_timer = 0;
416 1.21 bjh21 sc->sc_if.if_flags &= ~IFF_RUNNING;
417 1.1 briggs
418 1.1 briggs splx(s);
419 1.1 briggs return (0);
420 1.1 briggs }
421 1.1 briggs
422 1.1 briggs /*
423 1.1 briggs * Called if any Tx packets remain unsent after 5 seconds,
424 1.1 briggs * In all cases we just reset the chip, and any retransmission
425 1.1 briggs * will be handled by higher level protocol timeouts.
426 1.1 briggs */
427 1.1 briggs hide void
428 1.25 chs mcwatchdog(struct ifnet *ifp)
429 1.1 briggs {
430 1.1 briggs struct mc_softc *sc = ifp->if_softc;
431 1.1 briggs
432 1.1 briggs printf("mcwatchdog: resetting chip\n");
433 1.1 briggs mcreset(sc);
434 1.1 briggs }
435 1.1 briggs
436 1.1 briggs /*
437 1.1 briggs * stuff packet into MACE (at splnet)
438 1.1 briggs */
439 1.1 briggs integrate u_int
440 1.25 chs maceput(struct mc_softc *sc, struct mbuf *m)
441 1.1 briggs {
442 1.1 briggs struct mbuf *n;
443 1.1 briggs u_int len, totlen = 0;
444 1.1 briggs u_char *buff;
445 1.1 briggs
446 1.1 briggs buff = sc->sc_txbuf;
447 1.1 briggs
448 1.1 briggs for (; m; m = n) {
449 1.1 briggs u_char *data = mtod(m, u_char *);
450 1.1 briggs len = m->m_len;
451 1.1 briggs totlen += len;
452 1.25 chs memcpy(buff, data, len);
453 1.1 briggs buff += len;
454 1.1 briggs MFREE(m, n);
455 1.1 briggs }
456 1.1 briggs
457 1.20 thorpej if (totlen > PAGE_SIZE)
458 1.1 briggs panic("%s: maceput: packet overflow", sc->sc_dev.dv_xname);
459 1.1 briggs
460 1.1 briggs #if 0
461 1.1 briggs if (totlen < ETHERMIN + sizeof(struct ether_header)) {
462 1.1 briggs int pad = ETHERMIN + sizeof(struct ether_header) - totlen;
463 1.25 chs memset(sc->sc_txbuf + totlen, 0, pad);
464 1.1 briggs totlen = ETHERMIN + sizeof(struct ether_header);
465 1.1 briggs }
466 1.1 briggs #endif
467 1.1 briggs
468 1.1 briggs (*sc->sc_putpacket)(sc, totlen);
469 1.1 briggs
470 1.1 briggs sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */
471 1.1 briggs return (totlen);
472 1.1 briggs }
473 1.1 briggs
474 1.1 briggs void
475 1.25 chs mcintr(void *arg)
476 1.1 briggs {
477 1.1 briggs struct mc_softc *sc = arg;
478 1.1 briggs u_int8_t ir;
479 1.1 briggs
480 1.1 briggs ir = NIC_GET(sc, MACE_IR) & ~NIC_GET(sc, MACE_IMR);
481 1.1 briggs if (ir & JAB) {
482 1.1 briggs #ifdef MCDEBUG
483 1.1 briggs printf("%s: jabber error\n", sc->sc_dev.dv_xname);
484 1.1 briggs #endif
485 1.1 briggs sc->sc_if.if_oerrors++;
486 1.1 briggs }
487 1.1 briggs
488 1.1 briggs if (ir & BABL) {
489 1.1 briggs #ifdef MCDEBUG
490 1.1 briggs printf("%s: babble\n", sc->sc_dev.dv_xname);
491 1.1 briggs #endif
492 1.1 briggs sc->sc_if.if_oerrors++;
493 1.1 briggs }
494 1.1 briggs
495 1.1 briggs if (ir & CERR) {
496 1.14 scottr #ifdef MCDEBUG
497 1.1 briggs printf("%s: collision error\n", sc->sc_dev.dv_xname);
498 1.14 scottr #endif
499 1.1 briggs sc->sc_if.if_collisions++;
500 1.1 briggs }
501 1.1 briggs
502 1.1 briggs /*
503 1.1 briggs * Pretend we have carrier; if we don't this will be cleared
504 1.1 briggs * shortly.
505 1.1 briggs */
506 1.1 briggs sc->sc_havecarrier = 1;
507 1.1 briggs
508 1.1 briggs if (ir & XMTINT)
509 1.1 briggs mc_tint(sc);
510 1.1 briggs
511 1.1 briggs if (ir & RCVINT)
512 1.1 briggs mc_rint(sc);
513 1.1 briggs }
514 1.1 briggs
515 1.1 briggs integrate void
516 1.25 chs mc_tint(struct mc_softc *sc)
517 1.1 briggs {
518 1.1 briggs u_int8_t xmtrc, xmtfs;
519 1.1 briggs
520 1.1 briggs xmtrc = NIC_GET(sc, MACE_XMTRC);
521 1.1 briggs xmtfs = NIC_GET(sc, MACE_XMTFS);
522 1.1 briggs
523 1.1 briggs if ((xmtfs & XMTSV) == 0)
524 1.1 briggs return;
525 1.1 briggs
526 1.1 briggs if (xmtfs & UFLO) {
527 1.1 briggs printf("%s: underflow\n", sc->sc_dev.dv_xname);
528 1.1 briggs mcreset(sc);
529 1.1 briggs return;
530 1.1 briggs }
531 1.1 briggs
532 1.1 briggs if (xmtfs & LCOL) {
533 1.1 briggs printf("%s: late collision\n", sc->sc_dev.dv_xname);
534 1.1 briggs sc->sc_if.if_oerrors++;
535 1.1 briggs sc->sc_if.if_collisions++;
536 1.1 briggs }
537 1.1 briggs
538 1.1 briggs if (xmtfs & MORE)
539 1.1 briggs /* Real number is unknown. */
540 1.1 briggs sc->sc_if.if_collisions += 2;
541 1.1 briggs else if (xmtfs & ONE)
542 1.1 briggs sc->sc_if.if_collisions++;
543 1.1 briggs else if (xmtfs & RTRY) {
544 1.14 scottr printf("%s: excessive collisions\n", sc->sc_dev.dv_xname);
545 1.1 briggs sc->sc_if.if_collisions += 16;
546 1.1 briggs sc->sc_if.if_oerrors++;
547 1.1 briggs }
548 1.1 briggs
549 1.1 briggs if (xmtfs & LCAR) {
550 1.1 briggs sc->sc_havecarrier = 0;
551 1.1 briggs printf("%s: lost carrier\n", sc->sc_dev.dv_xname);
552 1.1 briggs sc->sc_if.if_oerrors++;
553 1.1 briggs }
554 1.1 briggs
555 1.1 briggs sc->sc_if.if_flags &= ~IFF_OACTIVE;
556 1.1 briggs sc->sc_if.if_timer = 0;
557 1.1 briggs mcstart(&sc->sc_if);
558 1.1 briggs }
559 1.1 briggs
560 1.5 scottr void
561 1.25 chs mc_rint(struct mc_softc *sc)
562 1.1 briggs {
563 1.1 briggs #define rxf sc->sc_rxframe
564 1.1 briggs u_int len;
565 1.1 briggs
566 1.1 briggs len = (rxf.rx_rcvcnt | ((rxf.rx_rcvsts & 0xf) << 8)) - 4;
567 1.1 briggs
568 1.1 briggs #ifdef MCDEBUG
569 1.1 briggs if (rxf.rx_rcvsts & 0xf0)
570 1.1 briggs printf("%s: rcvcnt %02x rcvsts %02x rntpc 0x%02x rcvcc 0x%02x\n",
571 1.1 briggs sc->sc_dev.dv_xname, rxf.rx_rcvcnt, rxf.rx_rcvsts,
572 1.1 briggs rxf.rx_rntpc, rxf.rx_rcvcc);
573 1.1 briggs #endif
574 1.1 briggs
575 1.1 briggs if (rxf.rx_rcvsts & OFLO) {
576 1.1 briggs printf("%s: receive FIFO overflow\n", sc->sc_dev.dv_xname);
577 1.1 briggs sc->sc_if.if_ierrors++;
578 1.1 briggs return;
579 1.1 briggs }
580 1.1 briggs
581 1.1 briggs if (rxf.rx_rcvsts & CLSN)
582 1.1 briggs sc->sc_if.if_collisions++;
583 1.1 briggs
584 1.1 briggs if (rxf.rx_rcvsts & FRAM) {
585 1.1 briggs #ifdef MCDEBUG
586 1.1 briggs printf("%s: framing error\n", sc->sc_dev.dv_xname);
587 1.1 briggs #endif
588 1.1 briggs sc->sc_if.if_ierrors++;
589 1.1 briggs return;
590 1.1 briggs }
591 1.1 briggs
592 1.1 briggs if (rxf.rx_rcvsts & FCS) {
593 1.1 briggs #ifdef MCDEBUG
594 1.1 briggs printf("%s: frame control checksum error\n", sc->sc_dev.dv_xname);
595 1.1 briggs #endif
596 1.1 briggs sc->sc_if.if_ierrors++;
597 1.1 briggs return;
598 1.1 briggs }
599 1.1 briggs
600 1.1 briggs mace_read(sc, rxf.rx_frame, len);
601 1.1 briggs #undef rxf
602 1.1 briggs }
603 1.1 briggs
604 1.1 briggs integrate void
605 1.25 chs mace_read(struct mc_softc *sc, caddr_t pkt, int len)
606 1.1 briggs {
607 1.1 briggs struct ifnet *ifp = &sc->sc_if;
608 1.1 briggs struct mbuf *m;
609 1.1 briggs
610 1.1 briggs if (len <= sizeof(struct ether_header) ||
611 1.1 briggs len > ETHERMTU + sizeof(struct ether_header)) {
612 1.1 briggs #ifdef MCDEBUG
613 1.1 briggs printf("%s: invalid packet size %d; dropping\n",
614 1.1 briggs sc->sc_dev.dv_xname, len);
615 1.1 briggs #endif
616 1.1 briggs ifp->if_ierrors++;
617 1.1 briggs return;
618 1.1 briggs }
619 1.1 briggs
620 1.1 briggs m = mace_get(sc, pkt, len);
621 1.1 briggs if (m == NULL) {
622 1.1 briggs ifp->if_ierrors++;
623 1.1 briggs return;
624 1.1 briggs }
625 1.1 briggs
626 1.1 briggs ifp->if_ipackets++;
627 1.19 thorpej
628 1.19 thorpej #if NBPFILTER > 0
629 1.19 thorpej /* Pass the packet to any BPF listeners. */
630 1.19 thorpej if (ifp->if_bpf)
631 1.19 thorpej bpf_mtap(ifp->if_bpf, m);
632 1.19 thorpej #endif
633 1.1 briggs
634 1.13 thorpej /* Pass the packet up. */
635 1.13 thorpej (*ifp->if_input)(ifp, m);
636 1.1 briggs }
637 1.1 briggs
638 1.1 briggs /*
639 1.1 briggs * Pull data off an interface.
640 1.1 briggs * Len is length of data, with local net header stripped.
641 1.1 briggs * We copy the data into mbufs. When full cluster sized units are present
642 1.1 briggs * we copy into clusters.
643 1.1 briggs */
644 1.1 briggs integrate struct mbuf *
645 1.25 chs mace_get(struct mc_softc *sc, caddr_t pkt, int totlen)
646 1.1 briggs {
647 1.25 chs struct mbuf *m;
648 1.1 briggs struct mbuf *top, **mp;
649 1.1 briggs int len;
650 1.1 briggs
651 1.1 briggs MGETHDR(m, M_DONTWAIT, MT_DATA);
652 1.1 briggs if (m == 0)
653 1.1 briggs return (0);
654 1.1 briggs m->m_pkthdr.rcvif = &sc->sc_if;
655 1.1 briggs m->m_pkthdr.len = totlen;
656 1.1 briggs len = MHLEN;
657 1.1 briggs top = 0;
658 1.1 briggs mp = ⊤
659 1.1 briggs
660 1.1 briggs while (totlen > 0) {
661 1.1 briggs if (top) {
662 1.1 briggs MGET(m, M_DONTWAIT, MT_DATA);
663 1.1 briggs if (m == 0) {
664 1.1 briggs m_freem(top);
665 1.1 briggs return 0;
666 1.1 briggs }
667 1.1 briggs len = MLEN;
668 1.1 briggs }
669 1.1 briggs if (totlen >= MINCLSIZE) {
670 1.1 briggs MCLGET(m, M_DONTWAIT);
671 1.1 briggs if ((m->m_flags & M_EXT) == 0) {
672 1.1 briggs m_free(m);
673 1.1 briggs m_freem(top);
674 1.1 briggs return 0;
675 1.1 briggs }
676 1.1 briggs len = MCLBYTES;
677 1.1 briggs }
678 1.1 briggs m->m_len = len = min(totlen, len);
679 1.25 chs memcpy(mtod(m, caddr_t), pkt, len);
680 1.1 briggs pkt += len;
681 1.1 briggs totlen -= len;
682 1.1 briggs *mp = m;
683 1.1 briggs mp = &m->m_next;
684 1.1 briggs }
685 1.1 briggs
686 1.1 briggs return (top);
687 1.1 briggs }
688 1.1 briggs
689 1.1 briggs /*
690 1.1 briggs * Go through the list of multicast addresses and calculate the logical
691 1.1 briggs * address filter.
692 1.1 briggs */
693 1.1 briggs void
694 1.25 chs mace_calcladrf(struct ethercom *ac, u_int8_t *af)
695 1.1 briggs {
696 1.1 briggs struct ifnet *ifp = &ac->ec_if;
697 1.1 briggs struct ether_multi *enm;
698 1.25 chs u_char *cp;
699 1.25 chs u_int32_t crc;
700 1.6 mycroft static const u_int32_t crctab[] = {
701 1.6 mycroft 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
702 1.6 mycroft 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
703 1.6 mycroft 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
704 1.6 mycroft 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
705 1.6 mycroft };
706 1.25 chs int len;
707 1.1 briggs struct ether_multistep step;
708 1.1 briggs
709 1.1 briggs /*
710 1.1 briggs * Set up multicast address filter by passing all multicast addresses
711 1.1 briggs * through a crc generator, and then using the high order 6 bits as an
712 1.1 briggs * index into the 64 bit logical address filter. The high order bit
713 1.1 briggs * selects the word, while the rest of the bits select the bit within
714 1.1 briggs * the word.
715 1.1 briggs */
716 1.1 briggs
717 1.1 briggs *((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0;
718 1.1 briggs ETHER_FIRST_MULTI(step, ac, enm);
719 1.1 briggs while (enm != NULL) {
720 1.1 briggs if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
721 1.1 briggs /*
722 1.1 briggs * We must listen to a range of multicast addresses.
723 1.1 briggs * For now, just accept all multicasts, rather than
724 1.1 briggs * trying to set only those filter bits needed to match
725 1.1 briggs * the range. (At this time, the only use of address
726 1.1 briggs * ranges is for IP multicast routing, for which the
727 1.1 briggs * range is big enough to require all bits set.)
728 1.1 briggs */
729 1.1 briggs goto allmulti;
730 1.1 briggs }
731 1.1 briggs
732 1.1 briggs cp = enm->enm_addrlo;
733 1.1 briggs crc = 0xffffffff;
734 1.1 briggs for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
735 1.6 mycroft crc ^= *cp++;
736 1.6 mycroft crc = (crc >> 4) ^ crctab[crc & 0xf];
737 1.6 mycroft crc = (crc >> 4) ^ crctab[crc & 0xf];
738 1.1 briggs }
739 1.1 briggs /* Just want the 6 most significant bits. */
740 1.1 briggs crc >>= 26;
741 1.1 briggs
742 1.1 briggs /* Set the corresponding bit in the filter. */
743 1.1 briggs af[crc >> 3] |= 1 << (crc & 7);
744 1.1 briggs
745 1.1 briggs ETHER_NEXT_MULTI(step, enm);
746 1.1 briggs }
747 1.1 briggs ifp->if_flags &= ~IFF_ALLMULTI;
748 1.1 briggs return;
749 1.1 briggs
750 1.1 briggs allmulti:
751 1.1 briggs ifp->if_flags |= IFF_ALLMULTI;
752 1.1 briggs *((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0xffffffff;
753 1.1 briggs }
754 1.1 briggs
755 1.1 briggs static u_char bbr4[] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};
756 1.1 briggs #define bbr(v) ((bbr4[(v)&0xf] << 4) | bbr4[((v)>>4) & 0xf])
757 1.1 briggs
758 1.1 briggs u_char
759 1.25 chs mc_get_enaddr(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
760 1.25 chs u_char *dst)
761 1.1 briggs {
762 1.1 briggs int i;
763 1.1 briggs u_char b, csum;
764 1.1 briggs
765 1.1 briggs /*
766 1.1 briggs * The XOR of the 8 bytes of the ROM must be 0xff for it to be
767 1.1 briggs * valid
768 1.1 briggs */
769 1.1 briggs for (i = 0, csum = 0; i < 8; i++) {
770 1.1 briggs b = bus_space_read_1(t, h, o+16*i);
771 1.1 briggs if (i < ETHER_ADDR_LEN)
772 1.1 briggs dst[i] = bbr(b);
773 1.1 briggs csum ^= b;
774 1.1 briggs }
775 1.1 briggs
776 1.1 briggs return csum;
777 1.1 briggs }
778