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